首先,我想掛鉤CreateFile()
并重寫它。然后我想重新編碼我的新CreateFile()
函式的呼叫堆疊。但是當我SymInitialize()
用來初始化一個句柄時,它陷入了一個無限回圈。通過我的除錯,原因是SymInitialize()
呼叫CreateFile()
。那么為什么會SymInitialize()
涉及CreateFile()
呢?如何避免這個回圈?是否有任何替代方法來記錄呼叫堆疊資訊以避免此回圈?
#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();
}
uj5u.com熱心網友回復:
主要問題是對SymInitialize的呼叫,您在其中為 fInvadeProcess 引數傳遞“TRUE”。這導致 SymLoadModuleEx 為每個加載的模塊呼叫。這將導致大量檔案訪問為每個加載的模塊下載/創建/打開 PDB 檔案。這就是你無限回圈的原因。
此示例的“快速”修復方法是將 SymInitialize 呼叫移動到鉤子呼叫之前的 main 中,因為它只需要呼叫一次。這意味著在掛鉤/呼叫 ShowTraceStack 之前加載所有 PDB 模塊。
其他問題是:
- dbghelp API 不是執行緒安全的 - 所以這個例子在多執行緒應用程式中不起作用
- SymFromAddr 也可能出于同樣的原因呼叫 CreateFile 來加載新加載的模塊 PDB 資訊 - 所以你的鉤子不通過檔案名將導致 PDB 資訊不起作用
如果你想讓某人更有用,我會:
- 在掛鉤之前將 SymInitialize 移動到 main (僅呼叫一次)
- 僅在鉤子中呼叫 CaptureStackBackTrace 并將執行緒堆疊資訊排隊等待稍后處理
- 創建一個單獨的執行緒,獲取 CaptureStackBackTrace 堆疊資訊輸出并將其轉換為堆疊跟蹤 - 這將是呼叫 dbghlp API 的唯一執行緒,呼叫 dbghlp API 執行緒安全
- 在您的鉤子中檢測何時從 dbghlp API 使用執行緒呼叫并且不進行堆疊跟蹤并且不修改 CreateFile 引數,因此您不會進入無限回圈
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/489311.html