内核态下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
相关产品推荐
相关产品推荐

