关于未公开函数ZwQuerySystemInformation的使用

本文介绍了在内核编程中遇到的未公开函数ZwQuerySystemInformation,详细讨论了其在获取系统模块信息时的作用。尽管微软官方未提供完整信息,但通过网络资源,作者分享了一段ring3环境下使用该函数获取进程模块信息的代码,并解析了SYSTEM_MODULE_INFORMATION结构。对比drivers.exe,揭示了ZwQuerySystemInformation在不同信息类下的功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

      最近看一些关于内核方面的资料,碰到未公开函数,未能在微软官方找到答案,从网上了解到一些信息,摘录下来备用。

      我看到驱动程序在ring0调用的一段代码的使用:

ULONG GetModuleBase(PCHAR szModuleName)
{
    ULONG uSize = 0x10000;
    PVOID pModuleInfo = ExAllocatePoolWithTag(NonPagedPool, 
                                            uSize, 
                                            'GetB');
    if (pModuleInfo == NULL)
    {
        KdPrint(("ExAllocatePoolWithTag failed\n"));
        return 0;
    }
    RtlZeroMemory(pModuleInfo, uSize);

    NTSTATUS status = ZwQuerySystemInformation(SystemModuleInformation, 
        pModuleInfo, 
        uSize, 
        NULL);

    if(!NT_SUCCESS(status))
    {
        KdPrint(("FindModuleByAddress query failed\n"));
        KdPrint(("FindModuleByAddress status: 0x%x\n", status));
        if (pModuleInfo != NULL)
        {
            ExFreePool(pModuleInfo);
            pModuleInfo = NULL;
        }
        return 0;
    }

    ULONG uNumberOfModules = *(PULONG)pModuleInfo;
    if (uNumberOfModules == 0)
    {
        return 0;
    }

    PRTL_PROCESS_MODULE_INFORMATION pStart = 
        (PRTL_PROCESS_MODULE_INFORMATION)((ULONG)pModuleInfo + sizeof(ULONG));

    for (ULONG uCount = 0; uCount < uNumberOfModules; uCount++)
    {
        PUCHAR pszFullPathName = (PUCHAR)pStart->FullPathName;

        ULONG uOffsetName = pStart->OffsetToFileName;

        PUCHAR pszName = (PUCHAR)(pszFullPathName + uOffsetName);

        if (_stricmp((const char *)pszName, szModuleName) == 0)
        {
            ULONG uImageBase = (ULONG)pStart->ImageBase;
            if (pModuleInfo != NULL)
            {
                ExFreePool(pModuleInfo);
                pModuleInfo = NULL;
            }
            return uImageBase;
        }

        pStart++;
    }
    
    if (pModuleInfo != NULL)
    {
        ExFreePool(pModuleInfo);
        pModuleInfo = NULL;
    }
    return 0;
}
      上面代码GetModuleBase功能是获取指定名字的模块的内存中的基址。

      其中ZwQuerySystemInformation函数微软官方链接:ZwQuerySystemInformation并未能提供足够的信息,SystemModuleInformation并没有在官方链接中找到描述的使用方法。我想官方不可能会漏掉这个使用,故意不公开一定是有原因的,传统上的原因是这块内容很可能在后面的版本改变不公开给用户使用。我不管是什么原因,能弄清楚这块内容,就是我的目标。

      函数原型:

NTSTATUS WINAPI ZwQuerySystemInformation(
  _In_       SYSTEM_INFORMATION_CLASS SystemInformationClass,
  _Inout_    PVOID SystemInformation,
  _In_       ULONG SystemInformationLength,
  _Out_opt_  PULONG ReturnLength
);

      在网上找到一段利用在ring3中利用ZwQuerySystemInformation来获取进程模块信息的代码,稍加修改,就可以正常编译运行,功能类似于ddk提供的drivers.exe的功能,上代码:

// DeepInNativeApi.cpp : Defines the entry point for the console application.
//

/*
* For x86/EWindows XP SP1 & VC 7      Win7 32bit&VC9
* cl listmodule.c /Os /G6 /W3
*
* Usage: listmodule
*/

/************************************************************************
*                                                                      *
*                               Head File                              *
*                                                                      *
************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <windows.h>

/************************************************************************
*                                                                      *
*                               Macro                                  *
*                                                                      *
************************************************************************/

#pragma comment( linker, “/subsystem:console” )
typedef LONG NTSTATUS;

#define NT_SUCCESS(status)      ((NTSTATUS)(status)>=0)

/*
*************************************************************************
* <<Windows NT/2000 Native API Reference>> by Gary Nebbett
*/

/*
* 虽然本程序用不到这么多枚举值,还是列出一份最完整的。这个程序本身不求完
* 美,尽可能多地保留一些未文档化的参考资料。
*/
typedef enum _SYSTEM_INFORMATION_CLASS     //    Q S
{
    SystemBasicInformation,                // 00 Y N
    SystemProcessorInformation,            // 01 Y N
    SystemPerformanceInformation,          // 02 Y N
    SystemTimeOfDayInformation,            // 03 Y N
    SystemNotImplemented1,                 // 04 Y N
    SystemProcessesAndThreadsInformation,  // 05 Y N
    SystemCallCounts,                      // 06 Y N
    SystemConfigurationInformation,        // 07 Y N
    SystemProcessorTimes,                  // 08 Y N
    SystemGlobalFlag,                      // 09 Y Y
    SystemNotImplemented2,                 // 10 Y N
    SystemModuleInformation,               // 11 Y N
    SystemLockInformation,                 // 12 Y N
    SystemNotImplemented3,                 // 13 Y N
    SystemNotImplemented4,                 // 14 Y N
    SystemNotImplemented5,                 // 15 Y N
    SystemHandleInformation,               // 16 Y N
    SystemObjectInformation,               // 17 Y N
    SystemPagefileInformation,             // 18 Y N
    SystemInstructionEmulationCounts,      // 19 Y N
    SystemInvalidInfoClass1,               // 20
    SystemCacheInformation,                // 21 Y Y
    SystemPoolTagInformation,              // 22 Y N
    SystemProcessorStatistics,             // 23 Y N
    SystemDpcInformation,                  // 24 Y Y
    SystemNotImplemented6,                 // 25 Y N
    SystemLoadImage,                       // 26 N Y
    SystemUnloadImage,                     // 27 N Y
    SystemTimeAdjustment,                  // 28 Y Y
    SystemNotImplemented7,                 // 29 Y N
    SystemNotImplemented8,                 // 30 Y N
    SystemNotImplemented9,                 // 31 Y N
    SystemCrashDumpInformation,            // 32 Y N
    SystemExceptionInformation,            // 33 Y N
    SystemCrashDumpStateInformation,       // 34 Y Y/N
    SystemKernelDebuggerInformation,       // 35 Y N
    SystemContextSwitchInformation,        // 36 Y N
    SystemRegistryQuotaInformation,        // 37 Y Y
    SystemLoadAndCallImage,                // 38 N Y
    SystemPrioritySeparation,              // 39 N Y
    SystemNotImplemented10,                // 40 Y N
    SystemNotImplemented11,                // 41 Y N
    SystemInvalidInfoClass2,               // 42
    SystemInvalidInfoClass3,               // 43
    SystemTimeZoneInformation,             // 44 Y N
    SystemLookasideInformation,            // 45 Y N
    SystemSetTimeSlipEvent,                // 46 N Y
    SystemCreateSession,                   // 47 N Y
    SystemDeleteSession,                   // 48 N Y
    SystemInvalidInfoClass4,               // 49
    SystemRangeStartInformation,           // 50 Y N
    SystemVerifierInformation,             // 51 Y Y
    SystemAddVerifier,                     // 52 N Y
    SystemSessionProcessesInformation      // 53 Y N
} SYSTEM_INFORMATION_CLASS;

typedef struct _SYSTEM_MODULE_INFORMATION  // Information Class 11
{
    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;
/*
* <<Windows NT/2000 Native API Reference>> by Gary Nebbett
*************************************************************************
*/

/*
* 参看DDK文档以及<<Windows NT/2000 Native API Reference>> by Gary Nebbett
* 这些Native API由ntdll.dll输出
*/
typedef NTSTATUS ( __stdcall *ZWQUERYSYSTEMINFORMATION ) ( IN SYSTEM_INFORMATION_CLASS SystemInformationClass, IN OUT PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG ReturnLength OPTIONAL );
typedef ULONG    ( __stdcall *RTLNTSTATUSTODOSERROR    ) ( IN NTSTATUS Status );

/************************************************************************
*                                                                      *
*                            Function Prototype                        *
*                                                                      *
************************************************************************/

static void    ListModule         ( void );
static BOOLEAN LocateNtdllEntry   ( void );
static void    PrintWin32Error    ( char *message, DWORD dwMessageId );
static void    PrintZwError       ( char *message, NTSTATUS status );
static PVOID   PrivateFindModule  ( const char *ModuleName );

/************************************************************************
*                                                                      *
*                            Static Global Var                         *
*                                                                      *
************************************************************************/

/*
* 由ntdll.dll输出的Native API函数指针
*/
static ZWQUERYSYSTEMINFORMATION ZwQuerySystemInformation = NULL;
static RTLNTSTATUSTODOSERROR    RtlNtStatusToDosError    = NULL;

/************************************************************************/

static void ListModule ( void )
{
    NTSTATUS                    status;
    PSYSTEM_MODULE_INFORMATION  module = NULL;
    ULONG                       n      = 0;
    ULONG                       i      = 0;
    void                       *buf    = NULL;

    ZwQuerySystemInformation( SystemModuleInformation, &n, 0, &n );
    if ( NULL == ( buf = calloc( ( size_t )n, 1 ) ) )
    {
        fprintf( stderr, "calloc() failed\n" );
        goto ListModule_return;
    }
    /*
     * <<Windows NT/2000 Native API Reference>> by Gary Nebbett所给的例子
     * 1.3以及A.2对第二、三形参理解有误,下面才是正确的用法。
     */
    status = ZwQuerySystemInformation( SystemModuleInformation, buf, n, NULL );
    if ( !NT_SUCCESS( status ) )
    {
        PrintZwError( "ZwQuerySystemInformation() failed", status );
        goto ListModule_return;
    }
    module = ( PSYSTEM_MODULE_INFORMATION )( ( PULONG )buf + 1 );
    n      = *( ( PULONG )buf );
    for ( i = 0; i < n; i++ )
    {
        printf( "0x%08X %s\n", module[i].Base, module[i].ImageName + module[i].ModuleNameOffset );
    }

ListModule_return:

    if ( buf != NULL )
    {
        free( buf );
        buf = NULL;
    }
    return;
}  /* end of ListModule */

/*
* ntdll.dll输出了所有的Native API
*/
static BOOLEAN LocateNtdllEntry ( void )
{
    BOOLEAN boolean_ret = FALSE;
    char    NTDLL_DLL[] = "ntdll.dll";
    HMODULE ntdll_dll   = NULL;

    /*
     * returns a handle to a mapped module without incrementing its
     * reference count
     */
    if ( ( ntdll_dll = GetModuleHandle( NTDLL_DLL ) ) == NULL )
    {
        PrintWin32Error( "GetModuleHandle() failed", GetLastError() );
        return( FALSE );
    }
    if ( !( ZwQuerySystemInformation = ( ZWQUERYSYSTEMINFORMATION )GetProcAddress( ntdll_dll,
         "ZwQuerySystemInformation" ) ) )
    {
        goto LocateNtdllEntry_return;
    }
    if ( !( RtlNtStatusToDosError = ( RTLNTSTATUSTODOSERROR )GetProcAddress( ntdll_dll,
         "RtlNtStatusToDosError" ) ) )
    {
        goto LocateNtdllEntry_return;
    }
    boolean_ret = TRUE;

LocateNtdllEntry_return:

    if ( FALSE == boolean_ret )
    {
        PrintWin32Error( "GetProcAddress() failed", GetLastError() );
    }
    ntdll_dll = NULL;
    return( boolean_ret );
}  /* end of LocateNtdllEntry */

static void PrintWin32Error ( char *message, DWORD dwMessageId )
{
    char *errMsg;

    FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
                   dwMessageId,
                   MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
                   ( LPTSTR )&errMsg, 0, NULL );
    fprintf( stderr, "%s: %s", message, errMsg );
    LocalFree( errMsg );
    return;
}  /* end of PrintWin32Error */

static void PrintZwError ( char *message, NTSTATUS status )
{
    char *errMsg;

    FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
                   RtlNtStatusToDosError( status ),
                   MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
                   ( LPTSTR )&errMsg, 0, NULL );
    fprintf( stderr, "%s: %s", message, errMsg );
    LocalFree( errMsg );
    return;
}  /* end of PrintZwError */

int main ( int argc, char * argv[] )
{
    if ( FALSE == LocateNtdllEntry() )
    {
        fprintf( stderr, "LocateNtdllEntry() failed\n" );
        return( EXIT_FAILURE );
    }
    ListModule();
	system("pause");
    return( EXIT_SUCCESS );
}  /* end of main */

/************************************************************************/
      上面的代码列出了并未文档化的一个枚举结构SYSTEM_INFORMATION_CLASS,这个结构很重要,在微软文档中讲述ZwQuerySystemInformation的第一个参数就指定需要这个结构的一个枚举值(但这个枚举的内容没有全部列出,只列出一小部分,其中没包括第11项SystemModuleInformation,当然也没有包含SYSTEM_MODULE_INFORMATION结构了)。

      我们可以再分析一下SYSTEM_MODULE_INFORMATION结构:

typedef struct _SYSTEM_MODULE_INFORMATION  // Information Class 11
{
    ULONG  Reserved[2]; //未了解用途
    PVOID  Base;      //进程基址
    ULONG  Size;
    ULONG  Flags;
    USHORT Index;
    USHORT Unknown;
    USHORT LoadCount;
    USHORT ModuleNameOffset;  //进程名字偏移
    CHAR   ImageName[256];      //进程映像全路径

    上面的代码使用了以上结构的三个成员,我贴上代码在我本机运行的结果:


再贴一张drivers.exe执行的结果图,其中很多信息也是通过ZwQuerySystemInformation函数实现的,只是第一个参数不同而已。


ZwQuerySystemInformation
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值