关于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