3

我制作了一个测试程序并制作了一个只打印一些文本的函数,我试图通过使用 IDA/Ghidra 反转它并获取指向它的指针来从 DLL 调用它。

它在 Ghidra 中的样子

我以为 IDA 提供了错误的地址,所以我与 Ghidra 核对了一下,我得到了相同的地址......

这是我从 DLL 调用函数的代码

#include <iostream>

void coolRoutine() {
    printf("starting...\n");
    void(*ofunct)() = (void(__cdecl *)())(0x00401000);
    printf("got funct!\n");
    ofunct();
    printf("done!\n");
}

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        coolRoutine();
        break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

程序打印“开始...”和“得到功能!” 但不调用原始函数。

我已经尝试查看几个帖子,但我无法弄清楚我做错了什么,因为其他人做了类似的事情并且对他们有用。

更新:正如有人建议的那样,我尝试将基地址添加到函数指针,但是我得到了相同的结果。

这是我尝试过的:

void coolRoutine() {
    printf("starting...\n");
    uintptr_t baseAddress = (uintptr_t)GetModuleHandle(0);
    std::cout << "Base Address: " << baseAddress << std::endl;
    void(*ofunct)() = (void(__cdecl *)())(baseAddress + 0x00401000);
    printf("got funct!\n");
    ofunct();
    printf("done!\n");
}

它正确地获取了基地址(或者至少我认为是,因为它不为空),但它没有执行 ofunct 并打印“完成!”。

4

1 回答 1

1

这是由于ASLR。应用程序的基地址在每次重新启动时都会发生变化,而 Ghidra 中的反汇编显示如果没有 ASLR,它的地址会是什么。

应用程序 pre-ASLR 的默认基地址是 0x00400000,因此我们必须执行 0x00401000 - 0x00400000 才能获得与基地址 0x1000 的相对地址。

现在,我们想将 0x1000 添加到基地址以获取我们的函数指针。

这可以使用

//Get the base address of the application
uintptr_t baseAddress = (uintptr_t)GetModuleHandle(0);
//Add the offset of the function relative to the base
uintptr_t functAddress = baseAddress + 0x1000;
//typecast it to the correct function signature
void(*funct)() = (void(__cdecl *)())(functAddress);
//call it
funct();
于 2020-04-19T21:32:20.787 回答