关于Enum Module的方法 ,我想最常用的就是ZwQuerySystemInformation函数。我们知道这个函数是一个undocumented function。未文档化的函数有一个地方让人不放心,就是微软可能在某个时候改变他。这里我想介绍一个文档化的方法来列举系统模块。实际上,这并不是一个新技术了,但是好像很多朋友还是在用未文档的ZwQuerySystemInformation列举系统模块,那么我就在这科普一下,只当是抛砖引玉。我建议大家还是尽量用文档化的方法,除非您更喜欢使用未文档的东西。^_^
首先介绍下Auxiliary Kernel-Mode Library,中文名为辅助内核模式库。您可以在微软提供的WDK中找到他(aux_klib.h,aux_klib.lib),这就意味着他不会再DDK中出现。这个库里的几个函数可以让内核模式驱动程序访问部分系统功能。他们具体是:
AuxKlibInitialize
AuxKlibQueryModuleInformation
AuxKlibGetImageExportDirectory
AuxKlibGetBugCheckData
由函数名我们已经可以看出他们大概都是干什么的。这里我重点介绍一下AuxKlibQueryModuleInformation。
AuxKlibQueryModuleInformation的函数原型为
NTSTATUS
AuxKlibQueryModuleInformation (
IN OUT PULONG BufferSize,
IN ULONG ElementSize,
OUT PVOID QueryInfo OPTIONAL
);
BufferSize:是个指向ULONG的指针,用来传递或接收缓冲区大小。如果第三个参数QueryInfo是NULL,那么函数会返回系统模块的字节数。如果QueryInfo不是NULL那么该参数就必须包含缓冲区字节数。
ElementSize:传递一个字节数。函数 sizeof( AUX_MODULE_BASIC_INFO )或 sizeof( AUX_MODULE_EXTENDED_INFO ) 。函数用他来判断第三个参数返回的类型。
QueryInfo:返回一个指向 AUX_MODULE_BASIC_INFO 或 AUX_MODULE_EXTENDED_INFO 的指针。
再来看看 AUX_MODULE_BASIC_INFO 或 AUX_MODULE_EXTENDED_INFO 这两个数据结构
typedef struct _AUX_MODULE_BASIC_INFO {
PVOID ImageBase;
} AUX_MODULE_BASIC_INFO, *PAUX_MODULE_BASIC_INFO;
typedef struct _AUX_MODULE_EXTENDED_INFO {
AUX_MODULE_BASIC_INFO BasicInfo;
ULONG ImageSize;
USHORT FileNameOffset;
UCHAR FullPathName [AUX_KLIB_MODULE_PATH_LEN];
} AUX_MODULE_EXTENDED_INFO, *PAUX_MODULE_EXTENDED_INFO;
不用多做解释,结构中的变量只是SYSTEM_MODULE_INFORMATION的一部分而已。
typedef struct _SYSTEM_MODULE_INFORMATION {
ULONG Reserved[2];
PVOID Base;
ULONG Size;
ULONG Flags;
USHORT Index;
USHORT Unknown;
USHORT LoadCount;
USHORT ModuleNameOffset;
CHAR ImageName[256];
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
说到这里,您应该想到这个函数应该就是对ZwQuerySystemInformation进行了一个封装而已。大家是不是想赶快试一下这个函数了?但是请不要着急,还有一个地方要说。不知道大家注意了AuxKlibInitialize这个函数没有。(也许您找就看出来了吧^_^)AuxKlibInitialize这个函数是用来初始化Auxiliary Kernel-Mode Library 的。也就是出当您要调用AuxKlibQueryModuleInformation时,必须先写AuxKlibInitialize这个函数。这个函数很简单,我们看看他的原型。
NTSTATUS
AuxKlibInitialize (
VOID
);
好了,说了这么多理论知识,也该动手试一试这个函数了。
NTSTATUS AUX_FUNC()
{
NTSTATUS ns = STATUS_SUCCESS;
ULONG uRet;
AUX_MODULE_EXTENDED_INFO* stModuleInfo;
ULONG uCount;
ULONG i;
ns = AuxKlibInitialize();
ns = AuxKlibQueryModuleInformation( &uRet ,sizeof( AUX_MODULE_EXTENDED_INFO ) ,NULL );
uCount = uRet / sizeof( AUX_MODULE_EXTENDED_INFO );
stModuleInfo = (AUX_MODULE_EXTENDED_INFO*)ExAllocatePoolWithTag( PagedPool, uRet ,'AUX');
RtlZeroMemory( stModuleInfo ,uRet );
ns = AuxKlibQueryModuleInformation( &uRet ,sizeof( AUX_MODULE_EXTENDED_INFO ) ,stModuleInfo );
for ( i = 0 ;i < uCount ; i++ )
{
KdPrint(( "%s/n" ,stModuleInfo[i].FullPathName ));
}
return ns;
}
这个过程很简单,只是为了说明这个文档化方法可以用。
好了,最后来证实一下我们刚刚的猜想,看他是否调用了ZwQuerySystemInformation。
用WinDbg调试一下可以看到在AuxKlibQueryModuleInformation函数中有以下代码
f781b0df 51 push ecx
f781b0e0 50 push eax
f781b0e1 53 push ebx
f781b0e2 6a0b push 0Bh
f781b0e4 ff15389081f7 call dword ptr [AuxKlibQueryModuleInformation!_imp__ZwQuerySystemInformation (f7819038)] ds:0023:f7819038={nt!ZwQuerySystemInformation (8082cc34)}
下面是栈回溯的结果
kd> k
ChildEBP RetAddr
f655dabc f781b0ea nt!ZwQuerySystemInformation [D:/wrk-v1.2/base/ntos/ke/i386/sysstubs.asm @ 1564]
f655dc40 f7818131 AuxKlibQueryModuleInformation!AuxKlibQueryModuleInformation+0x92 [d:/winmain/base/auxapilib/kmode/aux_klib.c @ 417]
f655dc68 f781820c AuxKlibQueryModuleInformation!AUX_FUNC+0x71 [f:/driver/auxklibquerymoduleinformation/auxklibquerymoduleinformation.c @ 54]
f655dc88 808ed241 AuxKlibQueryModuleInformation!DriverEntry+0x8c [f:/driver/auxklibquerymoduleinformation/auxklibquerymoduleinformation.c @ 83]
哦!还有更轻松的办法用来看出这一点。直接拖进IDA吧。^_^
可以看到这些代码。
PAGE:000140D9 lea ecx, [ebp+NumberOfBytes]
PAGE:000140DF push ecx ; ReturnLength
PAGE:000140E0 push eax ; SystemInformationLength
PAGE:000140E1 push ebx ; SystemInformation
PAGE:000140E2 push 0Bh ; SystemInformationClass
PAGE:000140E4 call ds:__imp__ZwQuerySystemInformation@16 ; ZwQuerySystemInformation(x,x,x,x)
PAGE:000140EA mov [ebp+var_144], eax
PAGE:000140F0 test eax, eax
这样,我们就确定了。AuxKlibQueryModuleInformation的确调用了ZwQuerySystemInformation。
文章写到这里就该结束了。最后提醒大家一下记得设置SOURCES的TARGETLIBS,不然找不到aux_klib.lib。
祝大家玩的愉快!^_^
AuxKlibQueryModuleInformation.rar
首先介绍下Auxiliary Kernel-Mode Library,中文名为辅助内核模式库。您可以在微软提供的WDK中找到他(aux_klib.h,aux_klib.lib),这就意味着他不会再DDK中出现。这个库里的几个函数可以让内核模式驱动程序访问部分系统功能。他们具体是:
AuxKlibInitialize
AuxKlibQueryModuleInformation
AuxKlibGetImageExportDirectory
AuxKlibGetBugCheckData
由函数名我们已经可以看出他们大概都是干什么的。这里我重点介绍一下AuxKlibQueryModuleInformation。
AuxKlibQueryModuleInformation的函数原型为
NTSTATUS
AuxKlibQueryModuleInformation (
IN OUT PULONG BufferSize,
IN ULONG ElementSize,
OUT PVOID QueryInfo OPTIONAL
);
BufferSize:是个指向ULONG的指针,用来传递或接收缓冲区大小。如果第三个参数QueryInfo是NULL,那么函数会返回系统模块的字节数。如果QueryInfo不是NULL那么该参数就必须包含缓冲区字节数。
ElementSize:传递一个字节数。函数 sizeof( AUX_MODULE_BASIC_INFO )或 sizeof( AUX_MODULE_EXTENDED_INFO ) 。函数用他来判断第三个参数返回的类型。
QueryInfo:返回一个指向 AUX_MODULE_BASIC_INFO 或 AUX_MODULE_EXTENDED_INFO 的指针。
再来看看 AUX_MODULE_BASIC_INFO 或 AUX_MODULE_EXTENDED_INFO 这两个数据结构
typedef struct _AUX_MODULE_BASIC_INFO {
PVOID ImageBase;
} AUX_MODULE_BASIC_INFO, *PAUX_MODULE_BASIC_INFO;
typedef struct _AUX_MODULE_EXTENDED_INFO {
AUX_MODULE_BASIC_INFO BasicInfo;
ULONG ImageSize;
USHORT FileNameOffset;
UCHAR FullPathName [AUX_KLIB_MODULE_PATH_LEN];
} AUX_MODULE_EXTENDED_INFO, *PAUX_MODULE_EXTENDED_INFO;
不用多做解释,结构中的变量只是SYSTEM_MODULE_INFORMATION的一部分而已。
typedef struct _SYSTEM_MODULE_INFORMATION {
ULONG Reserved[2];
PVOID Base;
ULONG Size;
ULONG Flags;
USHORT Index;
USHORT Unknown;
USHORT LoadCount;
USHORT ModuleNameOffset;
CHAR ImageName[256];
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
说到这里,您应该想到这个函数应该就是对ZwQuerySystemInformation进行了一个封装而已。大家是不是想赶快试一下这个函数了?但是请不要着急,还有一个地方要说。不知道大家注意了AuxKlibInitialize这个函数没有。(也许您找就看出来了吧^_^)AuxKlibInitialize这个函数是用来初始化Auxiliary Kernel-Mode Library 的。也就是出当您要调用AuxKlibQueryModuleInformation时,必须先写AuxKlibInitialize这个函数。这个函数很简单,我们看看他的原型。
NTSTATUS
AuxKlibInitialize (
VOID
);
好了,说了这么多理论知识,也该动手试一试这个函数了。
NTSTATUS AUX_FUNC()
{
NTSTATUS ns = STATUS_SUCCESS;
ULONG uRet;
AUX_MODULE_EXTENDED_INFO* stModuleInfo;
ULONG uCount;
ULONG i;
ns = AuxKlibInitialize();
ns = AuxKlibQueryModuleInformation( &uRet ,sizeof( AUX_MODULE_EXTENDED_INFO ) ,NULL );
uCount = uRet / sizeof( AUX_MODULE_EXTENDED_INFO );
stModuleInfo = (AUX_MODULE_EXTENDED_INFO*)ExAllocatePoolWithTag( PagedPool, uRet ,'AUX');
RtlZeroMemory( stModuleInfo ,uRet );
ns = AuxKlibQueryModuleInformation( &uRet ,sizeof( AUX_MODULE_EXTENDED_INFO ) ,stModuleInfo );
for ( i = 0 ;i < uCount ; i++ )
{
KdPrint(( "%s/n" ,stModuleInfo[i].FullPathName ));
}
return ns;
}
这个过程很简单,只是为了说明这个文档化方法可以用。
好了,最后来证实一下我们刚刚的猜想,看他是否调用了ZwQuerySystemInformation。
用WinDbg调试一下可以看到在AuxKlibQueryModuleInformation函数中有以下代码
f781b0df 51 push ecx
f781b0e0 50 push eax
f781b0e1 53 push ebx
f781b0e2 6a0b push 0Bh
f781b0e4 ff15389081f7 call dword ptr [AuxKlibQueryModuleInformation!_imp__ZwQuerySystemInformation (f7819038)] ds:0023:f7819038={nt!ZwQuerySystemInformation (8082cc34)}
下面是栈回溯的结果
kd> k
ChildEBP RetAddr
f655dabc f781b0ea nt!ZwQuerySystemInformation [D:/wrk-v1.2/base/ntos/ke/i386/sysstubs.asm @ 1564]
f655dc40 f7818131 AuxKlibQueryModuleInformation!AuxKlibQueryModuleInformation+0x92 [d:/winmain/base/auxapilib/kmode/aux_klib.c @ 417]
f655dc68 f781820c AuxKlibQueryModuleInformation!AUX_FUNC+0x71 [f:/driver/auxklibquerymoduleinformation/auxklibquerymoduleinformation.c @ 54]
f655dc88 808ed241 AuxKlibQueryModuleInformation!DriverEntry+0x8c [f:/driver/auxklibquerymoduleinformation/auxklibquerymoduleinformation.c @ 83]
哦!还有更轻松的办法用来看出这一点。直接拖进IDA吧。^_^
可以看到这些代码。
PAGE:000140D9 lea ecx, [ebp+NumberOfBytes]
PAGE:000140DF push ecx ; ReturnLength
PAGE:000140E0 push eax ; SystemInformationLength
PAGE:000140E1 push ebx ; SystemInformation
PAGE:000140E2 push 0Bh ; SystemInformationClass
PAGE:000140E4 call ds:__imp__ZwQuerySystemInformation@16 ; ZwQuerySystemInformation(x,x,x,x)
PAGE:000140EA mov [ebp+var_144], eax
PAGE:000140F0 test eax, eax
这样,我们就确定了。AuxKlibQueryModuleInformation的确调用了ZwQuerySystemInformation。
文章写到这里就该结束了。最后提醒大家一下记得设置SOURCES的TARGETLIBS,不然找不到aux_klib.lib。
祝大家玩的愉快!^_^
AuxKlibQueryModuleInformation.rar