【问题标题】:Directly call/jump in ASM without using relevance(x86)在 ASM 中直接调用/跳转而不使用相关性(x86)
【发布时间】:2011-02-15 06:27:50
【问题描述】:

我正在将一个 c++ DLL 注入到游戏中,并且我想将一个函数与我自己的一些代码挂钩。由于DLL每次都映射到不同的位置,直接跳转和调用会更容易。另外,因为这是一个钩子,所以我不想在返回函数时更改堆栈或寄存器。

我声明了一个 char* 来存储 Asm,这样我就有一个指向它的指针。(char* asm="\x00";) 如果你能提供十六进制,那会节省我一些时间。

我尝试使用 FF 和 EA 进行调用和跳转,但我想我只是不明白它们是如何工作的。当我使用它们时,我注意到我现在在操作中有一个冒号。

JMP FAR FWORD PTR DS:[00000000]

这不起作用,在我尝试使用指向跳转位置的指针后它仍然不起作用。

这是我开始尝试不同方法之前使用的程序集:

01270000    50              PUSH EAX
01270001    57              PUSH EDI
01270002    E8 E9CC1BFF     CALL fwound.0042CCF0
01270007    5F              POP EDI
01270008    58              POP EAX
01270009    50              PUSH EAX                      //replacements
0127000A    8D4C24 7C       LEA ECX,DWORD PTR SS:[ESP+7C] //
0127000E  - E9 36D11BFF     JMP fwound.0042D149

我使用 Olly 制作了该块,因此它知道当时需要的相关跳转/调用。

Asm 在内存中之后,我必须在函数中重写两个操作(它们被替换)才能跳转到这个位置。

那么,如何修复我的 Asm 块以使用直接跳转和调用?

【问题讨论】:

    标签: assembly dll x86


    【解决方案1】:

    您可以这样编码(gcc 样式/AT&T 汇编语法):

        jmp    *.Ltgtaddr
    .Ltgtaddr:  .long absoluteAddrOfFunctionToCall
    

    这组装成十个字节(在 32 位 x86 上)-ff 25 用于具有 32 位内存操作数的绝对 jmp,然后是带有下一个字的地址的四个字节,然后是(绝对)目标的内容您的代码的地址。

    编辑:我已经用经过编译和测试的示例更新了下面的部分。

    您可以从 C 源代码中动态创建这样的蹦床。示例源(需要 32 位 x86,留给读者如何将蹦床转换为 64 位的练习):

    #include <sys/mman.h>
    #include <stdio.h>
    
    void oneWay(char *str, int arg)
    { printf("string is \"%s\", int is %d\n", str, arg); }
    
    void otherWay(char *str, int arg)
    { printf(str, arg); printf("\n"); }
    
    void *trampGen(void *tgtAddr)
    {
        char *trampoline = mmap(NULL, 10, PROT_EXEC | PROT_WRITE | PROT_READ,
            MAP_PRIVATE | MAP_ANON, -1, 0);
        trampoline[0] = (char)0xff; trampoline[1] = (char)0x25;
        *(char**)(trampoline+2) = trampoline + 6;
        *(void**)(trampoline+6) = tgtAddr;
        return trampoline;
    }
    
    int main(int argc, char **argv)
    {
        void * (*funcptr)(char*, int) = trampGen(oneWay);
        *funcptr("Test %d String", 12345);
        *(void **)(((char *)funcptr) + 6) = otherWay;
        *funcptr("Test %d String", 12345);
        munmap(funcptr, 10);
        return 0;
    }
    

    为我输出:

    $ ./tt
    string is "Test %d String", int is 12345
    Test 12345 String
    

    请注意,留出整个 MMU 页面以仅使用其中的 10 个字节会稍微低效。如果您需要多个蹦床,请为蹦床实现自己的内存管理器...

    【讨论】:

      【解决方案2】:

      从来没有尝试过这种事情,
      但我认为您应该使用游戏已知内存位置的偏移量(使用 ollydbg 查找),因此每次将此(固定)偏移量添加到(可变)地址时。例如,此地址可以是在ss:ebp 找到的返回地址(因为游戏调用了您的函数),并且在 ollyDBG 的帮助下计算了该地址的偏移量。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-02-21
        • 2011-03-11
        • 1970-01-01
        • 1970-01-01
        • 2015-05-16
        • 2017-01-18
        相关资源
        最近更新 更多