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 ArgumentAdd(duint Start, duint End, bool Manual, duint InstructionCount) { // Make sure memory is readable if(!MemIsValidReadPtr(Start)) return false; // Fail if boundary exceeds module size auto moduleBase = ModBaseFromAddr(Start); if(moduleBase != ModBaseFromAddr(End)) return false; // Fail if 'Start' and 'End' are incompatible if(Start > End || ArgumentOverlaps(Start, End)) return false; ARGUMENTSINFO argument; if(!ModNameFromAddr(Start, argument.mod, true)) *argument.mod = '\0'; argument.start = Start - moduleBase; argument.end = End - moduleBase; argument.manual = Manual; argument.instructioncount = InstructionCount; return arguments.Add(argument); }
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; }
bool disasmispossiblestring(uint addr) { unsigned char data[11]; memset(data, 0, sizeof(data)); if(!MemRead((void*)addr, data, sizeof(data) - 3, 0)) return false; uint test = 0; memcpy(&test, data, sizeof(uint)); if(MemIsValidReadPtr(test)) //imports/pointers return false; if(isasciistring(data, sizeof(data)) or isunicodestring(data, _countof(data))) return true; return false; }
bool PatchSet(duint Address, unsigned char OldByte, unsigned char NewByte) { ASSERT_DEBUGGING("Export call"); // Address must be valid if(!MemIsValidReadPtr(Address)) return false; // Don't patch anything if the new and old values are the same if(OldByte == NewByte) return true; PATCHINFO newPatch; newPatch.addr = Address - ModBaseFromAddr(Address); newPatch.oldbyte = OldByte; newPatch.newbyte = NewByte; ModNameFromAddr(Address, newPatch.mod, true); // Generate a key for this address const duint key = ModHashFromAddr(Address); EXCLUSIVE_ACQUIRE(LockPatches); // Find any patch with this specific address auto found = patches.find(key); if(found != patches.end()) { if(found->second.oldbyte == NewByte) { // The patch was undone here patches.erase(found); return true; } // Keep the original byte from the previous patch newPatch.oldbyte = found->second.oldbyte; found->second = newPatch; } else { // The entry was never found, insert it patches.insert(std::make_pair(key, newPatch)); } 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 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; }
bool stackcommentget(duint addr, STACK_COMMENT* comment) { SHARED_ACQUIRE(LockSehCache); const auto found = SehCache.find(addr); if(found != SehCache.end()) { *comment = found->second; return true; } SHARED_RELEASE(); duint data = 0; memset(comment, 0, sizeof(STACK_COMMENT)); MemRead(addr, &data, sizeof(duint)); if(!MemIsValidReadPtr(data)) //the stack value is no pointer return false; duint size = 0; duint base = MemFindBaseAddr(data, &size); duint readStart = data - 16 * 4; if(readStart < base) readStart = base; unsigned char disasmData[256]; MemRead(readStart, disasmData, sizeof(disasmData)); duint prev = disasmback(disasmData, 0, sizeof(disasmData), data - readStart, 1); duint previousInstr = readStart + prev; BASIC_INSTRUCTION_INFO basicinfo; bool valid = disasmfast(disasmData + prev, previousInstr, &basicinfo); if(valid && basicinfo.call) //call { char label[MAX_LABEL_SIZE] = ""; ADDRINFO addrinfo; addrinfo.flags = flaglabel; if(_dbg_addrinfoget(data, SEG_DEFAULT, &addrinfo)) strcpy_s(label, addrinfo.label); char module[MAX_MODULE_SIZE] = ""; ModNameFromAddr(data, module, false); char returnToAddr[MAX_COMMENT_SIZE] = ""; if(*module) sprintf(returnToAddr, "%s.", module); if(!*label) sprintf_s(label, "%p", data); strcat(returnToAddr, label); data = basicinfo.addr; if(data) { *label = 0; addrinfo.flags = flaglabel; if(_dbg_addrinfoget(data, SEG_DEFAULT, &addrinfo)) strcpy_s(label, addrinfo.label); *module = 0; ModNameFromAddr(data, module, false); char returnFromAddr[MAX_COMMENT_SIZE] = ""; if(*module) sprintf_s(returnFromAddr, "%s.", module); if(!*label) sprintf_s(label, "%p", data); strcat_s(returnFromAddr, label); sprintf_s(comment->comment, GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "return to %s from %s")), returnToAddr, returnFromAddr); } else sprintf_s(comment->comment, GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "return to %s from ???")), returnToAddr); strcpy_s(comment->color, "!rtnclr"); // Special token for return address color; return true; } //string char string[MAX_STRING_SIZE] = ""; if(DbgGetStringAt(data, string)) { strncpy_s(comment->comment, string, _TRUNCATE); return true; } //label char label[MAX_LABEL_SIZE] = ""; ADDRINFO addrinfo; addrinfo.flags = flaglabel; if(_dbg_addrinfoget(data, SEG_DEFAULT, &addrinfo)) strcpy_s(label, addrinfo.label); char module[MAX_MODULE_SIZE] = ""; ModNameFromAddr(data, module, false); if(*module) //module { if(*label) //+label sprintf_s(comment->comment, "%s.%s", module, label); else //module only sprintf_s(comment->comment, "%s.%p", module, data); return true; } else if(*label) //label only { sprintf_s(comment->comment, "<%s>", label); return true; } return false; }
void FunctionPass::AnalysisWorker(duint Start, duint End, std::vector<FunctionDef>* Blocks) { // // Step 1: Use any defined functions in the PE function table // FindFunctionWorkerPrepass(Start, End, Blocks); // // Step 2: for each block that contains a CALL flag, // add it to a local function start array // // NOTE: *Some* indirect calls are included auto blockItr = std::next(m_MainBlocks.begin(), Start); for(duint i = Start; i < End; i++, ++blockItr) { if(blockItr->GetFlag(BASIC_BLOCK_FLAG_CALL)) { duint destination = blockItr->Target; // Was it a pointer? if(blockItr->GetFlag(BASIC_BLOCK_FLAG_INDIRPTR)) { // Read it from memory if(!MemRead(destination, &destination, sizeof(duint))) continue; // Validity check if(!MemIsValidReadPtr(destination)) continue; dprintf(QT_TRANSLATE_NOOP("DBG", "Indirect pointer: 0x%p 0x%p\n"), blockItr->Target, destination); } // Destination must be within analysis limits if(!ValidateAddress(destination)) continue; Blocks->push_back({ destination, 0, 0, 0, 0 }); } } // // Step 3: Sort and remove duplicates // std::sort(Blocks->begin(), Blocks->end()); Blocks->erase(std::unique(Blocks->begin(), Blocks->end()), Blocks->end()); // // Step 4: Find function ends // FindFunctionWorker(Blocks); // // Step 5: Find all orphaned blocks and repeat analysis process // // Starting from the first global block, scan until an "untouched" block is found blockItr = std::next(m_MainBlocks.begin(), Start); // Cached final block BasicBlock* finalBlock = &m_MainBlocks.back(); duint virtEnd = 0; for(duint i = Start; i < End; i++, ++blockItr) { if(blockItr->VirtualStart < virtEnd) continue; // Skip padding if(blockItr->GetFlag(BASIC_BLOCK_FLAG_PAD)) continue; // Is the block untouched? if(blockItr->GetFlag(BASIC_BLOCK_FLAG_FUNCTION)) continue; // Try to define a function FunctionDef def { blockItr->VirtualStart, 0, 0, 0, 0 }; if(ResolveFunctionEnd(&def, finalBlock)) { Blocks->push_back(def); virtEnd = def.VirtualEnd; } } }
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 }
bool stackcommentget(uint addr, STACK_COMMENT* comment) { uint data = 0; memset(comment, 0, sizeof(STACK_COMMENT)); MemRead(addr, &data, sizeof(uint)); if(!MemIsValidReadPtr(data)) //the stack value is no pointer return false; 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 { char label[MAX_LABEL_SIZE] = ""; ADDRINFO addrinfo; addrinfo.flags = flaglabel; if(_dbg_addrinfoget(data, SEG_DEFAULT, &addrinfo)) strcpy_s(label, addrinfo.label); char module[MAX_MODULE_SIZE] = ""; ModNameFromAddr(data, module, false); char returnToAddr[MAX_COMMENT_SIZE] = ""; if(*module) sprintf(returnToAddr, "%s.", module); if(!*label) sprintf(label, fhex, data); strcat(returnToAddr, label); data = basicinfo.addr; if(data) { *label = 0; addrinfo.flags = flaglabel; if(_dbg_addrinfoget(data, SEG_DEFAULT, &addrinfo)) strcpy_s(label, addrinfo.label); *module = 0; ModNameFromAddr(data, module, false); char returnFromAddr[MAX_COMMENT_SIZE] = ""; if(*module) sprintf(returnFromAddr, "%s.", module); if(!*label) sprintf(label, fhex, data); strcat_s(returnFromAddr, label); sprintf_s(comment->comment, "return to %s from %s", returnToAddr, returnFromAddr); } else sprintf_s(comment->comment, "return to %s from ???", returnToAddr); strcpy_s(comment->color, "#ff0000"); return true; } //string STRING_TYPE strtype; char string[512] = ""; if(disasmgetstringat(data, &strtype, string, string, 500)) { if(strtype == str_ascii) sprintf(comment->comment, "\"%s\"", string); else //unicode sprintf(comment->comment, "L\"%s\"", string); return true; } //label char label[MAX_LABEL_SIZE] = ""; ADDRINFO addrinfo; addrinfo.flags = flaglabel; if(_dbg_addrinfoget(data, SEG_DEFAULT, &addrinfo)) strcpy_s(label, addrinfo.label); char module[MAX_MODULE_SIZE] = ""; ModNameFromAddr(data, module, false); if(*module) //module { if(*label) //+label sprintf(comment->comment, "%s.%s", module, label); else //module only sprintf(comment->comment, "%s." fhex, module, data); return true; } else if(*label) //label only { sprintf(comment->comment, "<%s>", label); return true; } return false; }
bool disasmgetstringat(uint addr, STRING_TYPE* type, char* ascii, char* unicode, int maxlen) { if(type) *type = str_none; if(!disasmispossiblestring(addr)) return false; Memory<unsigned char*> data((maxlen + 1) * 2, "disasmgetstringat:data"); if(!MemRead(addr, data(), (maxlen + 1) * 2)) return false; uint test = 0; memcpy(&test, data(), sizeof(uint)); if(MemIsValidReadPtr(test)) return false; if(isasciistring(data(), maxlen)) { if(type) *type = str_ascii; int len = (int)strlen((const char*)data()); for(int i = 0, j = 0; i < len; i++) { switch(data()[i]) { case '\t': j += sprintf(ascii + j, "\\t"); break; case '\f': j += sprintf(ascii + j, "\\f"); break; case '\v': j += sprintf(ascii + j, "\\v"); break; case '\n': j += sprintf(ascii + j, "\\n"); break; case '\r': j += sprintf(ascii + j, "\\r"); break; case '\\': j += sprintf(ascii + j, "\\\\"); break; case '\"': j += sprintf(ascii + j, "\\\""); break; default: j += sprintf(ascii + j, "%c", data()[i]); break; } } return true; } else if(isunicodestring(data(), maxlen)) { if(type) *type = str_unicode; int len = (int)wcslen((const wchar_t*)data()); for(int i = 0, j = 0; i < len * 2; i += 2) { switch(data()[i]) { case '\t': j += sprintf(unicode + j, "\\t"); break; case '\f': j += sprintf(unicode + j, "\\f"); break; case '\v': j += sprintf(unicode + j, "\\v"); break; case '\n': j += sprintf(unicode + j, "\\n"); break; case '\r': j += sprintf(unicode + j, "\\r"); break; case '\\': j += sprintf(unicode + j, "\\\\"); break; case '\"': j += sprintf(unicode + j, "\\\""); break; default: j += sprintf(unicode + j, "%c", data()[i]); break; } } return true; } return false; }
extern "C" DLL_EXPORT bool _dbg_memisvalidreadptr(duint addr) { return MemIsValidReadPtr(addr); }
extern "C" DLL_EXPORT int _dbg_getbplist(BPXTYPE type, BPMAP* bpmap) { if(!bpmap) return 0; std::vector<BREAKPOINT> list; int bpcount = BpGetList(&list); if(bpcount == 0) { bpmap->count = 0; return 0; } int retcount = 0; std::vector<BRIDGEBP> bridgeList; BRIDGEBP curBp; unsigned short slot = 0; for(int i = 0; i < bpcount; i++) { memset(&curBp, 0, sizeof(BRIDGEBP)); switch(type) { case bp_none: //all types break; case bp_normal: //normal if(list[i].type != BPNORMAL) continue; break; case bp_hardware: //hardware if(list[i].type != BPHARDWARE) continue; break; case bp_memory: //memory if(list[i].type != BPMEMORY) continue; break; default: return 0; } switch(list[i].type) { case BPNORMAL: curBp.type = bp_normal; break; case BPHARDWARE: curBp.type = bp_hardware; break; case BPMEMORY: curBp.type = bp_memory; break; } switch(((DWORD)list[i].titantype) >> 8) { case UE_DR0: slot = 0; break; case UE_DR1: slot = 1; break; case UE_DR2: slot = 2; break; case UE_DR3: slot = 3; break; } curBp.addr = list[i].addr; curBp.enabled = list[i].enabled; //TODO: fix this if(MemIsValidReadPtr(curBp.addr)) curBp.active = true; strcpy_s(curBp.mod, list[i].mod); strcpy_s(curBp.name, list[i].name); curBp.singleshoot = list[i].singleshoot; curBp.slot = slot; if(curBp.active) { bridgeList.push_back(curBp); retcount++; } } if(!retcount) { bpmap->count = retcount; return retcount; } bpmap->count = retcount; bpmap->bp = (BRIDGEBP*)BridgeAlloc(sizeof(BRIDGEBP) * retcount); for(int i = 0; i < retcount; i++) memcpy(&bpmap->bp[i], &bridgeList.at(i), sizeof(BRIDGEBP)); return retcount; }