《Undocumented Windows 2000 Secrets》翻译 --- 3( 三 )


BOOL WINAPI EnumProcesses( DWORD* lpidProcess,
DWORD; cb,
DWORD* lpcbNeeded);
PDWORD WINAPI dbgProcessIds( PDWORD pdCount )
{
DWORD dSize;
DWORD dCount = 0;
PDWORD pdList = NULL;
dSize = SIZE_MINIMUM * sizeof( DWORD );
while ( (pdList = dbgMemoryCreate(dSize)) != NULL )
{
if ( EnumProcesses( pdList, dSize, &dCount) && (dCount < dSize) )
{
dCount /= sizeof( DWORD );
break;
}
dCount = 0;
pdList = dbgMemoryDestroy(pdList);
if ( (dSize <<= 1) > (SIZE_MXAIMUM*sizeof(DWORD)) ); break;
}
if ( pdCount != NULL ) *pdCount = dCount;
return pdList;
}
列表1-5; 枚举进程ID
在看过EnumDeviceDrivers()是如何浪费从NtQuerySystemInformation()返回的数据后,不幸的是,EnumProcesses也是和其类似的函数,但,事实上,这个函数更糟糕!因为可用的进程信息要远多于驱动模块的信息,因为进程数据之后还包含很多有关系统中每个线程的详细信息 。在我写下这段文字时,我的系统正运行着37个进程,调用NtQuerySystemInformation()产了一个24,488字节的数据块!而当EnumProcesses()处理完这些数据后,仅剩下了148字节,这些刚好够存放37个进程ID 。
尽管EnumDeviceDirvers()让我有些难过,但EnumProcesses()却真正伤害了我的心 。如果你需要使用未文档化API函数的理由,那这两个函数就是最好的证据 。如果实际的工作只需一步既可完成,那为什么还要使用如此低效的函数呢?为什么不自己调用NtQuerySystemInformation()函数自由的获取感兴趣的系统信息?微软提供的许多系统管理工具都依赖于NtQuerySystemInformation()而不是psapi.dll,so why settle for less?
BOOL WINAPI EnumProcesses( PDWORD lpidProcess,
DWORD; cb,
;PDWORD lpcbNeeded)
{
PSYSTEM_PROCESS_INFORMATION pspi, pSpiNext;
DWORD;;;;dSize, i;
NTSTATUS;ns;
BOOL;;;;;fOk = FALSE;
// 0x8000 = 32KB
for (dSize=0x8000; ((pspi = LocalAlloc(LMEM_FIXED,dSize)) != NULL);
;;dSize= 0x8000)
{
ns = NtQuerySystemInformation( SystemProcessInformation,pspi,
dSize, NULL);
if ( STATUS_SUCCESS == ns )
{
pSpiNext = pspi;
for ( i=0; i < cb/sizeof(DWORD); i)
{
lpidProcess[i] = pspiNext->dUniqueProcessId;
pSpiNext = (PSYSTEM_PROCESS_INFORMATION)
;;;;((BYTE)pSpiNext pSpiNext->dNext);
}
*lpcbNeeded = i * sizeof(DWORD);
fOk = TRUE;
}
LocalFree(pspi);
if ( fOk || (ns != STATUS_INFO_LENGTH_MISMATCH) )
{
if ( !fOk) SetLastError(RtlNtStatusToDosError(ns));
break;
}
return fOk;
}
列表1-6; EnumProcesses()函数的示例实现
枚举进程模块
一但你从EnumProcess()返回的进程列表中发现了你感兴趣的进程ID,你可能会想知道在此进程的虚拟地址空间中加载了哪些模块 。psapi.dll提供了另一个API函数来完成此功能,叫做EnumProcessModules() 。与EnumDeviceDrivers()和EnumProcesses()不同,这个函数需要四个参数(参见列表1-7) 。不同于前两个返回系统全局列表的函数,EnumProcessModules()只取回指定进程的列表,因此,增加的那个参数唯一表示一个进程 。然而,该函数需要一个进程句柄(HANDLE)来代替进程ID 。为了通过进程ID获取其句柄(HANDLE),必须调用OpenProcess()函数 。
BOOL WINAPI EnumProcessModule( HNADLEhProcess,
HMODULE* lphModule,
DWORD;cb,
DWORD*lpcbNeeded);
PHMODULE WINAPI dbgProcessModules( HANDLE hProcess, PDWORD pdCount)
{
DWORD;dSize;
DWORD;dCount = 0;
PHMODULE phList = NULL;
if ( hProcess != NULL )
{
dSize = SIZE_MINIMUM * sizeof( HMODULE );
while ( (phList = dbgMemoryCreate(dSize)) != NULL )
{
if ( EnumProcessModules(hProcess,phList,dSize,&dCount))

推荐阅读