malloc没有分配内存

时间:2015-02-05 00:51:31

标签: c++ winapi memory

调试我的代码时,我看到它跳转到ram的未定义部分,似乎malloc无法正常工作。这是用于创建trampoline并将realFunction挂钩到fakeFunction的代码。

void patch()
{
    PINT trampoline = (PINT)malloc(15);
    DWORD oldProtect;
    *((PBYTE)trampoline) = 0xE8;
    *((PDWORD)trampoline + 1) = ((DWORD)fakeFunction - (DWORD)trampoline -5);
    memcpy(trampoline, realFunction, 6);
    *((PDWORD)trampoline + 7) = 0xE9;
    *((PDWORD)trampoline + 8) = ((DWORD)fakeFunction - (DWORD)realFunction - 5);
    VirtualProtect((LPVOID)realFunction, 6, PAGE_EXECUTE_READWRITE, &oldProtect);
    *((PBYTE)realFunction) = 0xE9;
    *((PDWORD)realFunction + 1) = ((DWORD)trampoline - (DWORD)realFunction - 5);
    VirtualProtect((LPVOID)realFunction, 6, oldProtect, NULL);
}

更新:我解决了问题,这里是代码解释:

#include <iostream>
#include <windows.h>

using namespace std;

void realFunction()
{
    MessageBox(NULL, "realFunction()", "Trace", MB_OK);
}

void fakeFunction()
{
    MessageBox(NULL, "fakeFunction()", "Trace", MB_OK);
}

//I wrote this generic function (although not using it below) to ease the writing to memory process
template<typename T>
void writeMemory(DWORD address, T value)
{
    *((T*)address) = value;
}

void main()
{
    BYTE originalPrologue[sizeof(DWORD[2])]; //Why DWORD[2]... meh it is just 2*4 = bytes not a big deal.
    DWORD oldProtection;
    DWORD addr = (DWORD)realFunction;

    for (int i = 0; i < sizeof(DWORD[2]); i++) {
        originalPrologue[i] = (*(PBYTE)(addr + i));
    }

    //(DWORD)((DWORD)fakeFunction - (DWORD)realFunction - 5) note that we do target - source - 5, why - 5 ? because the size of jump instruction is 5, and the destination of jump is relative to it's address.
    //Implement Hook
    VirtualProtect(realFunction, sizeof(DWORD[3]), PAGE_EXECUTE_READWRITE, &oldProtection);
    *((PBYTE)addr) = 0xE9; E9 is JMP instruction
    *((PDWORD)(addr + 1)) = (DWORD)((DWORD)fakeFunction - (DWORD)realFunction - 5);
    VirtualProtect(realFunction, sizeof(DWORD[3]), oldProtection, NULL);

    realFunction(); //Boom, we now jump to our fake function instead of the original one.

    //Unimplement hook by restoring the original prologue
    VirtualProtect(realFunction, sizeof(DWORD[3]), PAGE_EXECUTE_READWRITE, &oldProtection);
    memcpy(realFunction, originalPrologue, sizeof(DWORD[2]));
    VirtualProtect(realFunction, sizeof(DWORD[3]), oldProtection, NULL);

    realFunction(); //Test it and we have the original function back!

    while (true){
        cin.get();
    }
}

1 个答案:

答案 0 :(得分:2)

这段代码充满了错误。正如评论中指出的那样,您根本没有考虑指针算术,因此您在不正确的内存地址处写入值。您也没有进行任何错误处理,并且您甚至没有正确设置绕行和蹦床功能。您显然没有阅读有关如何实际实施绕行的文档:

Detours: Binary Interception of Win32 Functions

特别是:

  

为了绕过目标函数,Detours首先为动态trampoline函数分配内存(如果没有提供静态trampoline),然后启用对目标和trampoline的写访问。从第一条指令开始,Detours将指令从目标复制到蹦床,直到至少复制了5个字节(足以进行无条件跳转指令)。如果目标函数少于5个字节,则Detours中止和   返回错误代码。要复制指令,Detours使用简单的表驱动反汇编程序。 Detours从最后添加了一条跳转指令   蹦床到第一个非复制的指令   目标函数。 Detours将无条件跳转指令写入绕行函数作为目标的第一条指令   功能。要完成,Detours将恢复目标和trampoline函数的原始页面权限,并通过调用FlushInstructionCache来刷新CPU指令缓存。

CPU指令是可变长度的。不同的指令是不同的字节长度。您可能需要将超过5个字节复制到蹦床中以说明完整说明。您不能假设每个函数中都使用了正好6个字节,因为您最终可能会复制多字节指令的一部分。因此,您必须分析正在绕行的原始函数的指令并根据需要复制正确的字节数,以便蹦床始终包含完整的指令,然后您必须在蹦床内的正确偏移处插入JMP指令,并使其跳转到原始函数的正确偏移量。

更糟糕的是,你的蹦床正在跳入你的绕道功能而不是原来的功能,你正在修补原来的功能,跳进你的蹦床,而不是你的绕行功能。

简而言之,这段代码的每一行都只是在每一步都做错了。如果你要解决这种先进的技术,那么至少应该足够聪明,使用预先制作的库来避免犯下所有这些错误。您的错误代码可能会导致严重的内存损坏和运行时错误。