为什么syminitialize()indecoke createfile()?

发布于 2025-02-05 07:35:25 字数 4876 浏览 2 评论 0原文

首先,我想挂接createfile()并重写它。然后,我想回顾一下我的新createfile()函数的呼叫堆。但是,当我使用syminitialize()初始化句柄时,它会落入无尽的循环中。通过我的调试,原因是syminitialize() indokes createfile()。那么,为什么syminitialize()涉及createfile()?如何避免此循环?是否有其他方法可以记录Callstack信息以避免此循环?

#include <windows.h>
#include <stdio.h>
#include "detours.h"
#include <fstream>
#include <io.h>   

#pragma comment(lib, "detours.lib")
#include <DbgHelp.h>                    //SymInitialize
#pragma comment(lib,"dbghelp.lib")
#define STACK_INFO_LEN  200

struct stackInfo {
    PDWORD hashValue; // hash value to identify same stack
    char* szBriefInfo; // callstack info
};

stackInfo ShowTraceStack(char* szBriefInfo)
{
    static const int MAX_STACK_FRAMES = 12;
    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;
    return traceStackInfo;
    //printf("%s", szStackInfo); 
}

HANDLE (*__stdcall 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.\n");
    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);
    if (bRet) {
        OutputDebugString(TEXT("WriteFile success!\r\n"));
    }
}

int main(){
    hook();
    myProcess();
    unhook();
}

Firstly, I want to hook CreateFile() and rewrite it. Then I want to recode the callstack of my new CreateFile() function. But when I use SymInitialize() to Initialize a handle, it falls into an endless loop. Through my debug, the reason is SymInitialize() invokes CreateFile(). So why does SymInitialize() involve CreateFile()? How to avoid this loop? Is there any alternative method to record callstack information to avoid this loop?

#include <windows.h>
#include <stdio.h>
#include "detours.h"
#include <fstream>
#include <io.h>   

#pragma comment(lib, "detours.lib")
#include <DbgHelp.h>                    //SymInitialize
#pragma comment(lib,"dbghelp.lib")
#define STACK_INFO_LEN  200

struct stackInfo {
    PDWORD hashValue; // hash value to identify same stack
    char* szBriefInfo; // callstack info
};

stackInfo ShowTraceStack(char* szBriefInfo)
{
    static const int MAX_STACK_FRAMES = 12;
    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;
    return traceStackInfo;
    //printf("%s", szStackInfo); 
}

HANDLE (*__stdcall 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.\n");
    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);
    if (bRet) {
        OutputDebugString(TEXT("WriteFile success!\r\n"));
    }
}

int main(){
    hook();
    myProcess();
    unhook();
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

静若繁花 2025-02-12 07:35:25

主要问题是呼叫您通过“ true”来获取finvadeprocess参数。这导致它为每个加载模块调用SymloadModuleex。这将导致大量的文件访问下载 /创建 /打开每个加载模块的PDB文件。这就是您无限循环的原因。

该示例的“快速修复程序”是在挂钩调用之前将呼叫的呼叫移动到主机上,因为只需要一次调用一次。这意味着在挂钩 /调用ShowTraceStack之前,将加载所有PDB模块。

另一个问题是:

  • DBGHELP API不是线程安全的 - 因此,此示例在多线程应用程序中也无法使用
  • SymfromAddr在SymfromAddr中也可以呼叫CreateFile,同样的原因是加载新加载的模块PDB信息 - 因此您的挂钩不通过该挂钩不通过该文件名将导致PDB信息

如果您想使某人更有用,我会的:

  • 将象征性移动到挂钩之前移动到main(仅一次称为一次),
  • 仅在挂钩中调用capturestackbacktrace并在稍后将要处理的线程堆栈信息排队时间
  • 创建一个单独的线程接收capturestackbacktrace堆栈信息输出并将其转换为堆栈跟踪 - 这是唯一一个呼叫dbghlp api的线程,呼叫dbghlp api thread
  • 在挂钩检测到从dbghlp api api使用线程时,请检测到挂钩中的安全 性。并且不要执行堆栈跟踪,也不要修改CreateFile参数,以免进入无限循环

The main problem is the call to SymInitialize where you pass through "TRUE" for fInvadeProcess parameter. This is causing it to SymLoadModuleEx to be called for each loaded module. This will cause a lot of file access to download / create / open PDB files for each loaded module. This is the reason for your infinite loop.

The "quick" fix for this sample is to move the call to SymInitialize into your main before the hook call as it only needs to be called once. This means all the PDB modules are loaded before the hooking / call to ShowTraceStack.

The other problems are:

  • dbghelp API is NOT thread safe - so this example will not work in a multi-threaded application
  • SymFromAddr may call CreateFile as well for the same reason to load a newly loaded module PDB information - so your hook not passing through the filename will cause PDB information to not work

If you are trying to make someone more useful I would:

  • Move SymInitialize to main before the hooking (called only once)
  • Only call CaptureStackBackTrace in the hook and queue the thread stack information to be processed at a later time
  • Create a separate thread the takes the CaptureStackBackTrace stack information output and convert it to a stack trace - this would is the only thread calling the dbghlp API making calls to dbghlp API thread safe
  • In your hook detect when being called from the dbghlp API usage thread and don't do the stack trace and don't modify the CreateFile parameters so you don't get into a infinite loop
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文