讀書筆記--[計算機病毒解密與對抗]
目錄:
- 遍歷進程&線程程序
- 終止進程
- 獲取進程信息
- 獲取進程內模塊信息
- 獲取進程命令行參數
代碼運行環境:Win7 x64
VS2012 Update3
遍歷系統中所有進程
- #include <stdio.h>
- #include <windows.h>
- #include <TlHelp32.h>
- int main()
- {
- // 為進程的所有線程拍個快照
- HANDLE hSnapshort = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
- if( hSnapshort==INVALID_HANDLE_VALUE )
- {
- printf("CreateToolhelp32Snapshot調用失敗!\n");
- return -1;
- }
- // 獲得線程列表,里面記錄了線程的詳細信息,再使用Thread32First和Thread32Next遍歷快照中記錄的每個線程信息
- PROCESSENTRY32 stcProcessInfo;
- stcProcessInfo.dwSize = sizeof(stcProcessInfo);
- BOOL bRet = Process32First(hSnapshort, &stcProcessInfo);
- printf("進程名\t\t\t 進程ID\t 線程數\t 父進程ID\n");
- while (bRet)
- {
- printf("%ls\t\t %d\t %d\t %d\n", stcProcessInfo.szExeFile, stcProcessInfo.th32ProcessID, stcProcessInfo.cntThreads, stcProcessInfo.th32ParentProcessID);
- bRet = Process32Next(hSnapshort, &stcProcessInfo);
- }
- CloseHandle(hSnapshort);
- system("pause");
- return 0;
- }
#include <stdio.h> #include <windows.h> #include <TlHelp32.h> int main() { // 為進程的所有線程拍個快照 HANDLE hSnapshort = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if( hSnapshort==INVALID_HANDLE_VALUE ) { printf("CreateToolhelp32Snapshot調用失敗!\n"); return -1; } // 獲得線程列表,里面記錄了線程的詳細信息,再使用Thread32First和Thread32Next遍歷快照中記錄的每個線程信息 PROCESSENTRY32 stcProcessInfo; stcProcessInfo.dwSize = sizeof(stcProcessInfo); BOOL bRet = Process32First(hSnapshort, &stcProcessInfo); printf("進程名\t\t\t 進程ID\t 線程數\t 父進程ID\n"); while (bRet) { printf("%ls\t\t %d\t %d\t %d\n", stcProcessInfo.szExeFile, stcProcessInfo.th32ProcessID, stcProcessInfo.cntThreads, stcProcessInfo.th32ParentProcessID); bRet = Process32Next(hSnapshort, &stcProcessInfo); } CloseHandle(hSnapshort); system("pause"); return 0; }
遍歷系統中所有線程
- #include <stdio.h>
- #include <windows.h>
- #include <TlHelp32.h>
- int main()
- {
- // 為進程的所有線程拍個快照
- HANDLE hSnapshort = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
- if( hSnapshort==INVALID_HANDLE_VALUE )
- {
- printf("CreateToolhelp32Snapshot調用失敗!\n");
- return -1;
- }
- // 獲得線程列表,里面記錄了線程的詳細信息,再使用Thread32First和Thread32Next遍歷快照中記錄的每個線程信息
- THREADENTRY32 stcThreadInfo;
- stcThreadInfo.dwSize = sizeof(stcThreadInfo);
- BOOL bRet = Thread32First(hSnapshort, &stcThreadInfo);
- DWORD dwProId = -1; // 保存上一個線程的進程ID
- unsigned unCount=0;
- while (bRet)
- {
- if( dwProId!=stcThreadInfo.th32OwnerProcessID )
- {
- // 記錄PID與所屬PID不同,遍歷至不屬於同一進程的線程
- if( dwProId!=-1 )
- {
- // 不是第一次遍歷
- printf("\n進程%d的線程總數:%d\n", dwProId, unCount);
- unCount = 0;
- printf("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n\n\n");
- }
- dwProId = stcThreadInfo.th32OwnerProcessID;
- printf("進程%d:\n\n ", dwProId);
- printf("線程TID\t\t線程所屬進程PID\t\t線程優先級\n");
- }
- printf(" %d\t\t\t%d\t\t\t %d\n",stcThreadInfo.th32ThreadID, stcThreadInfo.th32OwnerProcessID, stcThreadInfo.tpBasePri);
- unCount++;
- bRet = Thread32Next(hSnapshort, &stcThreadInfo);
- }
- printf("\n進程%d的線程總數:%d\n", dwProId, unCount);
- unCount = 0;
- printf("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n\n\n");
- CloseHandle(hSnapshort);
- system("pause");
- return 0;
- }
#include <stdio.h> #include <windows.h> #include <TlHelp32.h> int main() { // 為進程的所有線程拍個快照 HANDLE hSnapshort = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); if( hSnapshort==INVALID_HANDLE_VALUE ) { printf("CreateToolhelp32Snapshot調用失敗!\n"); return -1; } // 獲得線程列表,里面記錄了線程的詳細信息,再使用Thread32First和Thread32Next遍歷快照中記錄的每個線程信息 THREADENTRY32 stcThreadInfo; stcThreadInfo.dwSize = sizeof(stcThreadInfo); BOOL bRet = Thread32First(hSnapshort, &stcThreadInfo); DWORD dwProId = -1; // 保存上一個線程的進程ID unsigned unCount=0; while (bRet) { if( dwProId!=stcThreadInfo.th32OwnerProcessID ) { // 記錄PID與所屬PID不同,遍歷至不屬於同一進程的線程 if( dwProId!=-1 ) { // 不是第一次遍歷 printf("\n進程%d的線程總數:%d\n", dwProId, unCount); unCount = 0; printf("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n\n\n"); } dwProId = stcThreadInfo.th32OwnerProcessID; printf("進程%d:\n\n ", dwProId); printf("線程TID\t\t線程所屬進程PID\t\t線程優先級\n"); } printf(" %d\t\t\t%d\t\t\t %d\n",stcThreadInfo.th32ThreadID, stcThreadInfo.th32OwnerProcessID, stcThreadInfo.tpBasePri); unCount++; bRet = Thread32Next(hSnapshort, &stcThreadInfo); } printf("\n進程%d的線程總數:%d\n", dwProId, unCount); unCount = 0; printf("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n\n\n"); CloseHandle(hSnapshort); system("pause"); return 0; }
在win程序設計中除了使用ToolHelp函數可以完成進程的遍歷操作之外(程序需要包含tlhelp32.h),還可以使用Psapi函數EnumProcess函數,但是它只能獲取進程的ID。
進程相關操作--終止進程
- void WINAPI ExitProcess(
- UINT uExitCode; // 進程退出碼
- );
void WINAPI ExitProcess( UINT uExitCode; // 進程退出碼 );在程序的任意一個地方調用這個函數都會立即終止自身進程的運行。在C/C++中應避免直接調用這個函數,因為C/C++運行期庫得不到通知,∴沒有機會去調用全局或靜態C/C++對象的析構函數。
ExitProcess不能終止其他進程,應使用TerminateProcess函數。
- BOOL WINAPI TerminateProcess(
- HANDLE hProcess, // 要結束的進程句柄
- UINT uExitCode // 指定目標進程的退出碼
- );
BOOL WINAPI TerminateProcess( HANDLE hProcess, // 要結束的進程句柄 UINT uExitCode // 指定目標進程的退出碼 );
- HANDLE WINAPI OpenProcess(
- DWORD dwDesiredAccess, // 指定得到的句柄具有的訪問權限
- BOOL bInheritHandle, // 指定返回的句柄是否可被繼承
- DWORD dwProcessId // 指定要打開的進程ID
- );
HANDLE WINAPI OpenProcess( DWORD dwDesiredAccess, // 指定得到的句柄具有的訪問權限 BOOL bInheritHandle, // 指定返回的句柄是否可被繼承 DWORD dwProcessId // 指定要打開的進程ID );這個函數打開一個存在的進程,返回具有指定權限的句柄。
獲取進程的其他信息
- 獲取進程對應的可執行程序路徑
- DWORD WINAPI GetProcessImageFileNameA (
- _In_ HANDLE hProcess, // 要獲得文件路徑的進程句柄
- _Out_writes_(nSize) LPSTR lpImageFileName, // 保存文件路徑的內存首地址
- _In_ DWORD nSize<span style="white-space:pre"> </span>// 保存文件路徑的內存大小
- );
DWORD WINAPI GetProcessImageFileNameA ( _In_ HANDLE hProcess, // 要獲得文件路徑的進程句柄 _Out_writes_(nSize) LPSTR lpImageFileName, // 保存文件路徑的內存首地址 _In_ DWORD nSize// 保存文件路徑的內存大小 );注意使用上述函數獲取的路徑並不是磁盤驅動器的路徑,而是內核路徑,形如: " \Device\HarddiskVolume1\WINDOWS\System32\notepad.exe ",通常此路徑中的Device表示硬盤驅動器,HarddiskVolume表示分區數字表示具體分區號(1表C 2表D。。。),所以對路徑需要進行轉換。
- #include <stdio.h>
- #include <windows.h>
- #include <tchar.h>
- #include <TlHelp32.h>
- #include <Psapi.h>
- #pragma comment(lib, "psapi.lib")
- void TransPath(PTCHAR pPath)
- {
- // 獲取驅動器字符串位置
- PTCHAR pFind = _tcsstr(pPath, _T("HarddiskVolume"));
- if( pFind==NULL )
- return;
- TCHAR tcDriver[5] = {'C', 'D', 'E', 'F', 'G'}; // 可寫滿24個字符,這里只是一個demo
- int nNum = pFind[_tcslen(_T("HarddiskVolume"))] - 0x30;
- PTCHAR pTemp = _tcsstr(pFind, _T("\\"));
- // 拼接字符串的緩沖區
- TCHAR tcBuffer[MAX_PATH];
- memset(tcBuffer, 0, MAX_PATH*sizeof(TCHAR));
- _stprintf_s(tcBuffer, _T("%c:%s"), tcDriver[nNum-1], pTemp);
- memset(pPath, 0, _tcslen(pPath));
- _tcscpy_s(pPath, 256, tcBuffer);
- }
- int main()
- {
- // 傳入\Device\HarddiskVolume1\WINDOWS\System32\notepad.exe
- DWORD dwNeed;
- PDWORD pdwMem = new DWORD[4000];
- BOOL bRet = EnumProcesses(pdwMem, 4000, &dwNeed);
- if( !bRet )
- {
- if(pdwMem!=NULL)
- {
- delete[] pdwMem;
- pdwMem = nullptr;
- return -1;
- }
- }
- int nNumProc = dwNeed/4;
- HANDLE hProcess = NULL;
- DWORD dwPathLength = 0;
- TCHAR tcBuffer[256] = {0};
- for( int i=0; i<nNumProc; i++ )
- {
- hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pdwMem[i]);
- if( hProcess==NULL )
- continue;
- memset(tcBuffer, 0, 256*sizeof(TCHAR));
- dwPathLength = GetProcessImageFileName(hProcess, tcBuffer, 256);
- if( dwPathLength!=0 )
- {
- TransPath(tcBuffer);
- printf("%08d %ls\n",pdwMem[i], tcBuffer);
- }
- CloseHandle(hProcess);
- }
- if( pdwMem!=NULL )
- {
- delete[] pdwMem;
- pdwMem = NULL;
- }
- system("pause");
- return 0;
- }
#include <stdio.h> #include <windows.h> #include <tchar.h> #include <TlHelp32.h> #include <Psapi.h> #pragma comment(lib, "psapi.lib") void TransPath(PTCHAR pPath) { // 獲取驅動器字符串位置 PTCHAR pFind = _tcsstr(pPath, _T("HarddiskVolume")); if( pFind==NULL ) return; TCHAR tcDriver[5] = {'C', 'D', 'E', 'F', 'G'}; // 可寫滿24個字符,這里只是一個demo int nNum = pFind[_tcslen(_T("HarddiskVolume"))] - 0x30; PTCHAR pTemp = _tcsstr(pFind, _T("\\")); // 拼接字符串的緩沖區 TCHAR tcBuffer[MAX_PATH]; memset(tcBuffer, 0, MAX_PATH*sizeof(TCHAR)); _stprintf_s(tcBuffer, _T("%c:%s"), tcDriver[nNum-1], pTemp); memset(pPath, 0, _tcslen(pPath)); _tcscpy_s(pPath, 256, tcBuffer); } int main() { // 傳入\Device\HarddiskVolume1\WINDOWS\System32\notepad.exe DWORD dwNeed; PDWORD pdwMem = new DWORD[4000]; BOOL bRet = EnumProcesses(pdwMem, 4000, &dwNeed); if( !bRet ) { if(pdwMem!=NULL) { delete[] pdwMem; pdwMem = nullptr; return -1; } } int nNumProc = dwNeed/4; HANDLE hProcess = NULL; DWORD dwPathLength = 0; TCHAR tcBuffer[256] = {0}; for( int i=0; i<nNumProc; i++ ) { hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pdwMem[i]); if( hProcess==NULL ) continue; memset(tcBuffer, 0, 256*sizeof(TCHAR)); dwPathLength = GetProcessImageFileName(hProcess, tcBuffer, 256); if( dwPathLength!=0 ) { TransPath(tcBuffer); printf("%08d %ls\n",pdwMem[i], tcBuffer); } CloseHandle(hProcess); } if( pdwMem!=NULL ) { delete[] pdwMem; pdwMem = NULL; } system("pause"); return 0; }
- 獲取進程內模塊信息
一個可執行程序要執行就必須運行起來形成一個進程,即把自身加載到內存,我們把這段內存稱為該進程的主模塊。but並不是程序的所有功能都位於主模塊中,也有部分功能位於動態鏈接庫中,程序運行后也會把輔助功能的DLL加載到內存形成其他的模塊。摒棄一個進程中可以存在多個模塊用於輔助主模塊完成各種任務。有些病毒把自身代碼以模塊形式加載到正常進程中去然后偷偷執行。
使用ToolHelp系列函數獲取進程模塊和遍歷進程模塊
首先給某個進程的模塊拍個快照,這樣即可得到這個進程的模塊列表,里面記錄了每個模塊的詳細信息。然后使用
Module32First和
Module32Next即可遍歷快照列表中記錄的模塊信息。
使用Psapi函數操作
使用EnumProcessModules函數。這個函數只能得到每個模塊的句柄,不能得到模塊的名稱和路徑,所以需要使用GetModuleFileNameEx函數通過模塊句柄去獲得模塊的路徑。在枚舉進程中的模塊時,第一個模塊是進程的主模塊,用主模塊句柄得到的模塊路徑就是進程文件的路徑。
- 獲取進程命令行參數
命令行參數即進程啟動時傳遞給它的參數,通過這個參數可知道金城個啟動情況。例如系統服務中,凡是服務對應模塊是DLL文件情況,都需要svchost.exe去加載啟動,這樣系統中就有很多svchost進程,每個svchost進程對應一類服務,這時就是通過命令行參數來區分他們。獲取本進程命令行參數API:
- // 返回命令行參數字符串的首地址
- LPTSTR GetCommandLine(VOID);
// 返回命令行參數字符串的首地址 LPTSTR GetCommandLine(VOID);
- mov ax, dword ptr [7C8835F4]
- // 個人做測試的時候地址好像是7C8855F4
mov ax, dword ptr [7C8835F4] // 個人做測試的時候地址好像是7C8855F4也就是說進程的命令行參數被保存在內存中的固定位置,只要定位到GetCommandLineA的入口地址,跳過一個字節后取出一個dword值,這個值是一個指針,指向的內容即命令行參數的地址。現在的問題即得到遠程進程中GetCommandLineA函數的入口地址即可得到該進程的命令行參數。獲取指定模塊中某個Win32API函數地址的函數是GetProcAddress。but這個函數僅可獲取當前進程中API函數的地址,要獲得遠程進程中某個函數的地址就必須在遠程進程中執行這個函數,需要使用遠線程方法,本文暫時不涉及這個內容。 換個思路:GetCommandLineA使用Kernel32.dll提供,這個庫是系統基本庫,幾乎所有程序都會加載這個模塊。而且對於NT架構所有進程加載Kernel32.dll的模塊基址基本都是一致的,而GetCommandLineA在其庫中的地址也是固定的。所以我們在本進程中得到的此函數地址和遠程進程中該函數的地址是一致的(這個方法在我的電腦Win7x64中實驗失敗,應該因為程序的加載基址不固定了)。 獲取遠程進程中數據使用ReadProcessMemory函數。
- BOOL WINAPI ReadProcessMemory(
- _In_ HANDLE hProcess, <span style="white-space:pre"> </span> // 遠程進程句柄
- _In_ LPCVOID lpBaseAddress,<span style="white-space:pre"> </span> // 目標進程內存空間首地址
- _Out_writes_bytes_to_(nSize, *lpNumberOfBytesRead) LPVOID lpBuffer, // 本進程內存空間首地址,存儲讀出的數據
- _In_ SIZE_T nSize,<span style="white-space:pre"> </span> // 要讀取的字節數
- _Out_opt_ SIZE_T * lpNumberOfBytesRead<span style="white-space:pre"> </span> // 實際讀取的字節數
- );
BOOL WINAPI ReadProcessMemory( _In_ HANDLE hProcess, // 遠程進程句柄 _In_ LPCVOID lpBaseAddress, // 目標進程內存空間首地址 _Out_writes_bytes_to_(nSize, *lpNumberOfBytesRead) LPVOID lpBuffer, // 本進程內存空間首地址,存儲讀出的數據 _In_ SIZE_T nSize, // 要讀取的字節數 _Out_opt_ SIZE_T * lpNumberOfBytesRead // 實際讀取的字節數 );為保證此方法成功,應判斷當前系統是否是NT系統,使用GetVersion函數獲取當前系統的版本。返回值表示系統的版本信息,若是NT/2k/xp則返回值小於0x80000000,否則大於該值。虛擬機中XP實驗成功。
jpg改rar
