std::unique_ptr<DBGPATCHINFO> EnumPatches(size_t & buffersize, size_t & numPatches) { if(!DbgIsDebugging()) return nullptr; DbgFunctions()->PatchEnum(0, &buffersize); if(buffersize % sizeof(DBGPATCHINFO) != 0) { MessageBox(hwndDlg, LoadWideString(IDS_OUTDATED).c_str(), LoadWideString(IDS_PLUGNAME).c_str(), MB_ICONERROR); return nullptr; } if(buffersize == 0) { MessageBox(hwndDlg, LoadWideString(IDS_EMPTYPATCH).c_str(), LoadWideString(IDS_PLUGNAME).c_str(), MB_ICONERROR); return nullptr; } numPatches = buffersize / sizeof(DBGPATCHINFO); std::unique_ptr<DBGPATCHINFO> patchList(new DBGPATCHINFO[numPatches]); memset(patchList.get(), 0, numPatches * sizeof(DBGPATCHINFO)); DbgFunctions()->PatchEnum(patchList.get(), &buffersize); std::qsort(patchList.get(), numPatches, sizeof(DBGPATCHINFO), [](const void* a, const void* b) { const DBGPATCHINFO* A = (const DBGPATCHINFO*)a; const DBGPATCHINFO* B = (const DBGPATCHINFO*)b; if(A->addr > B->addr) return 1; else if(A->addr < B->addr) return -1; else return 0; }); return patchList; }
void disasmget(unsigned char* buffer, uint addr, DISASM_INSTR* instr) { if(!DbgIsDebugging()) { if(instr) instr->argcount = 0; return; } memset(instr, 0, sizeof(DISASM_INSTR)); Capstone cp; if(!cp.Disassemble(addr, buffer, MAX_DISASM_BUFFER)) { strcpy_s(instr->instruction, "???"); instr->instr_size = 1; instr->type = instr_normal; instr->argcount = 0; return; } const cs_insn* cpInstr = cp.GetInstr(); sprintf_s(instr->instruction, "%s %s", cpInstr->mnemonic, cpInstr->op_str); const cs_x86 & x86 = cpInstr->detail->x86; instr->instr_size = cpInstr->size; if(cp.InGroup(CS_GRP_JUMP) || cp.IsLoop() || cp.InGroup(CS_GRP_RET) || cp.InGroup(CS_GRP_CALL)) instr->type = instr_branch; else if(strstr(cpInstr->op_str, "sp") || strstr(cpInstr->op_str, "bp")) instr->type = instr_stack; else instr->type = instr_normal; instr->argcount = cp.x86().op_count <= 3 ? cp.x86().op_count : 3; for(int i = 0; i < instr->argcount; i++) HandleCapstoneOperand(cp, i, &instr->arg[i]); }
bool FunctionAdd(uint Start, uint End, bool Manual) { // CHECK: Export/Command function if(!DbgIsDebugging()) return false; // Make sure memory is readable if(!MemIsValidReadPtr(Start)) return false; // Fail if boundary exceeds module size const uint moduleBase = ModBaseFromAddr(Start); if(moduleBase != ModBaseFromAddr(End)) return false; // Fail if 'Start' and 'End' are incompatible if(Start > End || FunctionOverlaps(Start, End)) return false; FUNCTIONSINFO function; ModNameFromAddr(Start, function.mod, true); function.start = Start - moduleBase; function.end = End - moduleBase; function.manual = Manual; // Insert to global table EXCLUSIVE_ACQUIRE(LockFunctions); functions.insert(std::make_pair(ModuleRange(ModHashFromAddr(moduleBase), Range(function.start, function.end)), function)); return true; }
bool FunctionGet(uint Address, uint* Start, uint* End) { // CHECK: Exported function if(!DbgIsDebugging()) return false; const uint moduleBase = ModBaseFromAddr(Address); // Lookup by module hash, then function range SHARED_ACQUIRE(LockFunctions); auto found = functions.find(ModuleRange(ModHashFromAddr(moduleBase), Range(Address - moduleBase, Address - moduleBase))); // Was this range found? if(found == functions.end()) return false; if(Start) *Start = found->second.start + moduleBase; if(End) *End = found->second.end + moduleBase; return true; }
static CMDRESULT scriptinternalcmdexec(const char* cmd) { if(scriptisinternalcommand(cmd, "ret")) //script finished { if(!scriptstack.size()) //nothing on the stack { String TranslatedString = GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "Script finished!")); GuiScriptMessage(TranslatedString.c_str()); return STATUS_EXIT; } scriptIp = scriptstack.back(); //set scriptIp to the call address (scriptinternalstep will step over it) scriptstack.pop_back(); //remove last stack entry return STATUS_CONTINUE; } else if(scriptisinternalcommand(cmd, "invalid")) //invalid command for testing return STATUS_ERROR; else if(scriptisinternalcommand(cmd, "pause")) //pause the script return STATUS_PAUSE; else if(scriptisinternalcommand(cmd, "nop")) //do nothing return STATUS_CONTINUE; auto res = cmddirectexec(cmd); while(DbgIsDebugging() && dbgisrunning() && !bAbort) //while not locked (NOTE: possible deadlock) { Sleep(1); GuiProcessEvents(); //workaround for scripts being executed on the GUI thread } return res ? STATUS_CONTINUE : STATUS_ERROR; }
static CMDRESULT scriptinternalcmdexec(const char* cmd) { if(scriptisinternalcommand(cmd, "ret")) //script finished { if(!scriptstack.size()) //nothing on the stack { GuiScriptMessage("Script finished!"); return STATUS_EXIT; } scriptIp = scriptstack.back(); //set scriptIp to the call address (scriptinternalstep will step over it) scriptstack.pop_back(); //remove last stack entry return STATUS_CONTINUE; } else if(scriptisinternalcommand(cmd, "invalid")) //invalid command for testing return STATUS_ERROR; else if(scriptisinternalcommand(cmd, "pause")) //pause the script return STATUS_PAUSE; else if(scriptisinternalcommand(cmd, "nop")) //do nothing return STATUS_CONTINUE; char command[deflen] = ""; strcpy_s(command, StringUtils::Trim(cmd).c_str()); COMMAND* found = cmdfindmain(dbggetcommandlist(), command); if(!found) //invalid command return STATUS_ERROR; if(arraycontains(found->name, "var")) //var { cmddirectexec(dbggetcommandlist(), command); return STATUS_CONTINUE; } CMDRESULT res = cmddirectexec(dbggetcommandlist(), command); while(DbgIsDebugging() && dbgisrunning()) //while not locked (NOTE: possible deadlock) Sleep(10); return res; }
// Get the start/end of a loop at a certain depth and address bool LoopGet(int Depth, uint Address, uint* Start, uint* End) { // CHECK: Exported function if(!DbgIsDebugging()) return false; // Get the virtual address module const uint moduleBase = ModBaseFromAddr(Address); // Virtual address to relative address Address -= moduleBase; SHARED_ACQUIRE(LockLoops); // Search with this address range auto found = loops.find(DepthModuleRange(Depth, ModuleRange(ModHashFromAddr(moduleBase), Range(Address, Address)))); if(found == loops.end()) return false; // Return the loop start if(Start) *Start = found->second.start + moduleBase; // Also the loop end if(End) *End = found->second.end + moduleBase; return true; }
bool CommentDelete(uint Address) { // CHECK: Command/Sub function if(!DbgIsDebugging()) return false; EXCLUSIVE_ACQUIRE(LockComments); return (comments.erase(ModHashFromAddr(Address)) > 0); }
bool LabelDelete(uint Address) { // CHECK: Export function if(!DbgIsDebugging()) return false; EXCLUSIVE_ACQUIRE(LockLabels); return (labels.erase(ModHashFromAddr(Address)) > 0); }
bool FunctionDelete(uint Address) { // CHECK: Exported function if(!DbgIsDebugging()) return false; const uint moduleBase = ModBaseFromAddr(Address); EXCLUSIVE_ACQUIRE(LockFunctions); return (functions.erase(ModuleRange(ModHashFromAddr(moduleBase), Range(Address - moduleBase, Address - moduleBase))) > 0); }
void disasmget(uint addr, DISASM_INSTR* instr) { if(!DbgIsDebugging()) { if(instr) instr->argcount = 0; return; } unsigned char buffer[MAX_DISASM_BUFFER] = ""; DbgMemRead(addr, buffer, sizeof(buffer)); disasmget(buffer, addr, instr); }
void scriptrun(int destline) { if(DbgIsDebugging() && dbgisrunning()) { GuiScriptError(0, "Debugger must be paused to run a script!"); return; } if(bIsRunning) //already running return; bIsRunning = true; CloseHandle(CreateThread(0, 0, scriptRunThread, (void*)(uint)destline, 0, 0)); }
void scriptrun(int destline) { if(DbgIsDebugging() && dbgisrunning()) { GuiScriptError(0, GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "Debugger must be paused to run a script!"))); return; } if(bIsRunning) //already running return; bIsRunning = true; CloseHandle(CreateThread(0, 0, scriptRunSync, (void*)(duint)destline, 0, 0)); }
//check if a loop overlaps a range, inside is not overlapping bool LoopOverlaps(int Depth, uint Start, uint End, int* FinalDepth) { // CHECK: Export function if(!DbgIsDebugging()) return false; // Determine module addresses and lookup keys const uint moduleBase = ModBaseFromAddr(Start); const uint key = ModHashFromAddr(moduleBase); uint curStart = Start - moduleBase; uint curEnd = End - moduleBase; SHARED_ACQUIRE(LockLoops); // Check if the new loop fits in the old loop for(auto & itr : loops) { // Only look in the current module if(itr.first.second.first != key) continue; // Loop must be at this recursive depth if(itr.second.depth != Depth) continue; if(itr.second.start < curStart && itr.second.end > curEnd) return LoopOverlaps(Depth + 1, curStart, curEnd, FinalDepth); } // Did the user request t the loop depth? if(FinalDepth) *FinalDepth = Depth; // Check for loop overlaps for(auto & itr : loops) { // Only look in the current module if(itr.first.second.first != key) continue; // Loop must be at this recursive depth if(itr.second.depth != Depth) continue; if(itr.second.start <= curEnd && itr.second.end >= curStart) return true; } return false; }
bool FunctionOverlaps(uint Start, uint End) { // CHECK: Exported function if(!DbgIsDebugging()) return false; // A function can't end before it begins if(Start > End) return false; const uint moduleBase = ModBaseFromAddr(Start); SHARED_ACQUIRE(LockFunctions); return (functions.count(ModuleRange(ModHashFromAddr(moduleBase), Range(Start - moduleBase, End - moduleBase))) > 0); }
bool LoopAdd(uint Start, uint End, bool Manual) { // CHECK: Export function if(!DbgIsDebugging()) return false; // Loop must begin before it ends if(Start > End) return false; // Memory addresses must be valid if(!MemIsValidReadPtr(Start) || !MemIsValidReadPtr(End)) return false; // Check if loop boundaries are in the same module range const uint moduleBase = ModBaseFromAddr(Start); if(moduleBase != ModBaseFromAddr(End)) return false; // Loops cannot overlap other loops int finalDepth = 0; if(LoopOverlaps(0, Start, End, &finalDepth)) return false; // Fill out loop information structure LOOPSINFO loopInfo; loopInfo.start = Start - moduleBase; loopInfo.end = End - moduleBase; loopInfo.depth = finalDepth; loopInfo.manual = Manual; ModNameFromAddr(Start, loopInfo.mod, true); // Link this to a parent loop if one does exist if(finalDepth) LoopGet(finalDepth - 1, Start, &loopInfo.parent, 0); else loopInfo.parent = 0; EXCLUSIVE_ACQUIRE(LockLoops); // Insert into list loops.insert(std::make_pair(DepthModuleRange(finalDepth, ModuleRange(ModHashFromAddr(moduleBase), Range(loopInfo.start, loopInfo.end))), loopInfo)); return true; }
void FunctionDelRange(uint Start, uint End) { // CHECK: Exported function if(!DbgIsDebugging()) return; // Should all functions be deleted? // 0x00000000 - 0xFFFFFFFF if(Start == 0 && End == ~0) { FunctionClear(); } else { // The start and end address must be in the same module uint moduleBase = ModBaseFromAddr(Start); if(moduleBase != ModBaseFromAddr(End)) return; // Convert these to a relative offset Start -= moduleBase; End -= moduleBase; EXCLUSIVE_ACQUIRE(LockFunctions); for(auto itr = functions.begin(); itr != functions.end();) { const auto & currentFunction = itr->second; // Ignore manually set entries if(currentFunction.manual) { ++itr; continue; } // [Start, End] if(currentFunction.end >= Start && currentFunction.start <= End) itr = functions.erase(itr); else ++itr; } } }
void CPUDisassembly::mousePressEvent(QMouseEvent* event) { if(event->buttons() == Qt::MiddleButton) //copy address to clipboard { if(!DbgIsDebugging()) return; MessageBeep(MB_OK); copyAddress(); } else { Disassembly::mousePressEvent(event); if(mHighlightingMode) //disable highlighting mode after clicked { mHighlightingMode = false; reloadData(); } } }
void CommentDelRange(uint Start, uint End) { // CHECK: Export function if(!DbgIsDebugging()) return; // Are all comments going to be deleted? // 0x00000000 - 0xFFFFFFFF if(Start == 0 && End == ~0) { CommentClear(); } else { // Make sure 'Start' and 'End' reference the same module uint moduleBase = ModBaseFromAddr(Start); if(moduleBase != ModBaseFromAddr(End)) return; // Virtual -> relative offset Start -= moduleBase; End -= moduleBase; EXCLUSIVE_ACQUIRE(LockComments); for(auto itr = comments.begin(); itr != comments.end();) { // Ignore manually set entries if(itr->second.manual) { itr++; continue; } // [Start, End) if(itr->second.addr >= Start && itr->second.addr < End) itr = comments.erase(itr); else itr++; } } }
bool LabelGet(uint Address, char* Text) { // CHECK: Export function if(!DbgIsDebugging()) return false; SHARED_ACQUIRE(LockLabels); // Was the label at this address exist? auto found = labels.find(ModHashFromAddr(Address)); if(found == labels.end()) return false; // Copy to user buffer if(Text) strcpy_s(Text, MAX_LABEL_SIZE, found->second.text); return true; }
bool CommentGet(uint Address, char* Text) { // CHECK: Exported/Command function if(!DbgIsDebugging()) return false; SHARED_ACQUIRE(LockComments); // Get an existing comment and copy the string buffer auto found = comments.find(ModHashFromAddr(Address)); // Was it found? if(found == comments.end()) return false; if(found->second.manual) //autocomment strcpy_s(Text, MAX_COMMENT_SIZE, found->second.text); else sprintf_s(Text, MAX_COMMENT_SIZE, "\1%s", found->second.text); return true; }
extern "C" DLL_EXPORT bool _dbg_getregdump(REGDUMP* regdump) { if(!DbgIsDebugging()) { memset(regdump, 0, sizeof(REGDUMP)); return true; } TITAN_ENGINE_CONTEXT_t titcontext; if(!GetFullContextDataEx(hActiveThread, &titcontext)) return false; TranslateTitanContextToRegContext(&titcontext, ®dump->regcontext); duint cflags = regdump->regcontext.eflags; regdump->flags.c = valflagfromstring(cflags, "cf"); regdump->flags.p = valflagfromstring(cflags, "pf"); regdump->flags.a = valflagfromstring(cflags, "af"); regdump->flags.z = valflagfromstring(cflags, "zf"); regdump->flags.s = valflagfromstring(cflags, "sf"); regdump->flags.t = valflagfromstring(cflags, "tf"); regdump->flags.i = valflagfromstring(cflags, "if"); regdump->flags.d = valflagfromstring(cflags, "df"); regdump->flags.o = valflagfromstring(cflags, "of"); x87FPURegister_t x87FPURegisters[8]; Getx87FPURegisters(x87FPURegisters, &titcontext); TranslateTitanFpuRegisters(x87FPURegisters, regdump->x87FPURegisters); GetMMXRegisters(regdump->mmx, &titcontext); GetMxCsrFields(& (regdump->MxCsrFields), regdump->regcontext.MxCsr); Getx87ControlWordFields(& (regdump->x87ControlWordFields), regdump->regcontext.x87fpu.ControlWord); Getx87StatusWordFields(& (regdump->x87StatusWordFields), regdump->regcontext.x87fpu.StatusWord); LASTERROR lastError; lastError.code = ThreadGetLastError(ThreadGetId(hActiveThread)); lastError.name = ErrorCodeToName(lastError.code); regdump->lastError = lastError; return true; }
bool LabelSet(uint Address, const char* Text, bool Manual) { // CHECK: Exported/Command function if(!DbgIsDebugging()) return false; // A valid memory address must be supplied if(!MemIsValidReadPtr(Address)) return false; // Make sure the string is supplied, within bounds, and not a special delimiter if(!Text || Text[0] == '\1' || strlen(Text) >= MAX_LABEL_SIZE - 1) return false; // Labels cannot be "address" of actual variables if(strstr(Text, "&")) return false; // Delete the label if no text was supplied if(Text[0] == '\0') return LabelDelete(Address); // Fill out the structure data LABELSINFO labelInfo; labelInfo.manual = Manual; labelInfo.addr = Address - ModBaseFromAddr(Address); strcpy_s(labelInfo.text, Text); ModNameFromAddr(Address, labelInfo.mod, true); EXCLUSIVE_ACQUIRE(LockLabels); // Insert label by key const uint key = ModHashFromAddr(Address); if(!labels.insert(std::make_pair(ModHashFromAddr(key), labelInfo)).second) labels[key] = labelInfo; return true; }
bool LabelFromString(const char* Text, uint* Address) { // CHECK: Future? (Not used) if(!DbgIsDebugging()) return false; SHARED_ACQUIRE(LockLabels); for(auto & itr : labels) { // Check if the actual label name matches if(strcmp(itr.second.text, Text)) continue; if(Address) *Address = itr.second.addr + ModBaseFromName(itr.second.mod); // Set status to indicate if label was ever found return true; } return false; }
void CallStackView::setupContextMenu() { mMenuBuilder = new MenuBuilder(this, [](QMenu*) { return DbgIsDebugging(); }); QIcon icon = DIcon(ArchValue("processor32.png", "processor64.png")); mMenuBuilder->addAction(makeAction(icon, tr("Follow &Address"), SLOT(followAddress()))); QAction* mFollowTo = mMenuBuilder->addAction(makeAction(icon, tr("Follow &To"), SLOT(followTo()))); mFollowTo->setShortcutContext(Qt::WidgetShortcut); mFollowTo->setShortcut(QKeySequence("enter")); connect(this, SIGNAL(enterPressedSignal()), this, SLOT(followTo())); mMenuBuilder->addAction(makeAction(icon, tr("Follow &From"), SLOT(followFrom())), [this](QMenu*) { return !getCellContent(getInitialSelection(), 2).isEmpty(); }); MenuBuilder* mCopyMenu = new MenuBuilder(this); setupCopyMenu(mCopyMenu); // Column count cannot be zero mMenuBuilder->addSeparator(); mMenuBuilder->addMenu(makeMenu(DIcon("copy.png"), tr("&Copy")), mCopyMenu); mMenuBuilder->loadFromConfig(); }
bool CommentSet(uint Address, const char* Text, bool Manual) { // CHECK: Exported/Command function if(!DbgIsDebugging()) return false; // A valid memory address must be supplied if(!MemIsValidReadPtr(Address)) return false; // Make sure the string is supplied, within bounds, and not a special delimiter if(!Text || Text[0] == '\1' || strlen(Text) >= MAX_COMMENT_SIZE - 1) return false; // Delete the comment if no text was supplied if(Text[0] == '\0') return CommentDelete(Address); // Fill out the structure COMMENTSINFO comment; strcpy_s(comment.text, Text); ModNameFromAddr(Address, comment.mod, true); comment.manual = Manual; comment.addr = Address - ModBaseFromAddr(Address); // Key generated from module hash const uint key = ModHashFromAddr(Address); EXCLUSIVE_ACQUIRE(LockComments); // Insert if possible, otherwise replace if(!comments.insert(std::make_pair(key, comment)).second) comments[key] = comment; return true; }
void OpenSigMakeDialog() { // // Ensure a process is being debugged first // if (!DbgIsDebugging()) { _plugin_logprintf("No process is being debugged!\n"); return; } // // Open the dialog // g_SigMakeDialog = CreateDialog(g_LocalDllHandle, MAKEINTRESOURCE(IDD_MAKESIG), GuiGetWindowHandle(), MakeSigDialogProc); if (!g_SigMakeDialog) { _plugin_logprintf("Failed to create signature view window\n"); return; } ShowWindow(g_SigMakeDialog, SW_SHOW); }
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 }
extern "C" DLL_EXPORT bool _dbg_addrinfoget(duint addr, SEGMENTREG segment, ADDRINFO* addrinfo) { if(!DbgIsDebugging()) return false; bool retval = false; if(addrinfo->flags & flagmodule) //get module { if(ModNameFromAddr(addr, addrinfo->module, false)) //get module name retval = true; } if(addrinfo->flags & flaglabel) { if(LabelGet(addr, addrinfo->label)) retval = true; else //no user labels { DWORD64 displacement = 0; char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(char)]; PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer; pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); pSymbol->MaxNameLen = MAX_LABEL_SIZE; if(SafeSymFromAddr(fdProcessInfo->hProcess, (DWORD64)addr, &displacement, pSymbol) && !displacement) { pSymbol->Name[pSymbol->MaxNameLen - 1] = '\0'; if(!bUndecorateSymbolNames || !SafeUnDecorateSymbolName(pSymbol->Name, addrinfo->label, MAX_LABEL_SIZE, UNDNAME_COMPLETE)) strcpy_s(addrinfo->label, pSymbol->Name); retval = true; } if(!retval) //search for CALL <jmp.&user32.MessageBoxA> { BASIC_INSTRUCTION_INFO basicinfo; memset(&basicinfo, 0, sizeof(BASIC_INSTRUCTION_INFO)); if(disasmfast(addr, &basicinfo) && basicinfo.branch && !basicinfo.call && basicinfo.memory.value) //thing is a JMP { uint val = 0; if(MemRead(basicinfo.memory.value, &val, sizeof(val))) { if(SafeSymFromAddr(fdProcessInfo->hProcess, (DWORD64)val, &displacement, pSymbol) && !displacement) { pSymbol->Name[pSymbol->MaxNameLen - 1] = '\0'; if(!bUndecorateSymbolNames || !SafeUnDecorateSymbolName(pSymbol->Name, addrinfo->label, MAX_LABEL_SIZE, UNDNAME_COMPLETE)) sprintf_s(addrinfo->label, "JMP.&%s", pSymbol->Name); retval = true; } } } } if(!retval) //search for module entry { uint entry = ModEntryFromAddr(addr); if(entry && entry == addr) { strcpy_s(addrinfo->label, "EntryPoint"); retval = true; } } } } if(addrinfo->flags & flagbookmark) { addrinfo->isbookmark = BookmarkGet(addr); retval = true; } if(addrinfo->flags & flagfunction) { if(FunctionGet(addr, &addrinfo->function.start, &addrinfo->function.end)) retval = true; } if(addrinfo->flags & flagloop) { if(LoopGet(addrinfo->loop.depth, addr, &addrinfo->loop.start, &addrinfo->loop.end)) retval = true; } if(addrinfo->flags & flagcomment) { *addrinfo->comment = 0; if(CommentGet(addr, addrinfo->comment)) retval = true; else { DWORD dwDisplacement; IMAGEHLP_LINE64 line; line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); if(SafeSymGetLineFromAddr64(fdProcessInfo->hProcess, (DWORD64)addr, &dwDisplacement, &line) && !dwDisplacement) { char filename[deflen] = ""; strcpy_s(filename, line.FileName); int len = (int)strlen(filename); while(filename[len] != '\\' && len != 0) len--; if(len) len++; sprintf_s(addrinfo->comment, "\1%s:%u", filename + len, line.LineNumber); retval = true; } else if(!bOnlyCipAutoComments || addr == GetContextDataEx(hActiveThread, UE_CIP)) //no line number { DISASM_INSTR instr; String temp_string; String comment; ADDRINFO newinfo; char ascii[256 * 2] = ""; char unicode[256 * 2] = ""; memset(&instr, 0, sizeof(DISASM_INSTR)); disasmget(addr, &instr); int len_left = MAX_COMMENT_SIZE; for(int i = 0; i < instr.argcount; i++) { memset(&newinfo, 0, sizeof(ADDRINFO)); newinfo.flags = flaglabel; STRING_TYPE strtype = str_none; if(instr.arg[i].constant == instr.arg[i].value) //avoid: call <module.label> ; addr:label { if(instr.type == instr_branch || !disasmgetstringat(instr.arg[i].constant, &strtype, ascii, unicode, len_left) || strtype == str_none) continue; switch(strtype) { case str_none: break; case str_ascii: temp_string = instr.arg[i].mnemonic; temp_string.append(":\""); temp_string.append(ascii); temp_string.append("\""); break; case str_unicode: temp_string = instr.arg[i].mnemonic; temp_string.append(":L\""); temp_string.append(unicode); temp_string.append("\""); break; } } else if(instr.arg[i].memvalue && (disasmgetstringat(instr.arg[i].memvalue, &strtype, ascii, unicode, len_left) || _dbg_addrinfoget(instr.arg[i].memvalue, instr.arg[i].segment, &newinfo))) { switch(strtype) { case str_none: if(*newinfo.label) { temp_string = "["; temp_string.append(instr.arg[i].mnemonic); temp_string.append("]:"); temp_string.append(newinfo.label); } break; case str_ascii: temp_string = "["; temp_string.append(instr.arg[i].mnemonic); temp_string.append("]:"); temp_string.append(ascii); break; case str_unicode: temp_string = "["; temp_string.append(instr.arg[i].mnemonic); temp_string.append("]:"); temp_string.append(unicode); break; } } else if(instr.arg[i].value && (disasmgetstringat(instr.arg[i].value, &strtype, ascii, unicode, len_left) || _dbg_addrinfoget(instr.arg[i].value, instr.arg[i].segment, &newinfo))) { if(instr.type != instr_normal) //stack/jumps (eg add esp,4 or jmp 401110) cannot directly point to strings strtype = str_none; switch(strtype) { case str_none: if(*newinfo.label) { temp_string = instr.arg[i].mnemonic; temp_string.append(":"); temp_string.append(newinfo.label); } break; case str_ascii: temp_string = instr.arg[i].mnemonic; temp_string.append(":\""); temp_string.append(ascii); temp_string.append("\""); break; case str_unicode: temp_string = instr.arg[i].mnemonic; temp_string.append(":L\""); temp_string.append(unicode); temp_string.append("\""); break; } } else continue; if(!strstr(comment.c_str(), temp_string.c_str())) { if(comment.length()) comment.append(", "); comment.append(temp_string); retval = true; } } comment.resize(MAX_COMMENT_SIZE - 2); String fullComment = "\1"; fullComment += comment; strcpy_s(addrinfo->comment, fullComment.c_str()); } } } return retval; }
void* Bridge::processMessage(GUIMSG type, void* param1, void* param2) { if(dbgStopped) //there can be no more messages if the debugger stopped = BUG __debugbreak(); switch(type) { case GUI_DISASSEMBLE_AT: emit disassembleAt((int_t)param1, (int_t)param2); break; case GUI_SET_DEBUG_STATE: emit dbgStateChanged((DBGSTATE)(int_t)param1); break; case GUI_ADD_MSG_TO_LOG: emit addMsgToLog(QString((const char*)param1)); break; case GUI_CLEAR_LOG: emit clearLog(); break; case GUI_UPDATE_REGISTER_VIEW: emit updateRegisters(); break; case GUI_UPDATE_DISASSEMBLY_VIEW: emit repaintGui(); break; case GUI_UPDATE_BREAKPOINTS_VIEW: emit updateBreakpoints(); break; case GUI_UPDATE_WINDOW_TITLE: emit updateWindowTitle(QString((const char*)param1)); break; case GUI_GET_WINDOW_HANDLE: return winId; case GUI_DUMP_AT: emit dumpAt((int_t)param1); break; case GUI_SCRIPT_ADD: { BridgeResult result; emit scriptAdd((int)param1, (const char**)param2); result.Wait(); } break; case GUI_SCRIPT_CLEAR: emit scriptClear(); break; case GUI_SCRIPT_SETIP: emit scriptSetIp((int)param1); break; case GUI_SCRIPT_ERROR: { BridgeResult result; emit scriptError((int)param1, QString((const char*)param2)); result.Wait(); } break; case GUI_SCRIPT_SETTITLE: emit scriptSetTitle(QString((const char*)param1)); break; case GUI_SCRIPT_SETINFOLINE: emit scriptSetInfoLine((int)param1, QString((const char*)param2)); break; case GUI_SCRIPT_MESSAGE: { BridgeResult result; emit scriptMessage(QString((const char*)param1)); result.Wait(); } break; case GUI_SCRIPT_MSGYN: { BridgeResult result; emit scriptQuestion(QString((const char*)param1)); return (void*)result.Wait(); } break; case GUI_SCRIPT_ENABLEHIGHLIGHTING: emit scriptEnableHighlighting((bool)param1); break; case GUI_SYMBOL_UPDATE_MODULE_LIST: emit updateSymbolList((int)param1, (SYMBOLMODULEINFO*)param2); break; case GUI_SYMBOL_LOG_ADD: emit addMsgToSymbolLog(QString((const char*)param1)); break; case GUI_SYMBOL_LOG_CLEAR: emit clearSymbolLog(); break; case GUI_SYMBOL_SET_PROGRESS: emit setSymbolProgress((int)param1); break; case GUI_REF_ADDCOLUMN: emit referenceAddColumnAt((int)param1, QString((const char*)param2)); break; case GUI_REF_SETROWCOUNT: emit referenceSetRowCount((int_t)param1); break; case GUI_REF_GETROWCOUNT: return (void*)referenceManager->currentReferenceView()->mList->getRowCount(); case GUI_REF_DELETEALLCOLUMNS: GuiReferenceInitialize("References"); break; case GUI_REF_SETCELLCONTENT: { CELLINFO* info = (CELLINFO*)param1; emit referenceSetCellContent(info->row, info->col, QString(info->str)); } break; case GUI_REF_GETCELLCONTENT: return (void*)referenceManager->currentReferenceView()->mList->getCellContent((int)param1, (int)param2).toUtf8().constData(); case GUI_REF_RELOADDATA: emit referenceReloadData(); break; case GUI_REF_SETSINGLESELECTION: emit referenceSetSingleSelection((int)param1, (bool)param2); break; case GUI_REF_SETPROGRESS: emit referenceSetProgress((int)param1); break; case GUI_REF_SETSEARCHSTARTCOL: emit referenceSetSearchStartCol((int)param1); break; case GUI_REF_INITIALIZE: { BridgeResult result; emit referenceInitialize(QString((const char*)param1)); result.Wait(); } break; case GUI_STACK_DUMP_AT: emit stackDumpAt((uint_t)param1, (uint_t)param2); break; case GUI_UPDATE_DUMP_VIEW: emit updateDump(); break; case GUI_UPDATE_THREAD_VIEW: emit updateThreads(); break; case GUI_UPDATE_MEMORY_VIEW: emit updateMemory(); break; case GUI_ADD_RECENT_FILE: emit addRecentFile(QString((const char*)param1)); break; case GUI_SET_LAST_EXCEPTION: emit setLastException((unsigned int)param1); break; case GUI_GET_DISASSEMBLY: { uint_t parVA = (uint_t)param1; char* text = (char*)param2; if(!text || !parVA || !DbgIsDebugging()) return 0; byte_t wBuffer[16]; if(!DbgMemRead(parVA, wBuffer, 16)) return 0; QBeaEngine disasm(-1); Instruction_t instr = disasm.DisassembleAt(wBuffer, 16, 0, 0, parVA); BeaTokenizer::TokenizeInstruction(&instr.tokens, &instr.disasm, -1); QList<RichTextPainter::CustomRichText_t> richText; BeaTokenizer::TokenToRichText(&instr.tokens, &richText, 0); QString finalInstruction = ""; for(int i = 0; i < richText.size(); i++) finalInstruction += richText.at(i).text; strcpy_s(text, GUI_MAX_DISASSEMBLY_SIZE, finalInstruction.toUtf8().constData()); return (void*)1; } break; case GUI_MENU_ADD: { BridgeResult result; emit menuAddMenu((int)param1, QString((const char*)param2)); return (void*)result.Wait(); } break; case GUI_MENU_ADD_ENTRY: { BridgeResult result; emit menuAddMenuEntry((int)param1, QString((const char*)param2)); return (void*)result.Wait(); } break; case GUI_MENU_ADD_SEPARATOR: { BridgeResult result; emit menuAddSeparator((int)param1); result.Wait(); } break; case GUI_MENU_CLEAR: { BridgeResult result; emit menuClearMenu((int)param1); result.Wait(); } break; case GUI_SELECTION_GET: { int hWindow = (int)param1; SELECTIONDATA* selection = (SELECTIONDATA*)param2; if(!DbgIsDebugging()) return (void*)false; BridgeResult result; switch(hWindow) { case GUI_DISASSEMBLY: emit selectionDisasmGet(selection); break; case GUI_DUMP: emit selectionDumpGet(selection); break; case GUI_STACK: emit selectionStackGet(selection); break; default: return (void*)false; } result.Wait(); if(selection->start > selection->end) //swap start and end { int_t temp = selection->end; selection->end = selection->start; selection->start = temp; } return (void*)true; } break; case GUI_SELECTION_SET: { int hWindow = (int)param1; const SELECTIONDATA* selection = (const SELECTIONDATA*)param2; if(!DbgIsDebugging()) return (void*)false; BridgeResult result; switch(hWindow) { case GUI_DISASSEMBLY: emit selectionDisasmSet(selection); break; case GUI_DUMP: emit selectionDumpSet(selection); break; case GUI_STACK: emit selectionStackSet(selection); break; default: return (void*)false; } return (void*)result.Wait(); } break; case GUI_GETLINE_WINDOW: { QString text = ""; BridgeResult result; emit getStrWindow(QString((const char*)param1), &text); if(result.Wait()) { strcpy_s((char*)param2, GUI_MAX_LINE_SIZE, text.toUtf8().constData()); return (void*)true; } return (void*)false; //cancel/escape } break; case GUI_AUTOCOMPLETE_ADDCMD: emit autoCompleteAddCmd(QString((const char*)param1)); break; case GUI_AUTOCOMPLETE_DELCMD: emit autoCompleteDelCmd(QString((const char*)param1)); break; case GUI_AUTOCOMPLETE_CLEARALL: emit autoCompleteClearAll(); break; case GUI_ADD_MSG_TO_STATUSBAR: emit addMsgToStatusBar(QString((const char*)param1)); break; case GUI_UPDATE_SIDEBAR: emit updateSideBar(); break; case GUI_REPAINT_TABLE_VIEW: emit repaintTableView(); break; case GUI_UPDATE_PATCHES: emit updatePatches(); break; case GUI_UPDATE_CALLSTACK: emit updateCallStack(); break; case GUI_SYMBOL_REFRESH_CURRENT: emit symbolRefreshCurrent(); break; case GUI_LOAD_SOURCE_FILE: emitLoadSourceFile(QString((const char*)param1), (int)param2); break; case GUI_MENU_SET_ICON: { int hMenu = (int)param1; const ICONDATA* icon = (const ICONDATA*)param2; BridgeResult result; if(!icon) emit setIconMenu(hMenu, QIcon()); else { QImage img; img.loadFromData((uchar*)icon->data, icon->size); QIcon qIcon(QPixmap::fromImage(img)); emit setIconMenu(hMenu, qIcon); } result.Wait(); } break; case GUI_MENU_SET_ENTRY_ICON: { int hEntry = (int)param1; const ICONDATA* icon = (const ICONDATA*)param2; BridgeResult result; if(!icon) emit setIconMenuEntry(hEntry, QIcon()); else { QImage img; img.loadFromData((uchar*)icon->data, icon->size); QIcon qIcon(QPixmap::fromImage(img)); emit setIconMenuEntry(hEntry, qIcon); } result.Wait(); } break; case GUI_SHOW_CPU: emit showCpu(); break; case GUI_ADD_QWIDGET_TAB: emit addQWidgetTab((QWidget*)param1); break; case GUI_SHOW_QWIDGET_TAB: emit showQWidgetTab((QWidget*)param1); break; case GUI_CLOSE_QWIDGET_TAB: emit closeQWidgetTab((QWidget*)param1); break; case GUI_EXECUTE_ON_GUI_THREAD: GuiAddLogMessage(QString().sprintf("thread id (bridge) %X\n", GetCurrentThreadId()).toUtf8().constData()); emit executeOnGuiThread(param1); break; case GUI_UPDATE_TIME_WASTED_COUNTER: emit updateTimeWastedCounter(); break; } return nullptr; }