在不使用相关性的情况下直接调用/跳转ASM(x86)

时间:2011-02-15 06:27:51

标签: assembly dll x86

我正在向游戏中注入一个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块以使用直接跳转和调用?

2 个答案:

答案 0 :(得分:4)

你可以这样编码(gcc-style / 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页面放在一边仅使用十个字节就没有效率。如果您需要多个蹦床,请为蹦床实施自己的内存管理器......

答案 1 :(得分:0)

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