简单的蹦床挂钩

时间:2018-10-22 00:22:12

标签: c winapi

我一直试图在ExitProcess上编写一个蹦床挂钩,以求有趣。挂钩的代码(一个消息框)可以很好地执行,但是当需要返回ExitProcess时,我会遇到访问冲突。我已经多次阅读自己的代码,看不到任何错误。我将旧函数的序言存储在字节数组中,并在我修补的地址之后立即将jmp添加到该地址。我会用这种错误的方式吗?

#include "main.h"

PVOID TrampolineAddress;
BYTE TrampolineBytes[10] = { 0, 0, 0, 0, 0, 0xE9, 0, 0, 0, 0 };

void ExitProcessNew(UINT uExitCode)
{
    MessageBox(NULL, "Exiting!", "Exiting!", 0);
    _asm 
    {
        push uExitCode;
        call TrampolineAddress;
    }
}

int main()
{
    memcpy(&TrampolineBytes, &ExitProcess, 5);
    *(DWORD*)&TrampolineBytes[6] = (DWORD)((DWORD)&ExitProcessNew) - (DWORD)&ExitProcess;

    TrampolineAddress = VirtualAlloc(NULL, 10, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    memcpy(TrampolineAddress, TrampolineBytes, 10);

    BYTE PatchBytes[] = { 0xE9, 0, 0, 0, 0 };
    *(DWORD*)&PatchBytes[1] = (DWORD)((DWORD)&ExitProcessNew) - (DWORD)&ExitProcess - 5;

    BOOL writeSuccess = WriteProcessMemory(GetCurrentProcess(), &ExitProcess, PatchBytes, sizeof(PatchBytes), NULL);

    ExitProcess(0);
    printf("%d", GetLastError());
    getchar();
}

1 个答案:

答案 0 :(得分:0)

我花了很长时间尝试使您的代码正常工作,但最终我放弃了,决定仅仅向您展示有效的代码而不是尝试修复您的代码更容易。您的逻辑是有道理的,但我认为有几个小错误会导致失败。

因此,这是我使用很长时间的方法,该方法基于一个与我共享的名为Solaire的朋友的代码:

常规挂钩/绕行功能:

bool Hook(BYTE* src, BYTE* dst, int len)
{
    if (len < 5) return false;

    DWORD  curProtection;
    VirtualProtect(src, len, PAGE_EXECUTE_READWRITE, &curProtection);

    uintptr_t  relativeAddress = ((uintptr_t)dst - (uintptr_t)src) - 5;

    *src = 0xE9;
    *(uintptr_t *)((uintptr_t)src + 1) = relativeAddress;

    VirtualProtect(src, len, curProtection, &curProtection);
    return true;
}

蹦床功能:

void * TrampolineHook(BYTE* src, BYTE* dst, int len)
{
    // Make sure the length is greater than 5
    if (len < 5) return 0;

    // Create the gateway (len + 5 for the overwritten bytes + the jmp)
    void* gateway = VirtualAlloc(0, len + 5, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);

    //Write the stolen bytes into the gateway
    memcpy(gateway, src, len);

    // Get the gateway to destination addy
    uintptr_t  gatewayRelativeAddr = ((uintptr_t)src - (uintptr_t)gateway) - 5;

    // Add the jmp opcode to the end of the gateway
    *(BYTE*)((uintptr_t)gateway + len) = 0xE9;

    // Add the address to the jmp
    *(uintptr_t *)((uintptr_t)gateway + len + 1) = gatewayRelativeAddr;

    // Place the hook at the destination
    Hook(src, dst, len);

    return gateway;
}

您已经知道逻辑,因此我不需要解释代码,注释就足够了。

现在在下面,我们将定义与ExitProcess函数匹配的函数指针,并为模板加上“ t”前缀。

然后,我们创建该类型的指针,并为原始指针添加“ o”前缀,因为在运行代码后,我们将使用它来调用“原始”函数。然后,我们将流重定向到的实际函数的前缀为“ h”,表示“已连接”或其他任何内容。

主要代码:

typedef void(__stdcall* tExitProcess)(UINT);
tExitProcess oExitProcess;

void __stdcall hExitProcess(UINT uExitCode)
{
    MessageBox(NULL, "Exiting!", "Exiting!", 0);
    Sleep(1000);

    return oExitProcess(uExitCode);
}

int main()
{
    oExitProcess = (tExitProcess)TrampolineHook((BYTE*)&ExitProcess, (BYTE*)&hExitProcess, 5);
    ExitProcess(0);
}

相当标准的过程,请尝试一下,并与您进行比较,希望对您有所帮助