void CommentCacheSave(JSON Root) { EXCLUSIVE_ACQUIRE(LockComments); const JSON jsonComments = json_array(); const JSON jsonAutoComments = json_array(); // Build the JSON array for(auto & itr : comments) { JSON currentComment = json_object(); json_object_set_new(currentComment, "module", json_string(itr.second.mod)); json_object_set_new(currentComment, "address", json_hex(itr.second.addr)); json_object_set_new(currentComment, "text", json_string(itr.second.text)); if(itr.second.manual) json_array_append_new(jsonComments, currentComment); else json_array_append_new(jsonAutoComments, currentComment); } // Save to the JSON root if(json_array_size(jsonComments)) json_object_set(Root, "comments", jsonComments); if(json_array_size(jsonAutoComments)) json_object_set(Root, "autocomments", jsonAutoComments); json_decref(jsonComments); json_decref(jsonAutoComments); }
void LabelCacheSave(JSON Root) { EXCLUSIVE_ACQUIRE(LockLabels); // Create the sub-root structures in memory const JSON jsonLabels = json_array(); const JSON jsonAutoLabels = json_array(); // Iterator each label for(auto & itr : labels) { JSON jsonLabel = json_object(); json_object_set_new(jsonLabel, "module", json_string(itr.second.mod)); json_object_set_new(jsonLabel, "address", json_hex(itr.second.addr)); json_object_set_new(jsonLabel, "text", json_string(itr.second.text)); // Was the label manually added? if(itr.second.manual) json_array_append_new(jsonLabels, jsonLabel); else json_array_append_new(jsonAutoLabels, jsonLabel); } // Apply the object to the global root if(json_array_size(jsonLabels)) json_object_set(Root, "labels", jsonLabels); if(json_array_size(jsonAutoLabels)) json_object_set(Root, "autolabels", jsonAutoLabels); json_decref(jsonLabels); json_decref(jsonAutoLabels); }
/** \brief Deletes a variable. \param Name The name of the variable to delete. Cannot be null. \param DelSystem true to allow deleting system variables. \return true if the variable was deleted successfully, false otherwise. */ bool vardel(const char* Name, bool DelSystem) { EXCLUSIVE_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) EXCLUSIVE_RELEASE(); return vardel(found->second.alias.c_str(), DelSystem); } if(!DelSystem && found->second.type != VAR_USER) return false; found = variables.begin(); while(found != variables.end()) { auto del = found; found++; if(found->second.name == String(Name)) variables.erase(del); } return true; }
/** \brief Creates a new variable. \param Name The name of the variable. You can specify alias names by separating the names by '\1'. Cannot be null. \param Value The new variable value. \param Type The variable type. \return true if the new variables was created and set successfully, false otherwise. */ bool varnew(const char* Name, duint Value, VAR_TYPE Type) { if(!Name) return false; EXCLUSIVE_ACQUIRE(LockVariables); std::vector<String> names = StringUtils::Split(Name, '\1'); String firstName; for(int i = 0; i < (int)names.size(); i++) { String name_; Name = names.at(i).c_str(); if(*Name != '$') name_ = "$"; name_ += Name; if(!i) firstName = Name; if(variables.find(name_) != variables.end()) //found return false; VAR var; var.name = name_; if(i) var.alias = firstName; var.type = Type; var.value.size = sizeof(duint); var.value.type = VAR_UINT; var.value.u.value = Value; variables.insert(std::make_pair(name_, var)); } 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; }
void FunctionCacheSave(JSON Root) { EXCLUSIVE_ACQUIRE(LockFunctions); // Allocate JSON object array const JSON jsonFunctions = json_array(); const JSON jsonAutoFunctions = json_array(); for(auto & i : functions) { JSON currentFunction = json_object(); json_object_set_new(currentFunction, "module", json_string(i.second.mod)); json_object_set_new(currentFunction, "start", json_hex(i.second.start)); json_object_set_new(currentFunction, "end", json_hex(i.second.end)); if(i.second.manual) json_array_append_new(jsonFunctions, currentFunction); else json_array_append_new(jsonAutoFunctions, currentFunction); } if(json_array_size(jsonFunctions)) json_object_set(Root, "functions", jsonFunctions); if(json_array_size(jsonAutoFunctions)) json_object_set(Root, "autofunctions", jsonAutoFunctions); // Decrease reference count to avoid leaking memory json_decref(jsonFunctions); json_decref(jsonAutoFunctions); }
void ThreadCreate(CREATE_THREAD_DEBUG_INFO* CreateThread) { THREADINFO curInfo; memset(&curInfo, 0, sizeof(THREADINFO)); curInfo.ThreadNumber = ThreadGetCount(); curInfo.Handle = INVALID_HANDLE_VALUE; curInfo.ThreadId = ((DEBUG_EVENT*)GetDebugData())->dwThreadId; curInfo.ThreadStartAddress = (duint)CreateThread->lpStartAddress; curInfo.ThreadLocalBase = (duint)CreateThread->lpThreadLocalBase; // Duplicate the debug thread handle -> thread handle DuplicateHandle(GetCurrentProcess(), CreateThread->hThread, GetCurrentProcess(), &curInfo.Handle, 0, FALSE, DUPLICATE_SAME_ACCESS); // The first thread (#0) is always the main program thread if(curInfo.ThreadNumber <= 0) strcpy_s(curInfo.threadName, "Main Thread"); // Modify global thread list EXCLUSIVE_ACQUIRE(LockThreads); threadList.insert(std::make_pair(curInfo.ThreadId, curInfo)); EXCLUSIVE_RELEASE(); // Notify GUI GuiUpdateThreadView(); }
bool CommentDelete(uint Address) { // CHECK: Command/Sub function if(!DbgIsDebugging()) return false; EXCLUSIVE_ACQUIRE(LockComments); return (comments.erase(ModHashFromAddr(Address)) > 0); }
void ModClear() { EXCLUSIVE_ACQUIRE(LockModules); modinfo.clear(); EXCLUSIVE_RELEASE(); // Tell the symbol updater SymUpdateModuleList(); }
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 PatchDelRange(duint Start, duint End, bool Restore) { ASSERT_DEBUGGING("Export call"); // Are all bookmarks going to be deleted? // 0x00000000 - 0xFFFFFFFF if(Start == 0 && End == ~0) { EXCLUSIVE_ACQUIRE(LockPatches); patches.clear(); } else { // Make sure 'Start' and 'End' reference the same module duint moduleBase = ModBaseFromAddr(Start); if(moduleBase != ModBaseFromAddr(End)) return; // VA to RVA in module Start -= moduleBase; End -= moduleBase; EXCLUSIVE_ACQUIRE(LockPatches); for(auto itr = patches.begin(); itr != patches.end();) { const auto & currentPatch = itr->second; // [Start, End) if(currentPatch.addr >= Start && currentPatch.addr < End) { // Restore the original byte if necessary if(Restore) MemWrite((currentPatch.addr + moduleBase), ¤tPatch.oldbyte, sizeof(char)); itr = patches.erase(itr); } else ++itr; } } }
void LabelDelRange(uint Start, uint End) { // CHECK: Export function if(!DbgIsDebugging()) return; // Are all comments going to be deleted? // 0x00000000 - 0xFFFFFFFF if(Start == 0 && End == ~0) { EXCLUSIVE_ACQUIRE(LockLabels); labels.clear(); } else { // Make sure 'Start' and 'End' reference the same module uint moduleBase = ModBaseFromAddr(Start); if(moduleBase != ModBaseFromAddr(End)) return; EXCLUSIVE_ACQUIRE(LockLabels); for(auto itr = labels.begin(); itr != labels.end();) { // Ignore manually set entries if(itr->second.manual) { itr++; continue; } // [Start, End) if(itr->second.addr >= Start && itr->second.addr < End) itr = labels.erase(itr); else itr++; } } }
void LabelCacheLoad(JSON Root) { EXCLUSIVE_ACQUIRE(LockLabels); // Inline lambda to parse each JSON entry auto AddLabels = [](const JSON Object, bool Manual) { size_t i; JSON value; json_array_foreach(Object, i, value) { LABELSINFO labelInfo; memset(&labelInfo, 0, sizeof(LABELSINFO)); // Module const char* mod = json_string_value(json_object_get(value, "module")); if(mod && strlen(mod) < MAX_MODULE_SIZE) strcpy_s(labelInfo.mod, mod); else labelInfo.mod[0] = '\0'; // Address/Manual labelInfo.addr = (uint)json_hex_value(json_object_get(value, "address")); labelInfo.manual = Manual; // Text string const char* text = json_string_value(json_object_get(value, "text")); if(text) strcpy_s(labelInfo.text, text); else { // Skip empty strings continue; } // Go through the string replacing '&' with spaces for(char* ptr = labelInfo.text; ptr[0] != '\0'; ptr++) { if(ptr[0] == '&') ptr[0] = ' '; } // Finally insert the data const uint key = ModHashFromName(labelInfo.mod) + labelInfo.addr; labels.insert(std::make_pair(key, labelInfo)); } };
void ThreadClear() { EXCLUSIVE_ACQUIRE(LockThreads); // Close all handles first for(auto & itr : threadList) CloseHandle(itr.second.Handle); // Empty the array threadList.clear(); // Update the GUI's list EXCLUSIVE_RELEASE(); GuiUpdateThreadView(); }
/** \brief Clears all variables. */ void varfree() { EXCLUSIVE_ACQUIRE(LockVariables); // Each variable must be deleted manually; strings especially // because there are sub-allocations VAR_VALUE emptyValue; memset(&emptyValue, 0, sizeof(VAR_VALUE)); for(auto & itr : variables) varsetvalue(&itr.second, &emptyValue); // Now clear all vector elements variables.clear(); }
void ThreadExit(DWORD ThreadId) { EXCLUSIVE_ACQUIRE(LockThreads); // Erase element using native functions auto itr = threadList.find(ThreadId); if(itr != threadList.end()) { CloseHandle(itr->second.Handle); threadList.erase(itr); } EXCLUSIVE_RELEASE(); GuiUpdateThreadView(); }
bool ThreadSetName(DWORD ThreadId, const char* Name) { EXCLUSIVE_ACQUIRE(LockThreads); // Modifies a variable (name), so an exclusive lock is required if(threadList.find(ThreadId) != threadList.end()) { if(!Name) Name = ""; strcpy_s(threadList[ThreadId].threadName, Name); 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 cbCheckWatchdog(int argc, char* argv[]) { EXCLUSIVE_ACQUIRE(LockWatch); bool watchdogTriggered = false; for(auto j = watchexpr.begin(); j != watchexpr.end(); ++j) { std::pair<unsigned int, WatchExpr*> i = *j; i.second->watchdogTriggered = false; duint intVal = i.second->getIntValue(); watchdogTriggered |= i.second->watchdogTriggered; } EXCLUSIVE_RELEASE(); if(watchdogTriggered) GuiUpdateWatchViewAsync(); varset("$result", watchdogTriggered ? 1 : 0, false); 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; }
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; } } }
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; }
void CommentCacheLoad(JSON Root) { EXCLUSIVE_ACQUIRE(LockComments); // Inline lambda to parse each JSON entry auto AddComments = [](const JSON Object, bool Manual) { size_t i; JSON value; json_array_foreach(Object, i, value) { COMMENTSINFO commentInfo; memset(&commentInfo, 0, sizeof(COMMENTSINFO)); // Module const char* mod = json_string_value(json_object_get(value, "module")); if(mod && strlen(mod) < MAX_MODULE_SIZE) strcpy_s(commentInfo.mod, mod); else commentInfo.mod[0] = '\0'; // Address/Manual commentInfo.addr = (uint)json_hex_value(json_object_get(value, "address")); commentInfo.manual = Manual; // String value const char* text = json_string_value(json_object_get(value, "text")); if(text) strcpy_s(commentInfo.text, text); else { // Skip blank comments continue; } const uint key = ModHashFromName(commentInfo.mod) + commentInfo.addr; comments.insert(std::make_pair(key, commentInfo)); } };
bool ModUnload(uint Base) { EXCLUSIVE_ACQUIRE(LockModules); // Find the iterator index const auto found = modinfo.find(Range(Base, Base)); if(found == modinfo.end()) return false; // Unload everything from TitanEngine StaticFileUnloadW(nullptr, false, found->second.Handle, found->second.FileMapSize, found->second.MapHandle, found->second.FileMapVA); // Remove it from the list modinfo.erase(found); EXCLUSIVE_RELEASE(); // Update symbols SymUpdateModuleList(); return true; }
void stackupdateseh() { SehMap newcache; std::vector<duint> SEHList; if(ExHandlerGetSEH(SEHList)) { STACK_COMMENT comment; strcpy_s(comment.color, "!sehclr"); // Special token for SEH chain color. auto count = SEHList.size(); for(duint i = 0; i < count; i++) { if(i + 1 != count) sprintf_s(comment.comment, GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "Pointer to SEH_Record[%d]")), i + 1); else sprintf_s(comment.comment, GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "End of SEH Chain"))); newcache.insert({ SEHList[i], comment }); } } EXCLUSIVE_ACQUIRE(LockSehCache); SehCache = std::move(newcache); }
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; }
void PatchClear(const char* Module) { EXCLUSIVE_ACQUIRE(LockPatches); // Was a module specified? if(!Module || Module[0] == '\0') { // No specific entries to delete, so remove all of them patches.clear(); } else { // Otherwise iterate over each patch and check the owner // module for the address for(auto itr = patches.begin(); itr != patches.end();) { if(!_stricmp(itr->second.mod, Module)) itr = patches.erase(itr); else ++itr; } } }
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 LoopCacheSave(JSON Root) { EXCLUSIVE_ACQUIRE(LockLoops); // Create the root JSON objects const JSON jsonLoops = json_array(); const JSON jsonAutoLoops = json_array(); // Write all entries for(auto & itr : loops) { const LOOPSINFO & currentLoop = itr.second; JSON currentJson = json_object(); json_object_set_new(currentJson, "module", json_string(currentLoop.mod)); json_object_set_new(currentJson, "start", json_hex(currentLoop.start)); json_object_set_new(currentJson, "end", json_hex(currentLoop.end)); json_object_set_new(currentJson, "depth", json_integer(currentLoop.depth)); json_object_set_new(currentJson, "parent", json_hex(currentLoop.parent)); if(currentLoop.manual) json_array_append_new(jsonLoops, currentJson); else json_array_append_new(jsonAutoLoops, currentJson); } // Append a link to the global root if(json_array_size(jsonLoops)) json_object_set(Root, "loops", jsonLoops); if(json_array_size(jsonAutoLoops)) json_object_set(Root, "autoloops", jsonAutoLoops); // Release memory/references json_decref(jsonLoops); json_decref(jsonAutoLoops); }