(hopefully) high performance safe memory read function

This commit is contained in:
mrexodia 2015-12-19 07:05:50 +01:00
parent abc8a41a8d
commit 8f62768690
5 changed files with 89 additions and 6 deletions

View File

@ -32,6 +32,7 @@ namespace GleeBug
typedef std::map<uint32, ThreadInfo> ThreadMap;
typedef std::map<BreakpointKey, BreakpointInfo> BreakpointMap;
typedef std::map<BreakpointKey, BreakpointCallback> BreakpointCallbackMap;
typedef std::unordered_map<ptr, BreakpointMap::iterator> SoftwareBreakpointMap;
//vector typedefs
typedef std::vector<StepCallback> StepCallbackVector;

View File

@ -37,7 +37,8 @@ namespace GleeBug
FlushInstructionCache(hProcess, nullptr, 0);
//insert in the breakpoint map
breakpoints.insert({ { info.type, info.address }, info });
auto itr = breakpoints.insert({ { info.type, info.address }, info });
softwareBreakpointReferences[info.address] = itr.first;
return true;
}
@ -72,6 +73,7 @@ namespace GleeBug
}
//remove the breakpoint from the maps
softwareBreakpointReferences.erase(info.address);
breakpoints.erase(found);
breakpointCallbacks.erase({ BreakpointType::Software, address });
return true;

View File

@ -7,11 +7,60 @@ namespace GleeBug
return !!ReadProcessMemory(this->hProcess, reinterpret_cast<const void*>(address), buffer, size, nullptr);
}
bool ProcessInfo::MemReadSafe(ptr address, void* buffer, ptr size) const
{
if (!MemRead(address, buffer, size))
return false;
//choose the filter method that has the lowest cost
auto start = address;
auto end = start + size;
if (size > breakpoints.size())
{
for (const auto & breakpoint : breakpoints)
{
if (breakpoint.first.first != BreakpointType::Software)
continue;
const auto & info = breakpoint.second;
auto curAddress = info.address;
for (ptr j = 0; j < info.internal.software.size; j++)
{
if (curAddress + j >= start && curAddress + j < end)
((uint8*)buffer)[curAddress + j - start] = info.internal.software.oldbytes[j];
}
}
}
else
{
for (ptr i = start; i < end; i++)
{
auto found = softwareBreakpointReferences.find(i);
if (found == softwareBreakpointReferences.end())
continue;
const auto & info = found->second->second;
auto curAddress = info.address;
for (ptr j = 0; j < info.internal.software.size && i < end; j++, i++)
{
if (curAddress + j >= start && curAddress + j < end)
((uint8*)buffer)[curAddress + j - start] = info.internal.software.oldbytes[j];
}
i += info.internal.software.size - 1;
}
}
return true;
}
bool ProcessInfo::MemWrite(ptr address, const void* buffer, ptr size)
{
return !!WriteProcessMemory(this->hProcess, reinterpret_cast<void*>(address), buffer, size, nullptr);
}
bool ProcessInfo::MemWriteSafe(ptr address, const void* buffer, ptr size)
{
return false;
}
bool ProcessInfo::MemIsValidPtr(ptr address) const
{
uint8 byte;

View File

@ -24,6 +24,7 @@ namespace GleeBug
ThreadMap threads; //DO NOT COPY THESE OBJECTS!
DllMap dlls;
BreakpointMap breakpoints;
SoftwareBreakpointMap softwareBreakpointReferences;
BreakpointCallbackMap breakpointCallbacks;
BreakpointInfo hardwareBreakpoints[4];
@ -44,6 +45,15 @@ namespace GleeBug
*/
bool MemRead(ptr address, void* buffer, ptr size) const;
/**
\brief Safely read memory from the process, filtering out breakpoint bytes.
\param address The virtual address to read from.
\param [out] buffer Destination buffer. Cannot be null. May be filled partially on failure.
\param size The size to read.
\return true if it succeeds, false if it fails.
*/
bool MemReadSafe(ptr address, void* buffer, ptr size) const;
/**
\brief Write memory to the process.
\param address The virtual address to write to.
@ -53,6 +63,15 @@ namespace GleeBug
*/
bool MemWrite(ptr address, const void* buffer, ptr size);
/**
\brief Safely write memory to the process, preserving breakpoint bytes.
\param address The virtual address to write to.
\param [in] buffer Source buffer. Cannot be null.
\param size The size to write.
\return true if it succeeds, false if it fails.
*/
bool MemWriteSafe(ptr address, const void* buffer, ptr size);
/**
\brief Check if an address is a valid read pointer.
\param address The address to check.

View File

@ -50,7 +50,7 @@ protected:
printf("Process %d created with entry 0x%p\n",
_debugEvent.dwProcessId,
entry);
HardwareBreakpointSlot slot;
/*HardwareBreakpointSlot slot;
if (_process->GetFreeHardwareBreakpointSlot(slot))
{
if (_process->SetHardwareBreakpoint(entry, slot, this, &MyDebugger::cbEntryHardwareBreakpoint, HardwareBreakpointType::Execute, HardwareBreakpointSize::SizeByte))
@ -59,12 +59,24 @@ protected:
printf("Failed to set hardware breakpoint at 0x%p\n", entry);
}
else
printf("No free hardware breakpoint slot...\n");
printf("No free hardware breakpoint slot...\n");*/
/*if(_process->SetBreakpoint(entry, this, &MyDebugger::cbEntryBreakpoint))
if(_process->SetBreakpoint(entry, this, &MyDebugger::cbEntryBreakpoint))
printf("Breakpoint set at 0x%p!\n", entry);
else
printf("Failed to set breakpoint at 0x%p...\b", entry);*/
printf("Failed to set breakpoint at 0x%p...\b", entry);
uint8 test[5];
ptr start = entry - 2;
printf("unsafe: ");
_process->MemRead(start, test, sizeof(test));
for (int i = 0; i < sizeof(test); i++)
printf("%02X ", test[i]);
puts("");
_process->MemReadSafe(start, test, sizeof(test));
printf(" safe: ");
for (int i = 0; i < sizeof(test); i++)
printf("%02X ", test[i]);
puts("");
}
void cbExitProcessEvent(const EXIT_PROCESS_DEBUG_INFO & exitProcess, const ProcessInfo & process) override