我正在尝试热修补内存中的一个exe,源代码是可用的,但我这样做是为了学习。(因此,请不要评论我修改原始来源或使用迂回或任何其他libs)
下面是我遇到问题的函数。

vm_t* VM_Create( const char *module, intptr_t (*systemCalls)(intptr_t *), vmInterpret_t interpret )
{
    MessageBox(NULL, L"Oh snap! We hooked VM_Create!", L"Success!", MB_OK);
    return NULL;
}

void Hook_VM_Create(void)
{

    DWORD dwBackup;
    VirtualProtect((void*)0x00477C3E, 7, PAGE_EXECUTE_READWRITE, &dwBackup);

    //Patch the original VM_Create to jump to our detoured one.
    BYTE *jmp = (BYTE*)malloc(5);
    uint32_t offset = 0x00477C3E - (uint32_t)&VM_Create; //find the offset of the original function from our own
    memset((void*)jmp, 0xE9, 1);
    memcpy((void*)(jmp+1), &offset, sizeof(offset));
    memcpy((void*)0x00477C3E, jmp, 5);

    free(jmp);
}

我有一个vm_create函数,我想被调用,而不是原来的函数。我还没有写一个蹦床,所以它崩溃(如预期)。但是消息框没有弹出,我已经绕道原始vm创建到我自己的。我相信这是我重写原始指令的方式。

最佳答案

我能看出一些问题。
我假设0x00477C3E是原始VM_Create函数的地址。你真的不应该硬编码。改为使用&VM_Create。当然,这意味着您需要为替换函数使用不同的名称。
偏移量计算不正确。你看错了。更重要的是,偏移量应用于指令末尾而不是开头的指令指针。所以你需要把它移5(指令的大小)。偏移量也应该是有符号整数。
理想情况下,如果考虑到我的第一点,代码将如下所示:

int32_t offset = (int32_t)&New_VM_Create - ((int32_t)&VM_Create+5);

感谢Hans Passant修复我自己愚蠢的符号错误在原来的版本!
如果你在一台64位的机器上工作,你需要用64位来做你的算术运算,一旦你计算了偏移量,就把它截断为32位偏移量。
另一个细微差别是,在编写了新的JMP指令并调用FlushInstructionCache之后,应该将内存重置为只读。

07-24 09:45