编写蹦床函数

Posted

技术标签:

【中文标题】编写蹦床函数【英文标题】:Writing a Trampoline Function 【发布时间】:2011-12-27 07:57:54 【问题描述】:

我设法覆盖了内存中函数的前几个字节,并将其绕道到我自己的函数中。我现在在创建蹦床函数以将控制权反弹回实际函数时遇到问题。

这是我的问题here 的第二部分。

BYTE *buf = (BYTE*)VirtualAlloc(buf, 12, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
void (*ptr)(void) = (void (*)(void))buf;

vm_t* VM_Create( const char *module, intptr_t (*systemCalls)(intptr_t *), vmInterpret_t interpret )

    MessageBox(NULL, L"Oh Snap! VM_Create Hooked!", L"Success!", MB_OK);

    ptr();

    return NULL;//control should never get this far


void Hook_VM_Create(void)

    DWORD dwBackup;
    VirtualProtect((void*)0x00477C3E, 7, PAGE_EXECUTE_READWRITE, &dwBackup);

    //save the original bytes
    memset(buf, 0x90, sizeof(buf));
    memcpy(buf, (void*)0x00477C3E, 7);

    //finish populating the buffer with the jump instructions to the original functions
    BYTE *jmp2 = (BYTE*)malloc(5);
    int32_t offset2 = ((int32_t)0x00477C3E+7) - ((int32_t)&buf+12);
    memset((void*)jmp2, 0xE9, 1);
    memcpy((void*)(jmp2+1), &offset2, sizeof(offset2));
    memcpy((void*)(buf+7), jmp2, 5);

    VirtualProtect((void*)0x00477C3E, 7, PAGE_EXECUTE_READ, &dwBackup);

0x00477C3E 是被覆盖函数的地址。在我重写它们之前,原始函数的 asm 被保存到 buf。然后将我的 5 字节 jmp 指令添加到 buf 以返回原始函数的其余部分。

当调用 ptr() 时出现问题,程序崩溃。在调试站点时,它崩溃的地方看起来不像我的 ptr() 函数,但是仔细检查我的偏移量计算是否正确。

注意:省略了多余的代码,以便更容易阅读所有内容

编辑:这就是 ptr() 函数在 ollydbg 中的样子

0FFB0000   55               PUSH EBP
0FFB0001   57               PUSH EDI
0FFB0002   56               PUSH ESI
0FFB0003   53               PUSH EBX
0FFB0004   83EC 0C          SUB ESP,0C
0FFB0007  -E9 F1484EFD      JMP 0D4948FD

所以看起来好像我的偏移量计算是错误的。

【问题讨论】:

在哪里覆盖 0x00477C3E 处的代码以跳转到 VM_Create?你在哪里恢复 0x00477C3E 的代码?在返回原始代码时,您是否采取任何措施来保留寄存器等? 原来的VM_Create在VM_Hook_Create的开头被覆盖。代码没有恢复,包含缺少的 asm 指令的 detour 函数被加载到缓冲区中,然后调用,在缓冲区的末尾,跳转到原始 vm_create 的其余部分被“调用”(?) 【参考方案1】:

所以你的 buf[] 最终包含两件事:

原始指令的前 7 个字节 跳转

然后你将控制权转移给 buf。是否保证前 7 个字节仅包含整个指令?如果没有,您可能会在执行以这 7 个字节开始的最后一条不完整指令时或之后崩溃。

是否保证这 7 个字节中的指令不进行任何 EIP 相关计算(这包括主要具有 EIP 相关寻址的指令,例如跳转和调用)?否则,原函数的延续将无法正常工作,并可能最终导致程序崩溃。

原始函数是否带有任何参数?如果是这样,只需执行 ptr(); 即可使原始代码处理从寄存器和/或堆栈中获取的垃圾(取决于调用约定)并且可能会崩溃。

编辑:还有一件事。使用buf+12 而不是&buf+12。在您的代码中,buf 是一个指针,而不是数组。

【讨论】:

是的,前七个字节是完整的指令。事实上,它们是您在我的 ptr() 函数中看到的前七个字节。原始函数的参数被压入堆栈,并且没有进行相对于 eip 的计算。所以一切都应该是有效的。 @Adam: 去掉 buf 前的 & 符号。 roflmao,天哪,我真是个白痴。我怎么会错过这个。你会认为指针的其他事情不会发生这样的错误。 tyvm 调用 ptr() 正在破坏堆栈,但已修复此问题,现在一切顺利:D

以上是关于编写蹦床函数的主要内容,如果未能解决你的问题,请参考以下文章

什么是蹦床功能?

MonoTouch 6.0.8 发行说明中的​​“运行时蹦床”是啥意思?

如何分析 Monotouch 以查看运行时创建的蹦床数量(按类型)?

cf1491C. Pekora and Trampoline

蓝桥杯集训100题scratch汉娜蹦床 蓝桥杯scratch比赛专项预测编程题 模拟练习题第08题

蓝桥杯集训100题scratch汉娜蹦床 蓝桥杯scratch比赛专项预测编程题 模拟练习题第08题