【问题标题】:Hot Patching A Function热补丁功能
【发布时间】:2011-12-26 18:07:12
【问题描述】:

我正在尝试热修补内存中的 exe,源可用,但我这样做是为了学习。 (所以请不要让 cmets 建议我修改原始源或使用 detours 或任何其他库)

以下是我遇到问题的功能。

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 创建到我自己的。我相信这是我覆盖原始指令的方式。

【问题讨论】:

    标签: c winapi assembly reverse-engineering


    【解决方案1】:

    我可以看到一些问题。

    我假设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

    【讨论】:

    • 好的,我已经更新了我的偏移量,现在它是正确的。我没想到现在加 5 是有道理的。但是我仍然没有得到一个窗口说我们已经分支到我的 vm_create。我知道我将字节写入内存的方式是丑陋的,有没有更简洁的方法来做到这一点?你觉得我写内存的方式有什么问题吗?
    • 你记得把标志转过来偏移吗?在您的术语中,代码应为:int32_t offset = (int32_t)&VM_Create + 5 - (int32_t)0x00477C3E;
    • 写入内存的方式很好。您应该检查VirtualProtect 的返回值,但如果这不起作用,那么您会遇到段错误。您应该将 5 而不是 7 传递给 VirtualProtect。真的,这里唯一可能出错的是偏移量的计算。
    • 符号错误。偏移量 = &newFunc - (patchAddr + 5)。 -5.
    • 好的,它现在运行良好。我现在只需要用我重写的字节来编写我的蹦床函数。而且我现在完全理解了跳转算法,jmp 指令相对于它结束的地方跳转,而不是函数开始的地方(我知道这一点,我不知道为什么我会这么想),所以为了计算偏移量,我们将 5 添加到原始 vm_create,因为我们为 jmp + 相对地址写入的数据量是 5 个字节。非常感谢。我确实将内存重置为 PAGE_EXECUTE_READ。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-26
    • 1970-01-01
    • 1970-01-01
    • 2016-04-24
    • 2018-10-28
    相关资源
    最近更新 更多