使用RtlAppendUnicodeStringToString导致内核崩溃的驱动问题求助
Windows驱动中RtlAppendUnicodeStringToString多次拼接导致内核崩溃的解决方法
崩溃原因分析
问题代码里有两个致命错误:
NewBuffer是用RTL_CONSTANT_STRING初始化的,这会生成一个只读的栈上常量字符串,缓冲区根本不可写。RtlAppendUnicodeStringToString需要目标字符串有可写缓冲区,强行写入直接触发内存访问违例。- 手动修改
NewBuffer.MaximumLength但实际缓冲区物理大小未变,拼接时必然缓冲区溢出,破坏内核栈或触发页错误,直接导致崩溃。
替换后的代码能运行但功能不对,是因为直接修改了ImagePathName的缓冲区,既没给路径加引号,也没正确构造CommandLine格式,完全没实现预期需求。
正确实现代码
KeStackAttachProcess(Process, &apcstate); PPEB peb = PsGetProcessPeb(Process); if (peb != NULL) { const UNICODE_STRING prefix = RTL_CONSTANT_STRING(L"\""); const UNICODE_STRING imagePath = peb->ProcessParameters->ImagePathName; const UNICODE_STRING suffix = RTL_CONSTANT_STRING(L"\" --DEBUGMODE"); // 计算总字节数:前缀+路径+后缀,额外留空字符的空间 const USHORT totalLength = prefix.Length + imagePath.Length + suffix.Length; const USHORT totalMaxLength = totalLength + sizeof(WCHAR); // 在目标进程堆上分配可写缓冲区(必须用进程自己的堆,否则进程访问不到) PWSTR buffer = (PWSTR)RtlAllocateHeap(peb->ProcessHeap, HEAP_ZERO_MEMORY, totalMaxLength); if (buffer != NULL) { UNICODE_STRING newCommandLine = {0}; newCommandLine.Buffer = buffer; newCommandLine.MaximumLength = totalMaxLength; newCommandLine.Length = 0; // 依次拼接各部分 RtlAppendUnicodeStringToString(&newCommandLine, &prefix); RtlAppendUnicodeStringToString(&newCommandLine, &imagePath); RtlAppendUnicodeStringToString(&newCommandLine, &suffix); // 释放原CommandLine的缓冲区,避免内存泄漏 if (peb->ProcessParameters->CommandLine.Buffer != NULL) { RtlFreeHeap(peb->ProcessHeap, 0, peb->ProcessParameters->CommandLine.Buffer); } // 更新进程的CommandLine参数 peb->ProcessParameters->CommandLine = newCommandLine; } } KeUnstackDetachProcess(&apcstate);
关键注意事项
- 缓冲区必须在目标进程地址空间:PEB和ProcessParameters属于目标进程,内核栈内存其他进程无法访问,必须调用
RtlAllocateHeap用进程自己的堆分配内存。 - 提前计算总长度:确保分配的缓冲区足够容纳所有内容和末尾空终止符,避免拼接时溢出。
- 释放原缓冲区:替换CommandLine前要释放原来的缓冲区,防止进程堆内存泄漏。
内容的提问来源于stack exchange,提问作者Haru1ca
相关产品推荐
相关产品推荐

