代碼運行環境:Win7 x64css
VS2012 Update3windows
遍歷系統中全部進程api
#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; }
void WINAPI ExitProcess( UINT uExitCode; // 進程退出碼 );在程序的任意一個地方調用這個函數都會當即終止自身進程的運行。在C/C++中應避免直接調用這個函數,由於C/C++運行期庫得不到通知,∴沒有機會去調用全局或靜態C/C++對象的析構函數。
BOOL WINAPI TerminateProcess( HANDLE hProcess, // 要結束的進程句柄 UINT uExitCode // 指定目標進程的退出碼 );
HANDLE WINAPI OpenProcess( DWORD dwDesiredAccess, // 指定獲得的句柄具備的訪問權限 BOOL bInheritHandle, // 指定返回的句柄是否可被繼承 DWORD dwProcessId // 指定要打開的進程ID );這個函數打開一個存在的進程,返回具備指定權限的句柄。
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; }
// 返回命令行參數字符串的首地址 LPTSTR GetCommandLine(VOID);
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, // 遠程進程句柄 _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實驗成功。