Toolhelp API 简介
Toolhelp APIs是Windows中一组能够方便得到系统中win32应用程序的当前运行状况的
函数,这些函数设计目的是实现一些基于Win32子系统的工具,特别是调试器。通过使用
Toolhelp API,我们可以实现象Windows附带的系统工具Dr watson一样的功能(当然真正
实现它的所有功能不是光靠Toolhelp API一个函数库就可以的)。而且这些函数适用于
win9x,winnt,win2k,所以不需要为在不同的windows版本中移植代码操心。
下面将介绍ToolHelp APIs中一些主要的函数和结构。主要有CreateToolhelp32Sna
pshot和Xxx32First,Xxx32Next系列函数,还有Toolhelp32ReadProcessMemory。所用语
言为Object Pascal,对于使用C++的程序员可以参考SDK index中的tool help library
[Win32].
以下是它们的定义和说明:
1. 创建快照函数CreateToolhelp32Snapshot
function CreateToolhelp32Snapshot(
dwFlags
WORD, // 要得到进程的信息,赋为TH32CS_SNAPPROCESS
// 要得到线程的信息,赋为TH32CS_SNAPTHREAD
// 要得到指定进程的堆列表,赋为TH32CS_SNAPHEAPLIST
// 要得到指定进程的模块列表,赋为TH32CS_SNAPMODULE
th32ProcessID: DWORD // 当我们把dwFlags赋为TH32CS_SNAPMODULE 或者
// TH32CS_SNAPHEAPLIST时,需要指定具体的进程ID,否则
// 将忽略此参数。把它赋为0表示当前进程(也就是自己)
): THandle; // 返回值THandle将在以后要枚举进程、线程等对象时使用
当我们得到快照的句柄后可以分别使用Xxx32First,Xxx32Next这些函数进行对象枚举。
它们的定义如下所示:
2. Xxx32First,Xxx32Next枚举函数与有关结构
l 进程有关的函数与结构
tagPROCESSENTRY32 = packed record
dwSize: DWORD; // 指定结构的大小,
// 在调用Process32First前需要设置,否则将会失败
cntUsage: DWORD; // 引用计数
th32ProcessID: DWORD; // 进程号
th32DefaultHeapID: DWORD; // 进程的堆号,只对Toolhelp函数有意义,并不是一个有效句柄
th32ModuleID: DWORD; // 进程的模块号,只对Toolhelp函数有意义,并不是一个有效句柄
cntThreads: DWORD; // 进程中包括的线程数
th32ParentProcessID: DWORD; // 进程的母进程
pcPriClassBase: Longint; // 进程的线程的基优先级,所有此进程创建的线程将基于此优先级
dwFlags: DWORD; // 保留,没有使用
szExeFile: array[0..MAX_PATH - 1] of Char; // 进程所对应的文件及路径
end;
TProcessEntry32 = tagPROCESSENTRY32;
function Process32First(
hSnapshot: THandle; // 前面由CreateToolhelp32Snapshot创建的快照句柄
var lppe: TProcessEntry32 //函数输出进程信息
): BOOL; //调用成功将为True,否则为False
function Process32Next(hSnapshot: THandle; var lppe: TProcessEntry32): BOOL;
l 模块有关的函数和结构
tagMODULEENTRY32 = record
dwSize: DWORD; // 指定结构的大小,
// 在调用Module32First前需要设置,否则将会失败
th32ModuleID: DWORD; // 模块号
th32ProcessID: DWORD; // 包含本模块的进程号
GlblcntUsage: DWORD; // 本模块的全局引用计数
ProccntUsage: DWORD; // 包含模块的进程上下文中的模块引用计数
modBaseAddr: PBYTE; // 模块基地址
modBaseSize: DWORD; // 模块大小(字节数)
hModule: HMODULE; // 包含模块的进程上下文中的hModule句柄
// 注意:modBaseAddr 与 hModule 只在th32ProcessID的
// 上下文才有效
szModule: array[0..MAX_MODULE_NAME32] of Char; //模块名
szExePath: array[0..MAX_PATH - 1] of Char; //模块对应的文件名和路径
end;
TModuleEntry32 = tagMODULEENTRY32;
function Module32First(hSnapshot: THandle; var lpme: TModuleEntry32): BOOL; //同进程说明
function Module32Next(hSnapshot: THandle; var lpme: TModuleEntry32): BOOL;
l 线程有关的函数和结构
tagTHREADENTRY32 = record
dwSize: DWORD; // 指定结构的大小,
// 在调用Thread32First前需要设置,否则将会失败
cntUsage: DWORD; // 线程引用计数
th32ThreadID: DWORD; // 线程号
th32OwnerProcessID: DWORD; // 拥有线程的进程号
tpBasePri: Longint; // 在线程创建时的初始优先级
tpDeltaPri: Longint; // 现在线程的优先级的相对于初始值的改变量
dwFlags: DWORD; // 保留,没有使用
end;
TThreadEntry32 = tagTHREADENTRY32;
function Thread32First(hSnapshot: THandle; var lpte: TThreadEntry32): BOOL; stdcall;
function Thread32Next(hSnapshot: THandle; var lpte: TThreadENtry32): BOOL; stdcall;
l 堆有关的函数和结构
tagHEAPENTRY32 = record
dwSize: DWORD; // 指定结构的大小,
// 在调用Heap32First前需要设置,否则将会失败
hHandle: THandle; // 堆的句柄
dwAddress: DWORD; // 堆起始位置的线性地址
dwBlockSize: DWORD; // 堆的大小(字节数)
dwFlags: DWORD; // 标志,为以下值
// LF32_FIXED 堆内存块的位置是固定的
// LF32_FREE 堆内存块没有使用
// LF32_MOVEABLE 堆内存块的位置是可移动的
dwLockCount: DWORD; // 堆的锁定计数,每次对堆的执行GlobalLock
// 或者LocalLock都将使它增1
dwResvd: DWORD; // 保留,没有使用
th32ProcessID: DWORD; // 拥有本堆的进程号,
// 这个ID是可以被其他WIN32 API使用的。
th32HeapID: DWORD; // 堆号,只能在ToolHelp API中内部使用,
// 并不是有效的句柄
end;
THeapEntry32 = tagHEAPENTRY32;
function Heap32First(var lphe: THeapEntry32; th32ProcessID, th32HeapID: DWORD): BOOL;
function Heap32Next(var lphe: THeapEntry32): BOOL;
3. 更为有用的Toolhelp API函数有Toolhelp32ReadProcessMemory,它可以读其他进程内存空间的内容。
function Toolhelp32ReadProcessMemory(
th32ProcessID: DWORD; // 指定进程
lpBaseAddress: Pointer; // 要读的进程内存空间的起始地址
var lpBuffer; // 将要读的内容的保存缓冲区
cbRead: DWORD; // 要读的字节数
var lpNumberOfBytesRead: DWORD // 成功读取的字节数
): BOOL; // 函数成功返回True,否则返回False
下面我通过一个使用Delphi编写的枚举当前系统中的进程的程序来示范具体如何使用Toolhelp APIs.
得到其他进程的句柄是很有用的,比如可以清楚知道现在有哪些程序在运行,对于清楚知道系统中
应该运行什么程序的用户来说,那些后门程序将暴露无遗。当然Toolhelp API的其他功能
主要还是使用在高级应用中。
首先我们应该调用CreateToolhelp32Snapshot创建快照;然后调用Process32First,把创
建的快照的句柄传递给hSnapshot参数,函数成功返回后我们将在lppe参数中得到第一个进
程的信息;继续调用Process32Next,我们将得到后续的进程信息,直到Process32Next返
回False为止。记住最后我们应该调用CloseHandle把快照的句柄安全的释放。
是不是很简单?下面是范例的源程序,为了简单起见,我只写了关键的语句。
uses ... TLHelp32, ... // 需要用到TLHelp32单元即Toolhelp API library.
type
TForm1 = class(TForm)
...
end;
var
Form1: TForm1;
MyProcess : Tlist; // 返回的进程信息在MyProcess这个TList中。
type
TProcessInfo = Record
ExeFile : String;
ProcessID : DWORD;
end;
pProcessInfo = ^TProcessInfo;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
var
p : pProcessInfo;
IsLoopContinue:BOOL;
FSnapshotHandle:THandle;
FProcessEntry32:TProcessEntry32;
begin
MyProcess := TList.Create; // 保存进程信息的列表
MyProcess.Clear; // 初始化列表
FSnapshotHandle:=
CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0); // 创建系统快照
FProcessEntry32.dwSize:=Sizeof(FProcessEntry32); // 必须先设置结构的大小
IsLoopContinue:=
Process32First(FSnapshotHandle,FProcessEntry32); //得到第一个进程信息
while integer(IsLoopContinue)<>0 do
begin
New(p);
p.ExeFile := FProcessEntry32.szExeFile;
p.ProcessID := FProcessEntry32.th32ProcessID;
MyProcess.Add(p); // 添加进程信息
IsLoopContinue:=Process32Next(FSnapshotHandle,FProcessEntry32); // 继续枚举
end;
CloseHandle(FSnapshotHandle); // 释放快照句柄
end;
procedure TForm1.FormDestroy(Sender: TObject);
var
p : pProcessInfo;
i : integer;
begin
With MyProcess do
for i := Count - 1 DownTo 0 do
begin
p := items
;
Dispose(p); // 清除动态分配的内存
Delete(i); // 删除列表中的项
end;
end;
...
end.
作者会员名:aceszjp