PoEdu - Windows階段班 【Po學校】Lesson005_進程_017_進程的遍歷

    • 歷史緣由:WindowsAPI沒有枚舉進程的API
      • 早期機制:進程信息存放在數據庫,從註冊表來訪問;彙編裏以RegQuery函數來獲取。
      • 中期加入了ToolHelper庫,提供針對進程與線程的操做函數;
      • 後期加入了Process Status庫,提供針對進程的函數,有如:EnumProcess函數等。系統集成PSAPI.DLL裏面。
    • 進程與線程的遍歷操做,多使用ToolHelper庫函數,兼容性好。(從win95開始就存在了)
    • Tool Help 系列結構體

      • MODULEENTRY32 結構體 : 模塊結構體

        • 什麼是模塊?
          • 一個進程由多個模塊組成
            • 任何一個程序啓動,都須要加載ntdll.dll;任何一個界面,都須要加載user32.dll;由於裏面有咱們須要的API。咱們本身的exe文件,加上ntdll.dll,再加上user32.dll,程序才能完整。
        • 模塊結構體成員
          typedef struct tagMODULEENTRY32 {
            DWORD   dwSize;
            DWORD   th32ModuleID;
            DWORD   th32ProcessID;
            DWORD   GlblcntUsage;
            DWORD   ProccntUsage;
            BYTE    *modBaseAddr;
            DWORD   modBaseSize;
            HMODULE hModule;
            TCHAR   szModule[MAX_MODULE_NAME32 + 1];
            TCHAR   szExePath[MAX_PATH];
          } MODULEENTRY32, *PMODULEENTRY32;
          • dwSize 結構體大小
          • th32ModuleID 此成員再也不使用,而且老是設置爲一個。
          • th32ProcessID 要檢查模塊的進程的標識符。
          • GlblcntUsage 該模塊的負載計算,這不是通常意義的,並且一般等於0xffff。
          • ProccntUsage 該模塊的負荷計算(同glblcntusage),這不是通常意義的,並且一般等於0xffff。
          • modBaseAddr 在擁有進程的上下文中模塊的基址。
          • modBaseSize 模塊的大小,以字節爲單位。
          • hModule 在擁有進程的上下文中對模塊的句柄.
          • szModule The module name.
          • szExePath The module path.
      • HEAPENTRY32 結構體 : 堆結構體

        • 堆結構體成員:
          typedef struct tagHEAPENTRY32 {
            SIZE_T    dwSize;
            HANDLE    hHandle;
            ULONG_PTR dwAddress;
            SIZE_T    dwBlockSize;
            DWORD     dwFlags;
            DWORD     dwLockCount;
            DWORD     dwResvd;
            DWORD     th32ProcessID;
            ULONG_PTR th32HeapID;
          } HEAPENTRY32, *PHEAPENTRY32;
          • dwSize
          • hHandle 堆句柄
          • dwBlockSize 堆塊的大小,用字節表示。
          • dwFlags 當前堆狀態:固定的、未被使用、或者移動的、等狀態。
          • dwLockCount 此成員再也不使用,而且老是設置爲零。
          • dwResvd 保留的;不使用或改變的。
          • th32ProcessID
          • th32HeapID
      • HEAPLIST32 結構體 : 堆鏈表結構體

        • 堆鏈表結構體成員:
          typedef struct tagHEAPLIST32 {
            SIZE_T    dwSize;
            DWORD     th32ProcessID;
            ULONG_PTR th32HeapID;
            DWORD     dwFlags;
          } HEAPLIST32, *PHEAPLIST32;
          • dwSize
          • th32ProcessID
          • th32HeapID
          • dwFlags
    • ToolHelp 庫函數

      • CreateToolhelp32Snapshot() 建立進程快照
        HANDLE WINAPI CreateToolhelp32Snapshot(
          _In_  DWORD dwFlags,
          _In_  DWORD th32ProcessID
        );
        • 獲取指定進程的快照,以及這些進程使用的堆、模塊和線程。
        • 快照不是實時的,只是拍照時的狀態。
        • 參數 dwFlags :決定咱們能調用哪些函數。
          • TH32CS_INHERIT:指示是可繼承的快照句柄。
          • TH32CS_SNAPALL:包括全部進程和線程,再加上堆的 th32ProcessID 中指定的進程和模塊。等效於指定 TH32CS_SNAPHEAPLIST,TH32CS_SNAPMODULE,TH32CS_SNAPPROCESS 和 TH32CS_SNAPTHREAD 的值組合使用或運算 (|)。
          • TH32CS_SNAPHEAPLIST:包括全部堆的快照中的 th32ProcessID 中指定的進程。若要枚舉的堆,請參閱 Heap32ListFirst。
          • TH32CS_SNAPMODULE:包括全部模塊的快照中的 th32ProcessID 中指定的進程。若要枚舉模塊,請參閱 Module32First。若是函數失敗與 ERROR_BAD_LENGTH,重試功能,直到成功爲止。64 位 Windows: 在 32 位進程中使用此標誌,而在 64 位進程中使用 64 位的進程。若要包括 64 位進程從 th32ProcessID 中指定的進程的 32 位模塊,請使用 TH32CS_SNAPMODULE32 標誌。
          • TH32CS_SNAPMODULE32:包括全部的 32 位模塊的 th32ProcessID 在快照時從 64 位進程調用中指定的進程。此標誌能夠結合 TH32CS_SNAPMODULE 或 TH32CS_SNAPALL。若是函數失敗與 ERROR_BAD_LENGTH,重試功能,直到成功爲止。
          • TH32CS_SNAPPROCESS:包含在快照中系統中的全部進程。若要枚舉的進程,請參閱 Process32First。
          • TH32CS_SNAPTHREAD:包含在快照中系統中的全部線程。若要枚舉的線程,請參閱 Thread32First。若要標識屬於特定進程的線程,線程進行枚舉時比較 THREADENTRY32 結構的 th32OwnerProcessID 成員及其進程標識符。
        • 參數 th32ProcessID:
          • 要包含在快照中的進程的進程標識符。這個參數能夠是零,以代表當前進程。當指定的 TH32CS_SNAPHEAPLIST、 TH32CS_SNAPMODULE、 TH32CS_SNAPMODULE32 或 TH32CS_SNAPALL 的值,將使用此參數。不然爲它將被忽略,全部流程都包含在快照中。
          • 若是指定的進程是空閒進程或 CSRSS 之一處理,此函數將失敗和最後的錯誤代碼是 ERROR_ACCESS_DENIED,由於它們的訪問限制阻止用戶級代碼打開它們。
          • 若是指定的進程是一個 64 位的過程和調用方是 32 位的進程,此函數將失敗和最後的錯誤代碼是 ERROR_PARTIAL_COPY (299)。
          • 返回值:若是此函數成功,它返回一個打開句柄到指定快照。若是函數失敗,則返回 INVALID_HANDLE_VALUE
        • 簡單解釋:若是你想枚舉進程,dwFlags用TH32CS_SNAPPROCESS,此時th32ProcessID會被忽略,要枚舉模塊,用TH32CS_SNAPMODULE(64位程序枚舉32位進程的模塊時用TH32CS_SNAPMODULE32),枚舉模塊時th32ProcessID表示進程ID
      • Heap32First ()
        • 檢索已由進程分配的堆的第一個塊的信息。
      • Heap32ListFirst ()
        • 檢索由指定進程分配的第一個堆的信息。
      • Heap32ListNext ()
        • 檢索關於由進程分配的下一個堆的信息。
      • Heap32Next ()
        • 檢索關於由進程分配的堆的下一個塊的信息。
      • Module32First ()
        • 檢索與流程相關聯的第一個模塊的信息。
      • Module32Next ()
        • 檢索與進程或線程相關的下一個模塊的信息。
      • Process32First ()
        BOOL WINAPI Process32First(
          _In_     HANDLE hSnapshot,
          _Inout_  LPPROCESSENTRY32 lppe
        );
        • 獲取進程快照中的第一個進程信息
        • hSnapshot:調用 CreateToolhelp32Snapshot 函數返回的快照句柄。
        • lppe:指向 PROCESSENTRY32 結構的指針。它包含進程信息,如名稱的可執行文件、 進程標識符和父進程的進程標識符。
        • 返回值:若是進程列表中的第一項已被複制到緩衝區將返回 TRUE,失敗返回FALSE。若是沒有進程存在或快照不包含進程信息時GetLastError將返回 ERROR_NO_MORE_FILES 錯誤值。調用應用程序必須設置 PROCESSENTRY32 的 dwSize 成員的大小,以字節爲單位的結構。
      • Process32Next ()
        BOOL WINAPI Process32Next(
          _In_   HANDLE hSnapshot,
          _Out_  LPPROCESSENTRY32 lppe
        );
        • 獲取下一個進程信息
        • hSnapshot:調用 CreateToolhelp32Snapshot 函數返回的快照句柄。
        • lppe:指向 PROCESSENTRY32 結構的指針。它包含進程信息,如名稱的可執行文件、 進程標識符和父進程的進程標識符。(見上面)
        • 返回值:若是進程列表中的下一項已被複制到緩衝區將返回 TRUE,失敗返回FALSE。若是沒有進程存在或快照不包含進程信息時GetLastError將返回 ERROR_NO_MORE_FILES 錯誤值。
      • Thread32First ()
        • 檢索有關係統快照中遇到的任何進程的第一個線程的信息。
      • Thread32Next ()
        • 檢索有關係統內存快照中遇到的任何進程的下一個線程的信息。
      • Toolhelp32ReadProcessMemory ()
        BOOL WINAPI Toolhelp32ReadProcessMemory(
          _In_   DWORD th32ProcessID,
          _In_   LPCVOID lpBaseAddress,
          _Out_  LPVOID lpBuffer,
          _In_   SIZE_T cbRead,
          _Out_  SIZE_T lpNumberOfBytesRead
        );
        • 只能讀,不能寫;
        • 只需進程PID,不須要取得句柄;
        • 遠程讀取進程內容;
        • 將分配給另外一進程的內存複製到應用程序提供的緩衝區中。
      • 代碼實踐   遍歷QQ進程裏面的全部模塊:

        #include <windows.h>
        #include <tchar.h>
        #include <TlHelp32.h>
        
        int main()
        {
        	PROCESSENTRY32 pe32 = {0};
        	pe32.dwSize = sizeof(PROCESSENTRY32);
        
        	HANDLE hSnapshot;
        	hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
        	if (hSnapshot != INVALID_HANDLE_VALUE)
        	{
        		if (!Process32First(hSnapshot, &pe32))
        		{
        			DWORD dwError = GetLastError();
        			if (dwError == ERROR_NO_MORE_FILES)
        			{
        				_tprintf(TEXT("Error ! :%d \r\n"), dwError);
        			}
        		}
        		do
        		{
        // 			_tprintf(TEXT("PID :%d \t"), pe32.th32ProcessID);
        // 		    _tprintf(TEXT("File :%s \r\n"), pe32.szExeFile);
        			if (!_tcscmp(TEXT("QQ.exe"),pe32.szExeFile))
        			{
        				MODULEENTRY32 me32 = { 0 };
        				me32.dwSize = sizeof(MODULEENTRY32);
        				HANDLE hModuleSnop = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pe32.th32ProcessID);
        				if (hModuleSnop != INVALID_HANDLE_VALUE)
        				{
        					if (Module32First(hModuleSnop, &me32))
        					{
        						DWORD dwError = GetLastError();
        						if (dwError == ERROR_NO_MORE_FILES)
        						{
        							_tprintf(TEXT("Error ! :%d \r\n"), dwError);
        						}
        						do
        						{
        							_tprintf(TEXT("\tModuleName :%s \r\n"), me32.szModule);
        							_tprintf(TEXT("\tModuleBase :0x%x \r\n"), me32.modBaseAddr);
        							_tprintf(TEXT("\tModulePath :%s \r\n"), me32.szExePath);
        						} while (Module32Next(hModuleSnop, &me32));
        						CloseHandle(hModuleSnop);
        					}
        				}
        			}					
        		}
        		while (Process32Next(hSnapshot, &pe32));
        		CloseHandle(hSnapshot);
        	}
        	system("pause");
        	return 0;
        }
        
相關文章
相關標籤/搜索