My project contains managed part(dotnet
) and native(C++
) part. I want to hook Winapi CreateFiles
in my project by detours and log callstack. Now I have obtained a native callstack by invoking CaptureStackBackTrace and SymFromAddr api in dbghelp
. But I meet some troubles when those functions are used in dotnet
. as shown in the following picture, it can obtain correct callstack of native code(22, 21, 1, 0) but not work for managed code(20-2). may I have some methods to obtain both managed(dotnet) and un-managed(C++) callstack correctly? or maybe you have the best method to get callstack, could you help me?
dotnet produce:
public class CreateFileOrFolder
{
public void writeToFile(string pathString) {
System.IO.File.Create(pathString);
}
static void Main()
{
System.Console.WriteLine("Press any key to start.\n");
System.Console.ReadKey();
string fileName = "c.txt";
string pathString = System.IO.Path.Combine(@"D:\JunFiles\testDotNetProceduce", fileName);
// Verify the path that you have constructed.
Console.WriteLine("Path to my file: {0}\n", pathString);
CreateFileOrFolder creater = new CreateFileOrFolder();
if (!System.IO.File.Exists(pathString)) {
creater.writeToFile(pathString);
}
else
{
System.IO.File.Delete(pathString);
Console.WriteLine("File \"{0}\" already exists. but now it is deleted\n", fileName);
creater.writeToFile(pathString);
}
}
}
detours hook function:
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
) {
static BOOL state = FALSE;
printStack();
symbolSolve(process);
printf("HOOK sucess!\n");
std::cout << current_working_directory() << endl;
wchar_t newFileName[] = L".\\newFile.txt";
return oldCreateFile(
newFileName, // 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);
}
get callstack:
#define STACK_INFO_LEN 200
static HANDLE process;
unsigned int i;
void* stack[100];
unsigned short frames;
SYMBOL_INFO* symbol;
std::queue<std::pair<void*, unsigned short>> myQueue;
PDWORD hashValue = (PDWORD)malloc(sizeof(DWORD));
void printStack(void)
{
frames = CaptureStackBackTrace(0, 100, stack, hashValue);
void* stackTmp = stack;
}
DWORD WINAPI symbolSolve(LPVOID p) {
int myqueue_size = myQueue.size();
char* szBriefInfo = NULL;
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];
if (szBriefInfo == NULL) {
strcpy_s(szStackInfo, "stack traceback:\n");
}
else {
strcpy_s(szStackInfo, szBriefInfo);
}
symbol = (SYMBOL_INFO*)calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1);
symbol->MaxNameLen = 255;
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
IMAGEHLP_LINE line;
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
DWORD displacementLine = 0;
std::string strs = "";
strs += std::to_string(*hashValue);
for (i = 0; i < frames; i++) {
SymFromAddr(process, (DWORD64)(stack[i]), 0, symbol);
BOOL ret = SymGetLineFromAddr64(process, (DWORD64)(stack[i]), &displacementLine, &line);
_snprintf_s(szFrameInfo, sizeof(szFrameInfo), "%i: %s - 0x%0X ", frames - i - 1, symbol->Name, symbol->Address);
strcat_s(szStackInfo, szFrameInfo);
if (ret) {
_snprintf_s(szFrameInfo, sizeof(szFrameInfo), " | %s at %o \n", line.FileName, line.LineNumber);
strcat_s(szStackInfo, szFrameInfo);
}
else {
_snprintf_s(szFrameInfo, sizeof(szFrameInfo), "|error %d \n", GetLastError());
strcat_s(szStackInfo, szFrameInfo);
}
}
printf("%s \n", szStackInfo);
free(symbol);
return 0;
}
result: