You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

内核态下NTDLL中_snwprintf处理异常UNICODE_STRING的方案

内核态NTDLL版_snwprintf处理异常UNICODE_STRING的优化方案需求

在挂钩函数并使用_snwprintf格式化记录参数时,遇到如下问题:

  • 当格式化的UNICODE_STRING的MaximumLength为0(或小于Length)时,NTDLL实现的_snwprintf会返回-1,仅打印到失败位置
  • MSVCRT的_snwprintf实现可正常处理该场景,但内核态下无法使用MSVCRT版本

目前已有两种临时解决方案,但均觉繁琐:

  • 将格式串中的%wZ替换为%.*ls,并传入String->Length / sizeof(WCHAR)和String->Buffer作为参数
  • 初始化临时UNICODE_STRING并正确设置MaximumLength后再传入格式化函数

寻求更简洁的优化解决方案。

演示代码

int wmain()
{
    typedef int(__cdecl* _snwprintf_t)(wchar_t* Buffer, size_t BufferCount, const wchar_t* Format, ...);

    _snwprintf_t ntdll_snwprintf = (_snwprintf_t)GetProcAddress(GetModuleHandleW(L"NTDLL.DLL"), "_snwprintf");
    _snwprintf_t msvcrt_snwprintf = _snwprintf;

    const wchar_t* Format = L"Hello, %wZ!";

    UNICODE_STRING String = { 0 };
    String.Buffer = (wchar_t*)L"world";
    String.Length = 5 * sizeof(wchar_t);

    wchar_t ntdll_Buffer[16] = { 0 };
    int ntdll_Result = ntdll_snwprintf(ntdll_Buffer, ARRAYSIZE(ntdll_Buffer), Format, &String);
    wprintf(L"ntdll Result=%d Buffer=%ls\n", ntdll_Result, ntdll_Buffer);

    wchar_t msvcrt_Buffer[16] = { 0 };
    int msvcrt_Result = msvcrt_snwprintf(msvcrt_Buffer, ARRAYSIZE(msvcrt_Buffer), Format, &String);
    wprintf(L"msvcrt Result=%d Buffer=%ls\n", msvcrt_Result, msvcrt_Buffer);

    return 0;
}

输出结果

ntdll Result=-1 Buffer=Hello, 
msvcrt Result=13 Buffer=Hello, world!

问题复现场景代码

typedef NTSTATUS (NTAPI* LdrQueryImageFileExecutionOptions_t)(IN PUNICODE_STRING SubKey, IN PCWSTR ValueName, IN ULONG Type, OUT PVOID Buffer, IN ULONG BufferSize, OUT PULONG ReturnedLength OPTIONAL);
LdrQueryImageFileExecutionOptions_t LdrQueryImageFileExecutionOptions = (LdrQueryImageFileExecutionOptions_t)GetProcAddress(GetModuleHandleW(L"NTDLL.DLL"), "LdrQueryImageFileExecutionOptions");
UNICODE_STRING SubKey = { 0 };
SubKey.Buffer = (PWSTR)L"C:\\Windows\\System32\\notepad.exe";
SubKey.Length = lstrlenW(SubKey.Buffer) * sizeof(WCHAR);
SubKey.MaximumLength = SubKey.Length + sizeof(WCHAR);
NTSTATUS Status = LdrQueryImageFileExecutionOptions(&SubKey, L"test", 0, NULL, 0, NULL);

调试发现,LdrQueryImageFileExecutionOptions会调用子例程提取文件名到新的UNICODE_STRING,但未初始化其MaximumLength,随后传入NtOpenKey。

内容的提问来源于stack exchange,提问作者Luke

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.01 22:03:13