1
0
Fork 0

Refactor patches.cpp/.h

Fix compilation errors
This commit is contained in:
Nukem 2015-03-29 18:48:08 -04:00
parent 50ce7be0c3
commit 9f42cfe31b
8 changed files with 265 additions and 160 deletions

View File

@ -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;

View File

@ -101,7 +101,7 @@ void dbclose()
FunctionClear();
loopclear();
BpClear();
patchclear();
PatchClear();
}
///api functions

View File

@ -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++;
}

View File

@ -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();

View File

@ -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);
}

View File

@ -6,198 +6,307 @@
#include "threading.h"
#include "module.h"
typedef std::map<uint, PATCHINFO> 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++;
}
}
}

View File

@ -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<uint, PATCHINFO> 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);

View File

@ -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;