首页
论坛
课程
招聘
[原创]Tool Help Library学习笔记(CreateToolhelp32Snapshot)
2019-12-18 21:09 3901

[原创]Tool Help Library学习笔记(CreateToolhelp32Snapshot)

2019-12-18 21:09
3901
参考链接:Tool Help Library

一、简介

Tool Help Library提供的库函数可以是开发者更容易的获取当前正在执行的程序的信息。这些函数的存在是为了简化工具的创建,特别是调试器。

二、Tool Help Functions

2.1、系统快照(Snapshots of the system)

快照是工具帮助库的核心。快照是驻留在系统内存中的一个或者多个列表的当前状态的只读副本:进程、线程、模块和堆。

整个处理过程是使用tool help functions访问这些快照列表,而不是直接访问从操作系统访问。当进程启动和结束、线程创建和销毁、可执行模块从系统内存加载和卸载、堆创建和销毁时,系统内存中的列表(lists)将发生变化。使用快照中的信息可以防止不一致。否则,对列表的更改可能导致线程不正确的遍历或者导致访问冲突(a GP fault)。比如,如果应用程序在创建或者终止其他线程时,遍历线程列表,应用程序用于遍历线程列表的信息可能会出错。

使用CreateToolhelp32Snapshot函数可以获取系统内存快照。调用这个函数时,可以通过指定一个或者多个以下值来控制快照的内容:

TH32CS_SNAPHEAPLIST

TH32CS_SNAPMODULE

TH32CS_SNAPPROCESS

TH32CS_SNAPTHREAD

TH32CS_SNAPHEAPLIST 和 TH32CS_SNAPMODULE 值是特定于进程的。当指时,快照中包含指定这些值时,快照中包含指定进程的堆和模块列表。如果指定zero作为进程表示符,则使用当前进程。 TH32CS_SNAPTHREAD 值总是创建一个系统范围的快照,即使流程标识符被传递给CreateToolhelp32Snapshot。
要枚举所有进程的堆或模块状态,需要指定 TH32CS_SNAPALL值和当前进程表示符。然后,对快照中的每个附加进程,再次调用CreateToolhelp32Snapshot,指定其进程标识符,以及 TH32CS_SNAPHEAPLIST或 TH32CS_SNAPMODULE值。

通过使用GetLastError函数,可以检索CreateToolhelp32Snapshot的扩展错误状态代码。

当进程使用完快照时,使用CloseHandle函数销毁快照。如果不销毁快照,则进程将泄漏内存,直到它退出,此时,系统将收回内存。

备注
快照句柄(handle)的作用类似于文件句柄,并且对于可以在其中使用它的进程和线程,句柄遵循同样的规则。创建快照时可以使用 TH32CS_INHERIT值可以指定句柄是可继承的(inheritable)。

2.2、Process Walking

包含流程列表的快照包含关于当前正在执行的每个流程的信息。可以使用Process32First函数来检索列表中第一个进程的信息。检索列表中的第一个进程之后,可以使用Process32Next函数遍历后续条目的进程列表。Process32First和Process32Next用快照中的某个进程信息填充PROCESSENTRY32结构。
可以使用GetLastError函数检索Process32First和Process32Next的扩展错误状态代码。
可以使用Toolhelp32ReadProcessMemory函数或者VirtualQueryEx函数将特定进程中的内存读如缓冲区。

备注
PROCESSENTRY32的th32ProcessID和th32ParentProcessID成员的内容是进程标识符,可以由需要进程标识符的任何函数使用。

2.3、Thread Walking

包含线程列表的快照包含关于当前正在执行的每个进程的每个线程的信息。可以使用Thread32First函数检索列表中的第一个线程的信息。在检索列表的中的第一个线程之后,可以使用Thread32Next函数检索后续的线程信息。Thread32First和Thread32Next用快照中的各个线程的信息填充THREADENTRY32结构。
可以通过获取包含线程的快照,然后遍历线程列表,保留与指定进程具有相同进程标识符的线程的信息,从而枚举特定进程的线程。 
可以使用GetLastError函数检索Thread32First和Thread32Next的扩展错误状态代码。

备注
THREADENTRY32的th32ThreadID成员的内容是一个线程标识符,可以被任何需要线程标识符的函数使用。

2.4、Module Walking

包含指定流程的模块列表的快照包含关于指定流程使用的每个模块、可执行文件或动态链接库(DLL)的信息。可以使用Module32First函数来检索列表中的第一个模块的信息。在检索列表中的第一个模块之后,可以使用Module32Next函数来检索列表中后续模块的信息。 Module32First和Module32Next用关于模块的信息填充一个MODULEENTRY32结构。
可以使用GetLastError函数检索Module32First和Module32Next的扩展错误状态代码。 

备注
模块标识符在MODULEENTRY32的th32ModuleID成员中指定,仅在16位窗口中有意义。

2.5、Heap Lists and Heap Walking

包含指定进程的堆列表的快照包含与指定进程关联的每个堆的标识信息和关于每个堆的详细信息。可以使用Heap32ListFirst函数来检索堆列表的第一个堆的标识符。在检索列表中的第一个之后,可以使用Heap32ListNext函数遍历堆列表,查找与进程相关的后续堆。 Heap32ListFirst和Heap32ListNext用进程标识符、堆标识符和描述堆的标志填充一个HEAPLIST32结构。
可以使用Heap32First函数来检索关于堆的第一个块的信息。在检索堆的第一个块之后,您可以使用Heap32Next函数检索关于同一堆的后续块的信息。Heap32First和Heap32Next用堆的适当块的信息填充HEAPENTRY32结构 
可以使用GetLastError函数检索Heap32ListFirst、Heap32ListNext、Heap32First和Heap32Next的扩展错误状态代码。

备注
堆标识符是在HEAPENTRY32结构的th32HeapID成员中指定的,它只对工具帮助函数有意义。它不是句柄,其他函数也不能使用它。

三、Using the Tool Help Functions

示例为简单控制台应用程序获得正在运行的进程列表。首先,GetProcessList函数使用CreateToolhelp32Snapshot获取系统中当前正在执行的进程的快照,然后使用Process32First和Process32Next遍历快照中记录的列表。对于每个进程,GetProcessList依次调用在遍历模块列表中描述的ListProcessModules函数,以及在遍历线程列表中描述的ListProcessThreads函数,随后是使用Heap32ListFirst和Heap32ListNext函数遍历列表。对于每个堆,它使用Heap32First和Heap32Next函数遍历堆块。 。一个简单的错误报告函数printError显示任何失败的原因,这些失败通常是由于安全限制造成的。例如,空闲进程和CSRSS进程的OpenProcess失败,因为它们的访问限制阻止用户级代码打开它们。
#include <windows.h>
#include <tlhelp32.h>
#include <tchar.h>
#include <stdio.h>

//  Forward declarations:
BOOL GetProcessList();
BOOL ListProcessModules(DWORD dwPID);
BOOL ListProcessThreads(DWORD dwOwnerPID);
int ListProcessHeap(DWORD dwPID);
void printError(TCHAR* msg);

BOOL GetProcessList()
{
	HANDLE hProcessSnap;
	HANDLE hProcess;
	PROCESSENTRY32 pe32;
	DWORD dwPriorityClass;

	// Take a snapshot of all processes in the system.
	hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
	if (hProcessSnap == INVALID_HANDLE_VALUE)
	{
		printError(TEXT("CreateToolhelp32Snapshot (of processes)"));
		return(FALSE);
	}

	// Set the size of the structure before using it.
	pe32.dwSize = sizeof(PROCESSENTRY32);

	// Retrieve information about the first process,
	// and exit if unsuccessful
	if (!Process32First(hProcessSnap, &pe32))
	{
		printError(TEXT("Process32First")); // show cause of failure
		CloseHandle(hProcessSnap);          // clean the snapshot object
		return(FALSE);
	}

	// Now walk the snapshot of processes, and
	// display information about each process in turn
	do
	{
		_tprintf(TEXT("\n\n====================================================="));
		_tprintf(TEXT("\nPROCESS NAME:  %s"), pe32.szExeFile);
		_tprintf(TEXT("\n-------------------------------------------------------"));

		// Retrieve the priority class.
		dwPriorityClass = 0;
		hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID);
		if (hProcess == NULL)
			printError(TEXT("OpenProcess"));
		else
		{
			dwPriorityClass = GetPriorityClass(hProcess);
			if (!dwPriorityClass)
				printError(TEXT("GetPriorityClass"));
			CloseHandle(hProcess);
		}

		_tprintf(TEXT("\n  Process ID        = 0x%08X"), pe32.th32ProcessID);
		_tprintf(TEXT("\n  Thread count      = %d"), pe32.cntThreads);
		_tprintf(TEXT("\n  Parent process ID = 0x%08X"), pe32.th32ParentProcessID);
		_tprintf(TEXT("\n  Priority base     = %d"), pe32.pcPriClassBase);
		if (dwPriorityClass)
			_tprintf(TEXT("\n  Priority class    = %d"), dwPriorityClass);

		// List the modules and threads associated with this process
		ListProcessModules(pe32.th32ProcessID);
		ListProcessThreads(pe32.th32ProcessID);
		ListProcessHeap(pe32.th32ProcessID);

	} while (Process32Next(hProcessSnap, &pe32));

	CloseHandle(hProcessSnap);
	return(TRUE);
}


BOOL ListProcessModules(DWORD dwPID)
{
	HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
	MODULEENTRY32 me32;

	// Take a snapshot of all modules in the specified process.
	hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID);
	if (hModuleSnap == INVALID_HANDLE_VALUE)
	{
		printError(TEXT("CreateToolhelp32Snapshot (of modules)"));
		return(FALSE);
	}

	// Set the size of the structure before using it.
	me32.dwSize = sizeof(MODULEENTRY32);

	// Retrieve information about the first module,
	// and exit if unsuccessful
	if (!Module32First(hModuleSnap, &me32))
	{
		printError(TEXT("Module32First"));  // show cause of failure
		CloseHandle(hModuleSnap);           // clean the snapshot object
		return(FALSE);
	}

	// Now walk the module list of the process,
	// and display information about each module
	do
	{
		_tprintf(TEXT("\n\n     MODULE NAME:     %s"), me32.szModule);
		_tprintf(TEXT("\n     Executable     = %s"), me32.szExePath);
		_tprintf(TEXT("\n     Process ID     = 0x%08X"), me32.th32ProcessID);
		_tprintf(TEXT("\n     Ref count (g)  = 0x%04X"), me32.GlblcntUsage);
		_tprintf(TEXT("\n     Ref count (p)  = 0x%04X"), me32.ProccntUsage);
		_tprintf(TEXT("\n     Base address   = 0x%08X"), (DWORD)me32.modBaseAddr);
		_tprintf(TEXT("\n     Base size      = %d"), me32.modBaseSize);

	} while (Module32Next(hModuleSnap, &me32));

	CloseHandle(hModuleSnap);
	return(TRUE);
}

BOOL ListProcessThreads(DWORD dwOwnerPID)
{
	HANDLE hThreadSnap = INVALID_HANDLE_VALUE;
	THREADENTRY32 te32;

	// Take a snapshot of all running threads  
	hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
	if (hThreadSnap == INVALID_HANDLE_VALUE)
		return(FALSE);

	// Fill in the size of the structure before using it. 
	te32.dwSize = sizeof(THREADENTRY32);

	// Retrieve information about the first thread,
	// and exit if unsuccessful
	if (!Thread32First(hThreadSnap, &te32))
	{
		printError(TEXT("Thread32First")); // show cause of failure
		CloseHandle(hThreadSnap);          // clean the snapshot object
		return(FALSE);
	}

	// Now walk the thread list of the system,
	// and display information about each thread
	// associated with the specified process
	do
	{
		if (te32.th32OwnerProcessID == dwOwnerPID)
		{
			_tprintf(TEXT("\n\n     THREAD ID      = 0x%08X"), te32.th32ThreadID);
			_tprintf(TEXT("\n     Base priority  = %d"), te32.tpBasePri);
			_tprintf(TEXT("\n     Delta priority = %d"), te32.tpDeltaPri);
			_tprintf(TEXT("\n"));
		}
	} while (Thread32Next(hThreadSnap, &te32));

	CloseHandle(hThreadSnap);
	return(TRUE);
}

void printError(TCHAR* msg)
{
	DWORD eNum;
	TCHAR sysMsg[256];
	TCHAR* p;

	eNum = GetLastError();
	FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
		NULL, eNum,
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
		sysMsg, 256, NULL);

	// Trim the end of the line and terminate it with a null
	p = sysMsg;
	while ((*p > 31) || (*p == 9))
		++p;
	do { *p-- = 0; } while ((p >= sysMsg) &&
		((*p == '.') || (*p < 33)));

	// Display the message
	_tprintf(TEXT("\n  WARNING: %s failed with error %d (%s)"), msg, eNum, sysMsg);
}

int ListProcessHeap(DWORD dwPID)
{
	HEAPLIST32 hl;

	HANDLE hHeapSnap = CreateToolhelp32Snapshot(TH32CS_SNAPHEAPLIST, GetCurrentProcessId());

	hl.dwSize = sizeof(HEAPLIST32);

	if (hHeapSnap == INVALID_HANDLE_VALUE)
	{
		printf("CreateToolhelp32Snapshot failed (%d)\n", dwPID);
		return 1;
	}

	if (Heap32ListFirst(hHeapSnap, &hl))
	{
		do
		{
			HEAPENTRY32 he;
			ZeroMemory(&he, sizeof(HEAPENTRY32));
			he.dwSize = sizeof(HEAPENTRY32);

			if (Heap32First(&he, GetCurrentProcessId(), hl.th32HeapID))
			{
				printf("\nHeap ID: %d\n", hl.th32HeapID);
				do
				{
					printf("Block size: %d\n", he.dwBlockSize);

					he.dwSize = sizeof(HEAPENTRY32);
				} while (Heap32Next(&he));
			}
			hl.dwSize = sizeof(HEAPLIST32);
		} while (Heap32ListNext(hHeapSnap, &hl));
	}
	else printf("Cannot list first heap (%d)\n", GetLastError());

	CloseHandle(hHeapSnap);

	return 0;
}

int main()
{
	GetProcessList();

	return 0;
}
在程序或者函数的具体使用过程中,根据需要进行修改
GetCurrentProcessId() 函数直接返回当前进程ID


第五届安全开发者峰会(SDC 2021)10月23日上海召开!限时2.5折门票(含自助午餐1份)

收藏
点赞1
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回