《Undocumented Windows 2000 Secrets》翻译 --- 3

第一章 Windows 2000对调试技术的支持
翻译:Kendiv
更新:Monday, January 17, 2005
枚举系统模块和驱动(Drivers)
psapi.dll可以返回当前内存中的内核模块 。这本是非常简单的工作 。psapi.dll的EnumDeviceDrivers()函数接受一个PVOID类型的数组,它将用当前活动的内核驱动模块(active kernel-mode driver)的映像基址(image base address)来填充这个数组,这包括基本的内核模块ntdll.dll、ntoskrnl.exe、Win32K.sys、hal.dll和bootvid.dll 。返回值是这些可执行文件映射到的虚拟内存地址(译注,也称作线性地址) 。如果你使用内核调试器或其他调试工具检查这些地址的最初几个字节,你将清楚地认出那个有名的Dos stub程序,它以著名的Mark Zbikowski的首字母大写“MZ”开始,内含一个文本消息--“This program cannot be run in DOS mode”或类似的东西 。列表1-3展示了一个使用EnumDeviceDrivers()的简单函数,以及EnumDeviceDrivers函数的原型 。
BOOL WINAPI EnumDeviceDrivers ( PVOID* lpImageBase,
DWord; cb,
PDWORD lpcbNeeded);
PPVOID WINAPI dbgDriverAddresses( PDWORD pdCount )
{
DWORD dSize;
DWORD dCount = 0;
PPVOID ppList = NULL;
dSize = SIZE_MINIMUM * sizeof( PVOID );
【《Undocumented Windows 2000 Secrets》翻译 --- 3】 while ( (ppList = dbgMemoryCreate(dSize)) != NULL )
{
if ( EnumDeviceDrivers( ppList, dSize, &dCount) && (dCount < dSize) )
{
dCount /= sizeof( PVOID );
break;
}
dCount = 0;
ppList = dbgMemoryDestroy( ppList );
if ( (dSize <<= 1) > (SIZE_MAXIMUM * sizeof( PVOID )))
{
break;
}
}
if ( pdCount != NULL )
{
*pdCount = dCount;
}
return ppList;
}
列表1-3枚举系统模块地址
EnumDeviceDrivers()期望三个参数:一个数组指针,一个表示输入大小的值以及一个用于输出的类型为DWORD的变量 。第二个参数指定了传入的数组的字节数,第三个参数表示复制到该数组中的字节数 。因此,你必须将返回值除以sizeof(PVOID)来确定有多少个地址数据复制到了数组中 。不幸的是,该函数不能帮助你确定该提供多大的数组,尽管它实际上知道有多少个Driver在运行 。但它仅仅告诉你返回了多少字节,而且,如果数组太小,它会隐藏多出的字节 。因此,你必须使用无聊的trial-and-error循环来确定适当的数组大小,就如同列表1-3所示的那样,只要返回值与数组大小相同就假定还有数据未复制到数组中 。在刚开始时,代码中使用了一个合理的最小值--256(由SIZE_MINIMUM表示),这通常都足够大了,但是如果不够的话,在开始新的循环时,数组大小会增加为原来的2倍,直到获取了所有的指针或者数组大小超过了65,536 。数组使用的内存缓冲区由两个帮助函数dbgMemoryCreate()和dbgMemoryDestroy()提供,这两个函数只是Win32函数LocalAlloc和LocalFree的外包而已,这儿就不列出了 。
BOOL WINAPI EnumDeviceDrivers( PVOID* lpImageBase,
DWORD; cb,
DWORD* lpcbNeeded)
{
SYSTEM_MODULE_INFORMATION; smi;
PSYSTEM_MODULE_INFORMATION psmi;
DWORD;;;dSize, i;
NTSTATUSns;
BOOL;;;;fOk = FALSE;
ns = NtQuerySystemInformation( SystemModuleInformation,
&smi, sizeof(smi),NULL);
if ( (STATUS_SUCCESS == ns) | (STATUS_INFO_LENGTH_MISMATCH == ns) )
{
dSize = sizeof(SYSTEM_MODULE_INFORMATION)
;(smi.dCount*sizeof(SYSTEM_MODULE));
if ( (psmi = LocalAlloc(LEME_FIXED,dSize)) != NULL )
{
ns = NtQuerySystemInformation( SystemModuleInformation,psmi,dSize,NULL );
if ( ns == STATUS_SUCCESS )
{
for( i = 0; (i < psmi->dCount) && (i < cb/sizeof(DWORD))i)
lpImageBase[i] = psmi->aModules[i].pImageBase;

推荐阅读