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; }
// Get the start/end of a loop at a certain depth and address bool LoopGet(int Depth, duint Address, duint* Start, duint* End) { ASSERT_DEBUGGING("Export call"); // Get the virtual address module const duint 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 and end if(Start) *Start = found->second.start + moduleBase; if(End) *End = found->second.end + moduleBase; return true; }
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; }
// 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 LabelDelete(uint Address) { // CHECK: Export function if(!DbgIsDebugging()) return false; EXCLUSIVE_ACQUIRE(LockLabels); return (labels.erase(ModHashFromAddr(Address)) > 0); }
bool CommentDelete(uint Address) { // CHECK: Command/Sub function if(!DbgIsDebugging()) return false; EXCLUSIVE_ACQUIRE(LockComments); return (comments.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); }
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; }
//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 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 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 PatchDelete(duint Address, bool Restore) { ASSERT_DEBUGGING("Export call"); EXCLUSIVE_ACQUIRE(LockPatches); // Do a list lookup with hash auto found = patches.find(ModHashFromAddr(Address)); if(found == patches.end()) return false; // Restore the original byte at this address if(Restore) MemWrite((found->second.addr + ModBaseFromAddr(Address)), &found->second.oldbyte, sizeof(char)); // Finally remove it from the list patches.erase(found); return true; }
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 PatchGet(duint Address, PATCHINFO* Patch) { ASSERT_DEBUGGING("Export call"); SHARED_ACQUIRE(LockPatches); // Find this specific address in the list auto found = patches.find(ModHashFromAddr(Address)); if(found == patches.end()) return false; // Did the user request an output buffer? if(Patch) { *Patch = found->second; Patch->addr += ModBaseFromAddr(Address); } // Return true because the patch was found 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; }
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; }