Detours Hook CreateFileW获取调用栈报126/184错及重复输出问题
问题描述
通过Detours库Hook Win32 API CreateFileW,调用CaptureStackBackTrace捕获调用栈,使用SymFromAddr解析栈地址对应符号时,接口返回错误码126、184,符号解析失败。代码中仅显式调用一次ShowTraceStack函数,运行时却输出多份栈追踪信息。
附原实现代码:
#include <windows.h> #include <stdio.h> #include "detours.h" #include <fstream> #include <Shlwapi.h> #pragma comment(lib, "shlwapi.lib") //Windows API PathFileExists #include <io.h> #pragma comment(lib, "detours.lib") #include <DbgHelp.h> //SymInitialize #pragma comment(lib,"dbghelp.lib") #define STACK_INFO_LEN 20000 struct stackInfo { PDWORD hashValue; // hash value to identify same stack char* szBriefInfo; // callstack info }; stackInfo ShowTraceStack(char* szBriefInfo) { static const int MAX_STACK_FRAMES = 200; void* pStack[MAX_STACK_FRAMES]; static char szStackInfo[STACK_INFO_LEN * MAX_STACK_FRAMES]; static char szFrameInfo[STACK_INFO_LEN]; HANDLE process = GetCurrentProcess(); // The handle used must be unique to avoid sharing a session with another component, SymInitialize(process, NULL, TRUE); PDWORD hashValue = (PDWORD)malloc(sizeof(DWORD)); // allow memory for hashVavlue, it will be rewrited in function CaptureStackBackTrace WORD frames = CaptureStackBackTrace(0, MAX_STACK_FRAMES, pStack, hashValue); //printf("hash value is: %ud \n", &hashValue); if (szBriefInfo == NULL) { strcpy_s(szStackInfo, "stack traceback:\n"); } else { strcpy_s(szStackInfo, szBriefInfo); } for (WORD i = 0; i < frames; ++i) { DWORD64 address = (DWORD64)(pStack[i]); DWORD64 displacementSym = 0; char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)]; PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer; pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); pSymbol->MaxNameLen = MAX_SYM_NAME; DWORD displacementLine = 0; IMAGEHLP_LINE64 line; line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); if (SymFromAddr(process, address, &displacementSym, pSymbol) && SymGetLineFromAddr64(process, address, &displacementLine, &line)) { _snprintf_s(szFrameInfo, sizeof(szFrameInfo), "\t%s() at %s:%d(0x%x)\n", pSymbol->Name, line.FileName, line.LineNumber, pSymbol->Address); } else { _snprintf_s(szFrameInfo, sizeof(szFrameInfo), "\terror: %d\n", GetLastError()); } strcat_s(szStackInfo, szFrameInfo); } stackInfo traceStackInfo; traceStackInfo.hashValue = hashValue; traceStackInfo.szBriefInfo = szStackInfo; printf("%s", szStackInfo); return traceStackInfo; } HANDLE(*oldCreateFile)(LPCWSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE) = CreateFileW; HANDLE WINAPI newCreateFile( _In_ LPCWSTR lpFileName, _In_ DWORD dwDesiredAccess, _In_ DWORD dwShareMode, _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes, _In_ DWORD dwCreationDisposition, _In_ DWORD dwFlagsAndAttributes, _In_opt_ HANDLE hTemplateFile ) { ShowTraceStack((char*)"trace information."); return oldCreateFile( L".\\newFiles.txt", // L".\\NewFile.txt", // Filename //lpFileName, dwDesiredAccess, // Desired access dwShareMode, // Share mode lpSecurityAttributes, // Security attributes dwCreationDisposition, // Creates a new file, only if it doesn't already exist dwFlagsAndAttributes, // Flags and attributes NULL); } void hook() { DetourRestoreAfterWith(); DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourAttach(&(PVOID&)oldCreateFile, newCreateFile); DetourTransactionCommit(); } void unhook() { DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourDetach(&(PVOID&)oldCreateFile, newCreateFile); DetourTransactionCommit(); } void myProcess() { HANDLE hFile = CreateFile(TEXT(".\\CreateFileDemo.txt"), GENERIC_WRITE | GENERIC_READ, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { OutputDebugString(TEXT("CreateFile fail!\r\n")); } // write to file const int BUFSIZE = 4096; char chBuffer[BUFSIZE]; memcpy(chBuffer, "Test", 4); DWORD dwWritenSize = 0; BOOL bRet = WriteFile(hFile, chBuffer, 4, &dwWritenSize, NULL); ShowTraceStack((char*)"trace information."); if (bRet) { OutputDebugString(TEXT("WriteFile success!\r\n")); } } int main(){ hook(); myProcess(); unhook(); }
附运行结果截图:
故障原因
- 符号解析错误原因
- 错误码126对应
ERROR_MOD_NOT_FOUND:SymInitialize每次调用ShowTraceStack都重复执行,破坏了DbgHelp的符号会话,且未提前配置符号加载选项、未正确加载对应模块的符号文件,导致找不到模块对应符号。 - 错误码184对应
ERROR_INVALID_ADDRESS:Hook递归触发时栈帧混乱,传入SymFromAddr的地址包含无效地址、未加载模块的地址,无法解析。
- 错误码126对应
- 多份栈输出原因:Hook逻辑存在递归调用问题。
ShowTraceStack内部的printf输出、DbgHelp加载符号文件、C运行时IO操作,以及Hook函数中硬编码打开newFiles.txt的逻辑,都会隐式调用CreateFileW,再次触发Hook进入ShowTraceStack,导致递归打印多份栈信息,甚至栈溢出。
修复方案
- 调整DbgHelp初始化逻辑:仅在程序启动、Hook安装前初始化一次DbgHelp,提前配置符号加载选项,不要在每次抓栈时重复初始化。
- 增加线程级递归防护:进入Hook处理逻辑前先打标记,标记生效期间所有
CreateFileW调用直接走原函数,不触发栈打印逻辑,避免递归。 - 修正Hook逻辑:不要在Hook函数中硬编码修改打开的文件路径,避免无意义的文件触发额外调用;修正
CaptureStackBackTrace的哈希参数用法,不需要手动malloc内存,直接使用局部变量存储哈希值即可,避免内存泄漏。
关键修正代码:
// 全局添加线程局部递归防护标记 thread_local bool g_inHookProc = false; int main(){ // 初始化DbgHelp,仅执行一次 SymSetOptions(SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_DEFERRED_LOADS); SymInitialize(GetCurrentProcess(), NULL, TRUE); // 如需解析系统API符号,可添加符号路径配置 // SymSetSearchPath(GetCurrentProcess(), L"SRV*C:\\Symbols*https://msdl.microsoft.com/download/symbols;"); hook(); myProcess(); unhook(); // 程序退出前清理DbgHelp SymCleanup(GetCurrentProcess()); return 0; } // 修改Hook函数,增加递归防护 HANDLE WINAPI newCreateFile( _In_ LPCWSTR lpFileName, _In_ DWORD dwDesiredAccess, _In_ DWORD dwShareMode, _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes, _In_ DWORD dwCreationDisposition, _In_ DWORD dwFlagsAndAttributes, _In_opt_ HANDLE hTemplateFile ) { // 处于Hook处理流程中时,直接调用原函数 if (g_inHookProc) { return oldCreateFile(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); } g_inHookProc = true; ShowTraceStack((char*)"CreateFileW call trace:"); // 不要硬编码修改文件名,使用原调用的参数 HANDLE hRet = oldCreateFile(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); g_inHookProc = false; return hRet; } // 修改ShowTraceStack,删除内部重复的SymInitialize调用,修正hash参数用法 stackInfo ShowTraceStack(char* szBriefInfo) { static const int MAX_STACK_FRAMES = 200; void* pStack[MAX_STACK_FRAMES]; static char szStackInfo[STACK_INFO_LEN * MAX_STACK_FRAMES]; static char szFrameInfo[STACK_INFO_LEN]; HANDLE process = GetCurrentProcess(); DWORD hashValue = 0; // 直接用局部变量存哈希,不需要malloc WORD frames = CaptureStackBackTrace(0, MAX_STACK_FRAMES, pStack, &hashValue); // 剩余逻辑保持不变,删除原函数中SymInitialize(process, NULL, TRUE);这行 // ... }
内容的提问来源于stack exchange,提问作者GuangJun Liu
相关产品推荐
相关产品推荐

