From 9f42cfe31b7fcee5099cae175e8aca908f52514a Mon Sep 17 00:00:00 2001 From: Nukem Date: Sun, 29 Mar 2015 18:48:08 -0400 Subject: [PATCH] Refactor patches.cpp/.h Fix compilation errors --- x64_dbg_dbg/_dbgfunctions.cpp | 10 +- x64_dbg_dbg/addrinfo.cpp | 2 +- x64_dbg_dbg/label.cpp | 6 +- x64_dbg_dbg/label.h | 12 +- x64_dbg_dbg/memory.cpp | 2 +- x64_dbg_dbg/patches.cpp | 371 ++++++++++++++++++++++------------ x64_dbg_dbg/patches.h | 20 +- x64_dbg_dbg/value.cpp | 2 +- 8 files changed, 265 insertions(+), 160 deletions(-) diff --git a/x64_dbg_dbg/_dbgfunctions.cpp b/x64_dbg_dbg/_dbgfunctions.cpp index 6accb9cd..11b00322 100644 --- a/x64_dbg_dbg/_dbgfunctions.cpp +++ b/x64_dbg_dbg/_dbgfunctions.cpp @@ -53,7 +53,7 @@ static bool _sectionfromaddr(duint addr, char* section) static bool _patchget(duint addr) { - return patchget(addr, 0); + return PatchGet(addr, 0); } static bool _patchinrange(duint start, duint end) @@ -84,13 +84,13 @@ static void _patchrestorerange(duint start, duint end) end = a; } for(duint i = start; i < end + 1; i++) - patchdel(i, true); + PatchDelete(i, true); GuiUpdatePatches(); } static bool _patchrestore(duint addr) { - return patchdel(addr, true); + return PatchDelete(addr, true); } static void _getcallstack(DBGCALLSTACK* callstack) @@ -178,9 +178,9 @@ void dbgfunctionsinit() _dbgfunctions.PatchInRange = _patchinrange; _dbgfunctions.MemPatch = _mempatch; _dbgfunctions.PatchRestoreRange = _patchrestorerange; - _dbgfunctions.PatchEnum = (PATCHENUM)patchenum; + _dbgfunctions.PatchEnum = (PATCHENUM)PatchEnum; _dbgfunctions.PatchRestore = _patchrestore; - _dbgfunctions.PatchFile = (PATCHFILE)patchfile; + _dbgfunctions.PatchFile = (PATCHFILE)PatchFile; _dbgfunctions.ModPathFromAddr = ModPathFromAddr; _dbgfunctions.ModPathFromName = ModPathFromName; _dbgfunctions.DisasmFast = disasmfast; diff --git a/x64_dbg_dbg/addrinfo.cpp b/x64_dbg_dbg/addrinfo.cpp index 5608a81b..5d8da198 100644 --- a/x64_dbg_dbg/addrinfo.cpp +++ b/x64_dbg_dbg/addrinfo.cpp @@ -101,7 +101,7 @@ void dbclose() FunctionClear(); loopclear(); BpClear(); - patchclear(); + PatchClear(); } ///api functions diff --git a/x64_dbg_dbg/label.cpp b/x64_dbg_dbg/label.cpp index c916f145..e290bc86 100644 --- a/x64_dbg_dbg/label.cpp +++ b/x64_dbg_dbg/label.cpp @@ -42,8 +42,8 @@ bool LabelSet(uint Address, const char* Text, bool Manual) // Insert label by key uint key = ModHashFromAddr(Address); - if(!labels.insert(std::make_pair(ModHashFromAddr(key), label)).second) - labels[key] = label; + if(!labels.insert(std::make_pair(ModHashFromAddr(key), labelInfo)).second) + labels[key] = labelInfo; return true; } @@ -252,7 +252,7 @@ bool LabelEnum(LABELSINFO* List, size_t* Size) for (auto& itr : labels) { *List = itr.second; - List->addr += ModBaseFromName(itr.econd.mod); + List->addr += ModBaseFromName(itr.second.mod); List++; } diff --git a/x64_dbg_dbg/label.h b/x64_dbg_dbg/label.h index 4db64eb6..a7fe5c3d 100644 --- a/x64_dbg_dbg/label.h +++ b/x64_dbg_dbg/label.h @@ -10,12 +10,12 @@ struct LABELSINFO bool manual; }; -bool LabelSet(uint addr, const char* text, bool manual); -bool labelfromstring(const char* text, uint* addr); -bool LabelGet(uint addr, char* text); -bool LabelDelete(uint addr); -void LabelDelRange(uint start, uint end); +bool LabelSet(uint Address, const char* Text, bool Manual); +bool LabelFromString(const char* Text, uint* Address); +bool LabelGet(uint Address, char* Text); +bool LabelDelete(uint Address); +void LabelDelRange(uint Start, uint End); void labelcachesave(JSON root); void labelcacheload(JSON root); -bool LabelEnum(LABELSINFO* labellist, size_t* cbsize); +bool LabelEnum(LABELSINFO* List, size_t* Size); void LabelClear(); \ No newline at end of file diff --git a/x64_dbg_dbg/memory.cpp b/x64_dbg_dbg/memory.cpp index 22f331e7..cfb514fa 100644 --- a/x64_dbg_dbg/memory.cpp +++ b/x64_dbg_dbg/memory.cpp @@ -277,7 +277,7 @@ bool MemPatch(void* BaseAddress, void* Buffer, SIZE_T Size, SIZE_T* NumberOfByte } for(SIZE_T i = 0; i < Size; i++) - patchset((uint)BaseAddress + i, oldData[i], ((unsigned char*)Buffer)[i]); + PatchSet((uint)BaseAddress + i, oldData[i], ((unsigned char*)Buffer)[i]); return MemWrite(BaseAddress, Buffer, Size, NumberOfBytesWritten); } diff --git a/x64_dbg_dbg/patches.cpp b/x64_dbg_dbg/patches.cpp index a15a29b6..2707a22f 100644 --- a/x64_dbg_dbg/patches.cpp +++ b/x64_dbg_dbg/patches.cpp @@ -6,198 +6,307 @@ #include "threading.h" #include "module.h" +typedef std::map PatchesInfo; + static PatchesInfo patches; -bool patchset(uint addr, unsigned char oldbyte, unsigned char newbyte) +bool PatchSet(uint Address, unsigned char OldByte, unsigned char NewByte) { - if(!DbgIsDebugging() || !MemIsValidReadPtr(addr)) + // MemIsValidReadPtr also checks if the debugger is actually + // debugging + if(!MemIsValidReadPtr(Address)) return false; - if(oldbyte == newbyte) - return true; //no need to make a patch for a byte that is equal to itself + + // Don't patch anything if the new and old values are the same + if(OldByte == NewByte) + return true; + PATCHINFO newPatch; - newPatch.addr = addr - ModBaseFromAddr(addr); - ModNameFromAddr(addr, newPatch.mod, true); - newPatch.oldbyte = oldbyte; - newPatch.newbyte = newbyte; - uint key = ModHashFromAddr(addr); - CriticalSectionLocker locker(LockPatches); - PatchesInfo::iterator found = patches.find(key); - if(found != patches.end()) //we found a patch on the specified address + newPatch.addr = Address - ModBaseFromAddr(Address); + newPatch.oldbyte = OldByte; + newPatch.newbyte = NewByte; + ModNameFromAddr(Address, newPatch.mod, true); + + // Generate a key for this address + uint 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) //patch is undone + if(found->second.oldbyte == NewByte) { + // The patch was undone here patches.erase(found); return true; } else { - newPatch.oldbyte = found->second.oldbyte; //keep the original byte from the previous patch - found->second = newPatch; + // Keep the original byte from the previous patch + newPatch.oldbyte = found->second.oldbyte; + found->second = newPatch; } } - else - patches.insert(std::make_pair(key, newPatch)); + else + { + // The entry was never found, insert it + patches.insert(std::make_pair(key, newPatch)); + } + return true; } -bool patchget(uint addr, PATCHINFO* patch) +bool PatchGet(uint Address, PATCHINFO* Patch) { + // CHECK: Export if(!DbgIsDebugging()) return false; - CriticalSectionLocker locker(LockPatches); - PatchesInfo::iterator found = patches.find(ModHashFromAddr(addr)); - if(found == patches.end()) //not found + + SHARED_ACQUIRE(LockPatches); + + // Find this specific address in the list + auto found = patches.find(ModHashFromAddr(Address)); + + if(found == patches.end()) return false; - if(patch) + + // Did the user request an output buffer? + if(Patch) { - *patch = found->second; - patch->addr += ModBaseFromAddr(addr); - return true; + *Patch = found->second; + Patch->addr += ModBaseFromAddr(Address); } - return (found->second.oldbyte != found->second.newbyte); + + // Return true because the patch was found + return true; } -bool patchdel(uint addr, bool restore) +bool PatchDelete(uint Address, bool Restore) { + // CHECK: Export function if(!DbgIsDebugging()) return false; - CriticalSectionLocker locker(LockPatches); - PatchesInfo::iterator found = patches.find(ModHashFromAddr(addr)); + + EXCLUSIVE_ACQUIRE(LockPatches); + + // Do a list lookup with hash + auto found = patches.find(ModHashFromAddr(Address)); + if(found == patches.end()) //not found return false; - if(restore) - MemWrite((void*)(found->second.addr + ModBaseFromAddr(addr)), &found->second.oldbyte, sizeof(char), 0); + + // Restore the original byte at this address + if(Restore) + MemWrite((void*)(found->second.addr + ModBaseFromAddr(Address)), &found->second.oldbyte, sizeof(char), nullptr); + + // Finally remove it from the list patches.erase(found); return true; } -void patchdelrange(uint start, uint end, bool restore) +void PatchDelRange(uint Start, uint End, bool Restore) { - if(!DbgIsDebugging()) - return; - bool bDelAll = (start == 0 && end == ~0); //0x00000000-0xFFFFFFFF - uint modbase = ModBaseFromAddr(start); - if(modbase != ModBaseFromAddr(end)) - return; - start -= modbase; - end -= modbase; - CriticalSectionLocker locker(LockPatches); - PatchesInfo::iterator i = patches.begin(); - while(i != patches.end()) - { - if(bDelAll || (i->second.addr >= start && i->second.addr < end)) - { - if(restore) - MemWrite((void*)(i->second.addr + modbase), &i->second.oldbyte, sizeof(char), 0); - patches.erase(i++); - } - else - i++; - } + // CHECK: Export call + if (!DbgIsDebugging()) + return; + + // 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 + uint 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();) + { + // [Start, End) + if (itr->second.addr >= Start && itr->second.addr < End) + { + // Restore the original byte if necessary + if (Restore) + MemWrite((void*)(itr->second.addr + moduleBase), &itr->second.oldbyte, sizeof(char), nullptr); + + itr = patches.erase(itr); + } + else + itr++; + } + } } -void patchclear(const char* mod) -{ - CriticalSectionLocker locker(LockPatches); - if(!mod or !*mod) - patches.clear(); - else - { - PatchesInfo::iterator i = patches.begin(); - while(i != patches.end()) - { - if(!_stricmp(i->second.mod, mod)) - patches.erase(i++); - else - i++; - } - } -} - -bool patchenum(PATCHINFO* patcheslist, size_t* cbsize) +bool PatchEnum(PATCHINFO* List, size_t* Size) { + // CHECK: Exported if(!DbgIsDebugging()) return false; - if(!patcheslist && !cbsize) + + // At least one parameter is needed + if(!List && !Size) return false; - CriticalSectionLocker locker(LockPatches); - if(!patcheslist && cbsize) + + SHARED_ACQUIRE(LockPatches); + + // Did the user request the size? + if(Size) { - *cbsize = patches.size() * sizeof(PATCHINFO); - return true; + *Size = patches.size() * sizeof(PATCHINFO); + + if (!List) + return true; } - int j = 0; - for(PatchesInfo::iterator i = patches.begin(); i != patches.end(); ++i, j++) + + // Copy each vector entry to a C-style array + for(auto& itr : patches) { - patcheslist[j] = i->second; - uint modbase = ModBaseFromName(patcheslist[j].mod); - patcheslist[j].addr += modbase; + *List = itr.second; + List->addr += ModBaseFromName(itr.second.mod);; + List++; } + return true; } -int patchfile(const PATCHINFO* patchlist, int count, const char* szFileName, char* error) +int PatchFile(const PATCHINFO* List, int Count, const char* FileName, char* Error) { - if(!count) + // + // This function returns an int based on the number + // of patches applied. -1 indicates a failure. + // + if(Count <= 0) { - if(error) - strcpy_s(error, MAX_ERROR_SIZE, "no patches to apply"); + // Notify the user of the error + if(Error) + strcpy_s(Error, MAX_ERROR_SIZE, "No patches to apply"); + return -1; } - char modname[MAX_MODULE_SIZE] = ""; - strcpy_s(modname, patchlist[0].mod); - //check if all patches are in the same module - for(int i = 0; i < count; i++) - if(_stricmp(patchlist[i].mod, modname)) - { - if(error) - sprintf(error, "not all patches are in module %s", modname); - return -1; - } - uint modbase = ModBaseFromName(modname); - if(!modbase) //module not loaded + + // Get a copy of the first module name in the array + char moduleName[MAX_MODULE_SIZE]; + strcpy_s(moduleName, List[0].mod); + + // Check if all patches are in the same module + for (int i = 0; i < Count; i++) + { + if (_stricmp(List[i].mod, moduleName)) + { + if (Error) + sprintf_s(Error, MAX_ERROR_SIZE, "not all patches are in module %s", moduleName); + + return -1; + } + } + + // See if the module was loaded + uint moduleBase = ModBaseFromName(moduleName); + + if(!moduleBase) { - if(error) - sprintf(error, "failed to get base of module %s", modname); + if(Error) + sprintf_s(Error, MAX_ERROR_SIZE, "failed to get base of module %s", moduleName); + return -1; } - wchar_t szOriginalName[MAX_PATH] = L""; - if(!GetModuleFileNameExW(fdProcessInfo->hProcess, (HMODULE)modbase, szOriginalName, MAX_PATH)) + + // Get the unicode version of the module's path + wchar_t originalName[MAX_PATH]; + + if(!GetModuleFileNameExW(fdProcessInfo->hProcess, (HMODULE)moduleBase, originalName, ARRAYSIZE(originalName))) { - if(error) - sprintf(error, "failed to get module path of module %s", modname); + if(Error) + sprintf_s(Error, MAX_ERROR_SIZE, "Failed to get module path of module %s", moduleName); + return -1; } - if(!CopyFileW(szOriginalName, StringUtils::Utf8ToUtf16(szFileName).c_str(), false)) + + // Create a temporary backup file + if(!CopyFileW(originalName, StringUtils::Utf8ToUtf16(FileName).c_str(), false)) { - if(error) - strcpy_s(error, MAX_ERROR_SIZE, "failed to make a copy of the original file (patch target is in use?)"); + if(Error) + strcpy_s(Error, MAX_ERROR_SIZE, "Failed to make a copy of the original file (patch target is in use?)"); + return -1; } - HANDLE FileHandle; - DWORD LoadedSize; - HANDLE FileMap; - ULONG_PTR FileMapVA; - if(StaticFileLoadW(StringUtils::Utf8ToUtf16(szFileName).c_str(), UE_ACCESS_ALL, false, &FileHandle, &LoadedSize, &FileMap, &FileMapVA)) + + HANDLE fileHandle; + DWORD loadedSize; + HANDLE fileMap; + ULONG_PTR fileMapVa; + if (!StaticFileLoadW(StringUtils::Utf8ToUtf16(FileName).c_str(), UE_ACCESS_ALL, false, &fileHandle, &loadedSize, &fileMap, &fileMapVa)) + { + strcpy_s(Error, MAX_ERROR_SIZE, "StaticFileLoad failed"); + return -1; + } + + // Begin iterating all patches, applying them to a file + int patchCount = 0; + + for(int i = 0; i < Count; i++) { - int patched = 0; - for(int i = 0; i < count; i++) - { - unsigned char* ptr = (unsigned char*)ConvertVAtoFileOffsetEx(FileMapVA, LoadedSize, modbase, patchlist[i].addr, false, true); - if(!ptr) //skip patches that do not have a raw address - continue; - dprintf("patch%.4d|%s[%.8X]:%.2X/%.2X->%.2X\n", i + 1, modname, ptr - FileMapVA, *ptr, patchlist[i].oldbyte, patchlist[i].newbyte); - *ptr = patchlist[i].newbyte; - patched++; - } - if(!StaticFileUnloadW(StringUtils::Utf8ToUtf16(szFileName).c_str(), true, FileHandle, LoadedSize, FileMap, FileMapVA)) - { - if(error) - strcpy_s(error, MAX_ERROR_SIZE, "StaticFileUnload failed"); - return -1; - } - return patched; + // Convert the virtual address to an offset within disk file data + unsigned char* ptr = (unsigned char*)ConvertVAtoFileOffsetEx(fileMapVa, loadedSize, moduleBase, List[i].addr, false, true); + + // Skip patches that do not have a raw address + if(!ptr) + continue; + + dprintf("patch%.4d|%s[%.8X]:%.2X/%.2X->%.2X\n", i + 1, moduleName, ptr - fileMapVa, *ptr, List[i].oldbyte, List[i].newbyte); + *ptr = List[i].newbyte; + patchCount++; } - strcpy_s(error, MAX_ERROR_SIZE, "StaticFileLoad failed"); - return -1; + + // Unload the file from memory and commit changes to disk + if(!StaticFileUnloadW(StringUtils::Utf8ToUtf16(FileName).c_str(), true, fileHandle, loadedSize, fileMap, fileMapVa)) + { + if(Error) + strcpy_s(Error, MAX_ERROR_SIZE, "StaticFileUnload failed"); + + return -1; + } + + // Zero the error message and return count + if (Error) + memset(Error, 0, MAX_ERROR_SIZE * sizeof(char)); + + return patchCount; } + +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++; + } + } +} \ No newline at end of file diff --git a/x64_dbg_dbg/patches.h b/x64_dbg_dbg/patches.h index fc9f2bfd..c5a4e717 100644 --- a/x64_dbg_dbg/patches.h +++ b/x64_dbg_dbg/patches.h @@ -1,5 +1,4 @@ -#ifndef _PATCHES_H -#define _PATCHES_H +#pragma once #include "_global.h" @@ -10,14 +9,11 @@ struct PATCHINFO unsigned char oldbyte; unsigned char newbyte; }; -typedef std::map PatchesInfo; -bool patchset(uint addr, unsigned char oldbyte, unsigned char newbyte); -bool patchget(uint addr, PATCHINFO* patch); -bool patchdel(uint addr, bool restore); -void patchdelrange(uint start, uint end, bool restore); -void patchclear(const char* mod = 0); -bool patchenum(PATCHINFO* patchlist, size_t* cbsize); -int patchfile(const PATCHINFO* patchlist, int count, const char* szFileName, char* error); - -#endif //_PATCHES_H +bool PatchSet(uint Address, unsigned char OldByte, unsigned char NewByte); +bool PatchGet(uint Address, PATCHINFO* Patch); +bool PatchDelete(uint Address, bool Restore); +void PatchDelRange(uint Start, uint End, bool Restore); +bool PatchEnum(PATCHINFO* List, size_t* Size); +int PatchFile(const PATCHINFO* List, int Count, const char* FileName, char* Error); +void PatchClear(const char* Module = nullptr); \ No newline at end of file diff --git a/x64_dbg_dbg/value.cpp b/x64_dbg_dbg/value.cpp index f440f6e9..4324683c 100644 --- a/x64_dbg_dbg/value.cpp +++ b/x64_dbg_dbg/value.cpp @@ -1557,7 +1557,7 @@ bool valfromstring(const char* string, uint* value, bool silent, bool baseonly, return false; else if(valapifromstring(string, value, value_size, true, silent, hexonly)) //then come APIs return true; - else if(labelfromstring(string, value)) //then come labels + else if(LabelFromString(string, value)) //then come labels return true; else if(SymAddrFromName(string, value)) //then come symbols return true;