Add a utility function for patching read-only memory.

develop
Alexander Gavrilov 2012-08-17 14:32:04 +04:00
parent 509d957090
commit bcc41c081a
5 changed files with 76 additions and 0 deletions

@ -1235,6 +1235,12 @@ and are only documented here for completeness:
Returns a sequence of tables describing virtual memory ranges of the process.
* ``dfhack.internal.patchMemory(dest,src,count)``
Like memmove below, but works even if dest is read-only memory, e.g. code.
If destination overlaps a completely invalid memory region, or another error
occurs, returns false.
* ``dfhack.internal.memmove(dest,src,count)``
Wraps the standard memmove function. Accepts both numbers and refs as pointers.

@ -1409,6 +1409,11 @@ global environment, persistent between calls to the script.</p>
<li><p class="first"><tt class="docutils literal">dfhack.internal.getMemRanges()</tt></p>
<p>Returns a sequence of tables describing virtual memory ranges of the process.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.internal.patchMemory(dest,src,count)</tt></p>
<p>Like memmove below, but works even if dest is read-only memory, e.g. code.
If destination overlaps a completely invalid memory region, or another error
occurs, returns false.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.internal.memmove(dest,src,count)</tt></p>
<p>Wraps the standard memmove function. Accepts both numbers and refs as pointers.</p>
</li>

@ -1548,6 +1548,56 @@ void ClassNameCheck::getKnownClassNames(std::vector<std::string> &names)
names.push_back(*it);
}
bool Process::patchMemory(void *target, const void* src, size_t count)
{
uint8_t *sptr = (uint8_t*)target;
uint8_t *eptr = sptr + count;
// Find the valid memory ranges
std::vector<t_memrange> ranges;
getMemRanges(ranges);
unsigned start = 0;
while (start < ranges.size() && ranges[start].end <= sptr)
start++;
if (start >= ranges.size() || ranges[start].start > sptr)
return false;
unsigned end = start+1;
while (end < ranges.size() && ranges[end].start < eptr)
{
if (ranges[end].start != ranges[end-1].end)
return false;
end++;
}
if (ranges[end-1].end < eptr)
return false;
// Verify current permissions
for (unsigned i = start; i < end; i++)
if (!ranges[i].valid || !(ranges[i].read || ranges[i].execute) || ranges[i].shared)
return false;
// Apply writable permissions & update
bool ok = true;
for (unsigned i = start; i < end && ok; i++)
{
t_memrange perms = ranges[i];
perms.write = perms.read = true;
if (!setPermisions(perms, perms))
ok = false;
}
if (ok)
memmove(target, src, count);
for (unsigned i = start; i < end && ok; i++)
setPermisions(ranges[i], ranges[i]);
return ok;
}
/*******************************************************************************
M O D U L E S
*******************************************************************************/

@ -1124,6 +1124,17 @@ static int internal_getMemRanges(lua_State *L)
return 1;
}
static int internal_patchMemory(lua_State *L)
{
void *dest = checkaddr(L, 1);
void *src = checkaddr(L, 2);
int size = luaL_checkint(L, 3);
if (size < 0) luaL_argerror(L, 1, "negative size");
bool ok = Core::getInstance().p->patchMemory(dest, src, size);
lua_pushboolean(L, ok);
return 1;
}
static int internal_memmove(lua_State *L)
{
void *dest = checkaddr(L, 1);
@ -1214,6 +1225,7 @@ static const luaL_Reg dfhack_internal_funcs[] = {
{ "setAddress", internal_setAddress },
{ "getVTable", internal_getVTable },
{ "getMemRanges", internal_getMemRanges },
{ "patchMemory", internal_patchMemory },
{ "memmove", internal_memmove },
{ "memcmp", internal_memcmp },
{ "memscan", internal_memscan },

@ -283,6 +283,9 @@ namespace DFHack
/// modify permisions of memory range
bool setPermisions(const t_memrange & range,const t_memrange &trgrange);
/// write a possibly read-only memory area
bool patchMemory(void *target, const void* src, size_t count);
private:
VersionInfo * my_descriptor;
PlatformSpecific *d;