void stackgetcallstack(duint csp, std::vector<CALLSTACKENTRY> & callstackVector, bool cache) { if(cache) { SHARED_ACQUIRE(LockCallstackCache); auto found = CallstackCache.find(csp); if(found != CallstackCache.end()) { callstackVector = found->second; return; } callstackVector.clear(); return; } // Gather context data CONTEXT context; memset(&context, 0, sizeof(CONTEXT)); context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; if(SuspendThread(hActiveThread) == -1) return; if(!GetThreadContext(hActiveThread, &context)) return; if(ResumeThread(hActiveThread) == -1) return; // Set up all frame data STACKFRAME64 frame; ZeroMemory(&frame, sizeof(STACKFRAME64)); #ifdef _M_IX86 DWORD machineType = IMAGE_FILE_MACHINE_I386; frame.AddrPC.Offset = context.Eip; frame.AddrPC.Mode = AddrModeFlat; frame.AddrFrame.Offset = context.Ebp; frame.AddrFrame.Mode = AddrModeFlat; frame.AddrStack.Offset = csp; frame.AddrStack.Mode = AddrModeFlat; #elif _M_X64 DWORD machineType = IMAGE_FILE_MACHINE_AMD64; frame.AddrPC.Offset = context.Rip; frame.AddrPC.Mode = AddrModeFlat; frame.AddrFrame.Offset = context.Rsp; frame.AddrFrame.Mode = AddrModeFlat; frame.AddrStack.Offset = csp; frame.AddrStack.Mode = AddrModeFlat; #endif const int MaxWalks = 50; // Container for each callstack entry (50 pre-allocated entries) callstackVector.clear(); callstackVector.reserve(MaxWalks); for(auto i = 0; i < MaxWalks; i++) { if(!StackWalk64( machineType, fdProcessInfo->hProcess, hActiveThread, &frame, &context, StackReadProcessMemoryProc64, SymFunctionTableAccess64, StackGetModuleBaseProc64, StackTranslateAddressProc64)) { // Maybe it failed, maybe we have finished walking the stack break; } if(frame.AddrPC.Offset != 0) { // Valid frame CALLSTACKENTRY entry; memset(&entry, 0, sizeof(CALLSTACKENTRY)); StackEntryFromFrame(&entry, (duint)frame.AddrFrame.Offset + sizeof(duint), (duint)frame.AddrPC.Offset, (duint)frame.AddrReturn.Offset); callstackVector.push_back(entry); } else { // Base reached break; } } EXCLUSIVE_ACQUIRE(LockCallstackCache); if(CallstackCache.size() > MAX_CALLSTACK_CACHE) CallstackCache.clear(); CallstackCache[csp] = callstackVector; }
void stackgetcallstack(uint csp, CALLSTACK* callstack) { #if 1 callstack->total = 0; if(!DbgIsDebugging() || csp % sizeof(uint)) //alignment problem return; if(!MemIsValidReadPtr(csp)) return; std::vector<CALLSTACKENTRY> callstackVector; uint stacksize = 0; uint stackbase = MemFindBaseAddr(csp, &stacksize, false); if(!stackbase) //super-fail (invalid stack address) return; //walk up the stack uint i = csp; while(i != stackbase + stacksize) { uint data = 0; MemRead(i, &data, sizeof(uint)); if(MemIsValidReadPtr(data) && MemIsCodePage(data, false)) //the stack value is a pointer to an executable page { uint size = 0; uint base = MemFindBaseAddr(data, &size); uint readStart = data - 16 * 4; if(readStart < base) readStart = base; unsigned char disasmData[256]; MemRead(readStart, disasmData, sizeof(disasmData)); uint prev = disasmback(disasmData, 0, sizeof(disasmData), data - readStart, 1); uint previousInstr = readStart + prev; BASIC_INSTRUCTION_INFO basicinfo; bool valid = disasmfast(disasmData + prev, previousInstr, &basicinfo); if(valid && basicinfo.call) //call { CALLSTACKENTRY curEntry; memset(&curEntry, 0, sizeof(CALLSTACKENTRY)); StackEntryFromFrame(&curEntry, i, basicinfo.addr, data); callstackVector.push_back(curEntry); } } i += sizeof(uint); } callstack->total = (int)callstackVector.size(); if(callstack->total) { callstack->entries = (CALLSTACKENTRY*)BridgeAlloc(callstack->total * sizeof(CALLSTACKENTRY)); for(int i = 0; i < callstack->total; i++) { //CALLSTACKENTRY curEntry; //memcpy(&curEntry, &callstackVector.at(i), sizeof(CALLSTACKENTRY)); //dprintf(fhex":" fhex ":" fhex ":%s\n", curEntry.addr, curEntry.to, curEntry.from, curEntry.comment); memcpy(&callstack->entries[i], &callstackVector.at(i), sizeof(CALLSTACKENTRY)); } } #else // Gather context data CONTEXT context; memset(&context, 0, sizeof(CONTEXT)); context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; if(SuspendThread(hActiveThread) == -1) return; if(!GetThreadContext(hActiveThread, &context)) return; if(ResumeThread(hActiveThread) == -1) return; // Set up all frame data STACKFRAME64 frame; ZeroMemory(&frame, sizeof(STACKFRAME64)); #ifdef _M_IX86 DWORD machineType = IMAGE_FILE_MACHINE_I386; frame.AddrPC.Offset = context.Eip; frame.AddrPC.Mode = AddrModeFlat; frame.AddrFrame.Offset = context.Ebp; frame.AddrFrame.Mode = AddrModeFlat; frame.AddrStack.Offset = csp; frame.AddrStack.Mode = AddrModeFlat; #elif _M_X64 DWORD machineType = IMAGE_FILE_MACHINE_AMD64; frame.AddrPC.Offset = context.Rip; frame.AddrPC.Mode = AddrModeFlat; frame.AddrFrame.Offset = context.Rsp; frame.AddrFrame.Mode = AddrModeFlat; frame.AddrStack.Offset = csp; frame.AddrStack.Mode = AddrModeFlat; #endif // Container for each callstack entry std::vector<CALLSTACKENTRY> callstackVector; while(true) { if(!StackWalk64( machineType, fdProcessInfo->hProcess, hActiveThread, &frame, &context, StackReadProcessMemoryProc64, SymFunctionTableAccess64, StackGetModuleBaseProc64, StackTranslateAddressProc64)) { // Maybe it failed, maybe we have finished walking the stack break; } if(frame.AddrPC.Offset != 0) { // Valid frame CALLSTACKENTRY entry; memset(&entry, 0, sizeof(CALLSTACKENTRY)); StackEntryFromFrame(&entry, (uint)frame.AddrFrame.Offset, (uint)frame.AddrReturn.Offset, (uint)frame.AddrPC.Offset); callstackVector.push_back(entry); } else { // Base reached break; } } // Convert to a C data structure callstack->total = (int)callstackVector.size(); if(callstack->total > 0) { callstack->entries = (CALLSTACKENTRY*)BridgeAlloc(callstack->total * sizeof(CALLSTACKENTRY)); // Copy data directly from the vector memcpy(callstack->entries, callstackVector.data(), callstack->total * sizeof(CALLSTACKENTRY)); } #endif }