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;
        }
        

          

posted on 2017-06-19 00:08  zzdoit  阅读(495)  评论(0编辑  收藏  举报

导航