// 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; }
/** \brief Enumerates all variables. \param [in,out] List A pointer to place the variables in. If null, \p cbsize will be filled to the number of bytes required. \param [in,out] Size This function retrieves the number of bytes required to store all variables. Can be null if \p entries is not null. \return true if it succeeds, false if it fails. */ bool varenum(VAR* List, size_t* Size) { // A list or size must be requested if(!List && !Size) return false; SHARED_ACQUIRE(LockVariables); if(Size) { // Size requested, so return it *Size = variables.size() * sizeof(VAR); if(!List) return true; } // Fill out all list entries for(auto & itr : variables) { *List = itr.second; List++; } return true; }
bool PatchEnum(PATCHINFO* List, size_t* Size) { ASSERT_DEBUGGING("Export call"); ASSERT_FALSE(!List && !Size); SHARED_ACQUIRE(LockPatches); // Did the user request the size? if(Size) { *Size = patches.size() * sizeof(PATCHINFO); if(!List) return true; } // Copy each vector entry to a C-style array for(auto & itr : patches) { *List = itr.second; List->addr += ModBaseFromName(itr.second.mod);; List++; } 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; }
/** \brief Gets a variable value. \param Name The name of the variable. \param [out] Value This function can get the variable value. If this value is null, it is ignored. \param [out] Size This function can get the variable size. If this value is null, it is ignored. \param [out] Type This function can get the variable type. If this value is null, it is ignored. \return true if the variable was found and the optional values were retrieved successfully, false otherwise. */ bool varget(const char* Name, VAR_VALUE* Value, int* Size, VAR_TYPE* Type) { SHARED_ACQUIRE(LockVariables); String name_; if(*Name != '$') name_ = "$"; name_ += Name; auto found = variables.find(name_); if(found == variables.end()) //not found return false; if(found->second.alias.length()) { // Release the lock (potential deadlock here) SHARED_RELEASE(); return varget(found->second.alias.c_str(), Value, Size, Type); } if(Type) *Type = found->second.type; if(Size) *Size = found->second.value.size; if(Value) *Value = found->second.value; 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; }
DWORD ThreadGetLastError(DWORD ThreadId) { SHARED_ACQUIRE(LockThreads); if(threadList.find(ThreadId) != threadList.end()) return ThreadGetLastErrorTEB(threadList[ThreadId].ThreadLocalBase); ASSERT_ALWAYS("Trying to get last error of a thread that doesn't exist!"); return 0; }
HANDLE ThreadGetHandle(DWORD ThreadId) { SHARED_ACQUIRE(LockThreads); if(threadList.find(ThreadId) != threadList.end()) return threadList[ThreadId].Handle; ASSERT_ALWAYS("Trying to get handle of a thread that doesn't exist!"); return nullptr; }
uint ModEntryFromAddr(uint Address) { SHARED_ACQUIRE(LockModules); auto module = ModInfoFromAddr(Address); if(!module) return 0; return module->entry; }
uint ModSizeFromAddr(uint Address) { SHARED_ACQUIRE(LockModules); auto module = ModInfoFromAddr(Address); if(!module) return 0; return module->size; }
SCRIPT_EXPORT bool Script::Module::SectionFromAddr(duint addr, int number, ModuleSectionInfo* section) { SHARED_ACQUIRE(LockModules); MODINFO* modInfo = ModInfoFromAddr(addr); if(!section || !modInfo || number < 0 || number >= int(modInfo->sections.size())) return false; const MODSECTIONINFO & secInfo = modInfo->sections.at(number); section->addr = secInfo.addr; section->size = secInfo.size; strcpy_s(section->name, secInfo.name); return true; }
int ModPathFromAddr(duint Address, char* Path, int Size) { SHARED_ACQUIRE(LockModules); auto module = ModInfoFromAddr(Address); if(!module) return 0; strcpy_s(Path, Size, module->path); return (int)strlen(Path); }
bool ModSectionsFromAddr(uint Address, std::vector<MODSECTIONINFO>* Sections) { SHARED_ACQUIRE(LockModules); auto module = ModInfoFromAddr(Address); if(!module) return false; // Copy vector <-> vector *Sections = module->sections; 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; }
int ThreadResumeAll() { // ResumeThread does not modify any internal variables SHARED_ACQUIRE(LockThreads); int count = 0; for(auto & entry : threadList) { if(ResumeThread(entry.second.Handle) != -1) count++; } return count; }
uint ModHashFromAddr(uint Address) { // // Returns a unique hash from a virtual address // SHARED_ACQUIRE(LockModules); auto module = ModInfoFromAddr(Address); if(!module) return Address; return module->hash + (Address - module->base); }
SCRIPT_EXPORT bool Script::Module::InfoFromAddr(duint addr, Script::Module::ModuleInfo* info) { SHARED_ACQUIRE(LockModules); MODINFO* modInfo = ModInfoFromAddr(addr); if(!info || !modInfo) return false; info->base = modInfo->base; info->size = modInfo->size; info->entry = modInfo->entry; info->sectionCount = int(modInfo->sections.size()); strcpy_s(info->name, modInfo->name); strcat_s(info->name, modInfo->extension); strcpy_s(info->path, modInfo->path); return true; }
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); }
SCRIPT_EXPORT bool Script::Module::SectionListFromAddr(duint addr, ListInfo* listInfo) { SHARED_ACQUIRE(LockModules); MODINFO* modInfo = ModInfoFromAddr(addr); if (!modInfo) return false; std::vector<ModuleSectionInfo> scriptSectionList(modInfo->sections.size()); for (const auto & section : modInfo->sections) { ModuleSectionInfo scriptSection; scriptSection.addr = section.addr; scriptSection.size = section.size; strcpy_s(scriptSection.name, section.name); } return List<ModuleSectionInfo>::CopyData(listInfo, scriptSectionList); }
DWORD ThreadGetId(HANDLE Thread) { SHARED_ACQUIRE(LockThreads); // Search for the ID in the local list for(auto & entry : threadList) { if(entry.second.Handle == Thread) return entry.first; } // Wasn't found, check with Windows typedef DWORD (WINAPI * GETTHREADID)(HANDLE hThread); static GETTHREADID _GetThreadId = (GETTHREADID)GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "GetThreadId"); return _GetThreadId ? _GetThreadId(Thread) : 0; }
/** \brief Gets a variable type. \param Name The name of the variable. Cannot be null. \param [out] Type This function can retrieve the variable type. If null it is ignored. \param [out] ValueType This function can retrieve the variable value type. If null it is ignored. \return true if getting the type was successful, false otherwise. */ bool vargettype(const char* Name, VAR_TYPE* Type, VAR_VALUE_TYPE* ValueType) { SHARED_ACQUIRE(LockVariables); String name_; if(*Name != '$') name_ = "$"; name_ += Name; auto found = variables.find(name_); if(found == variables.end()) //not found return false; if(found->second.alias.length()) return vargettype(found->second.alias.c_str(), Type, ValueType); if(ValueType) *ValueType = found->second.value.type; if(Type) *Type = found->second.type; return true; }
uint ModBaseFromName(const char* Module) { if(!Module || strlen(Module) >= MAX_MODULE_SIZE) return 0; SHARED_ACQUIRE(LockModules); for(auto itr = modinfo.begin(); itr != modinfo.end(); itr++) { char currentModule[MAX_MODULE_SIZE]; strcpy_s(currentModule, itr->second.name); strcat_s(currentModule, itr->second.extension); // Test with and without extension if(!_stricmp(currentModule, Module) || !_stricmp(itr->second.name, Module)) return itr->second.base; } return 0; }
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 ModNameFromAddr(uint Address, char* Name, bool Extension) { if(!Name) return false; SHARED_ACQUIRE(LockModules); // Get a pointer to module information auto module = ModInfoFromAddr(Address); if(!module) return false; // Copy initial module name strcpy_s(Name, MAX_MODULE_SIZE, module->name); if(Extension) strcat_s(Name, MAX_MODULE_SIZE, module->extension); 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; }
void ThreadGetList(THREADLIST* List) { ASSERT_NONNULL(List); SHARED_ACQUIRE(LockThreads); // // This function converts a C++ std::unordered_map to a C-style THREADLIST[]. // Also assume BridgeAlloc zeros the returned buffer. // List->count = (int)threadList.size(); List->list = nullptr; if(List->count <= 0) return; // Allocate C-style array List->list = (THREADALLINFO*)BridgeAlloc(List->count * sizeof(THREADALLINFO)); // Fill out the list data int index = 0; for(auto & itr : threadList) { HANDLE threadHandle = itr.second.Handle; // Get the debugger's active thread index if(threadHandle == hActiveThread) List->CurrentThread = index; memcpy(&List->list[index].BasicInfo, &itr.second, sizeof(THREADINFO)); List->list[index].ThreadCip = GetContextDataEx(threadHandle, UE_CIP); List->list[index].SuspendCount = ThreadGetSuspendCount(threadHandle); List->list[index].Priority = ThreadGetPriority(threadHandle); List->list[index].WaitReason = ThreadGetWaitReason(threadHandle); List->list[index].LastError = ThreadGetLastErrorTEB(itr.second.ThreadLocalBase); index++; } }
extern "C" DLL_EXPORT bool _dbg_memmap(MEMMAP* memmap) { SHARED_ACQUIRE(LockMemoryPages); int pagecount = (int)memoryPages.size(); memset(memmap, 0, sizeof(MEMMAP)); memmap->count = pagecount; if(!pagecount) return true; // Allocate memory that is already zeroed memmap->page = (MEMPAGE*)BridgeAlloc(sizeof(MEMPAGE) * pagecount); // Copy all elements over int i = 0; for(auto & itr : memoryPages) memcpy(&memmap->page[i++], &itr.second, sizeof(MEMPAGE)); // Done 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 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; }
int ThreadGetCount() { SHARED_ACQUIRE(LockThreads); return (int)threadList.size(); }