C++内核调用ZwQuerySystemInformation报类型不兼容错误排查
内核BigPool查询代码类型转换报错修复
核心错误点
- 自定义的
ZwQuerySystemInformation函数签名完全不符合原生定义:第二个参数被错误定义为PSYSTEM_BIGPOOL_INFORMATION强类型指针,实际应为通用无类型指针PVOID;长度参数、返回长度参数被错误定义为ULONG64类型,实际原生为ULONG类型,这是触发编译报错、甚至后续运行时栈崩溃的核心原因。 - 首次探测缓冲区长度的调用传参逻辑错误:第一次调用函数获取所需缓冲区大小时,不需要传入有效信息结构体指针,直接传
NULL即可,你传入&infoLen(长度变量的地址)和错误的函数签名共同触发了类型不匹配报错。 - 附加逻辑问题:一是自定义的
SystemBigPoolInformation枚举值默认取0,和Windows原生系统的枚举值不匹配,编译通过后调用也会返回参数错误;二是打印SizeInBytes(SIZE_T类型数值)时误用了指针格式符%p,会导致打印值异常。
修正后的代码
修正后的结构体与函数声明
typedef struct _SYSTEM_BIGPOOL_ENTRY { union { PVOID VirtualAddress; ULONG_PTR NonPaged : 1; }; ULONG_PTR SizeInBytes; union { UCHAR Tag[4]; ULONG64 TagULong; }; } SYSTEM_BIGPOOL_ENTRY, *PSYSTEM_BIGPOOL_ENTRY; typedef struct _SYSTEM_BIGPOOL_INFORMATION { ULONG64 Count; SYSTEM_BIGPOOL_ENTRY AllocatedInfo[ANYSIZE_ARRAY]; } SYSTEM_BIGPOOL_INFORMATION, *PSYSTEM_BIGPOOL_INFORMATION; typedef enum _SYSTEM_INFORMATION_CLASS { SystemBigPoolInformation = 66 // 补全原生系统对应枚举值,默认0会导致调用失败 } SYSTEM_INFORMATION_CLASS; // 修正为符合原生定义的函数签名 typedef NTSTATUS(WINAPI* fNtQuerySystemInformation)( SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength ); NTSTATUS ZwQuerySystemInformation( SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength);
注意:内核函数声明必须和系统导出的原生函数签名完全一致,参数类型、参数顺序不匹配会直接导致栈错位、调用崩溃。
修正后的业务实现代码
PVOID ExPool() { ULONG infoLen = 0; NTSTATUS status = ZwQuerySystemInformation(SystemBigPoolInformation, NULL, 0, &infoLen); PSYSTEM_BIGPOOL_INFORMATION pPoolInfo = NULL; while (status == STATUS_INFO_LENGTH_MISMATCH) { DbgPrintEx(0, 0, "Required Length : %lX\n", infoLen); if (pPoolInfo) { ExFreePool(pPoolInfo); pPoolInfo = NULL; } pPoolInfo = (PSYSTEM_BIGPOOL_INFORMATION)ExAllocatePool(NonPagedPool, infoLen); if (!pPoolInfo) { return NULL; } status = ZwQuerySystemInformation(SystemBigPoolInformation, pPoolInfo, infoLen, &infoLen); } if (NT_SUCCESS(status) && pPoolInfo) { DbgPrintEx(0, 0, "Call status : %lX\n", status); DbgPrintEx(0, 0, "BigPool Entry Count : %lu\n", pPoolInfo->Count); for (ULONG64 i = 0; i < pPoolInfo->Count; i++) { SYSTEM_BIGPOOL_ENTRY* Entry = &pPoolInfo->AllocatedInfo[i]; PVOID VirtualAddress = (PVOID)((uintptr_t)Entry->VirtualAddress & ~1ull); SIZE_T SizeInBytes = Entry->SizeInBytes; BOOLEAN NonPaged = (BOOLEAN)(Entry->NonPaged); if (NonPaged && SizeInBytes == 0x200000) { // 修正数值类型的打印格式符,不要用%p打印非地址数值 DbgPrintEx(0, 0, "NonPagedPool Address: %p, Size: %llX\n", VirtualAddress, SizeInBytes); } } ExFreePool(pPoolInfo); pPoolInfo = NULL; } return NULL; }
补充说明
你之前尝试把变量转成ULONG64解决不了问题,因为报错根本不是业务逻辑里的结构体字段类型不匹配,是函数原型定义错误+首次调用传参错误两个基础问题,和结构体里的ULONG/ULONG64字段定义没有关系。
内容的提问来源于stack exchange,提问作者Maurice Moss
相关产品推荐
相关产品推荐

