我试图为x86和amd64编写trampolines,以便将给定的函数调用立即导向存储在已知内存位置的地址(目的是确保第一个目标地址存在于给定的DLL中(视窗))。
以下代码尝试使用_fn
作为内存位置(或其中一组)来启动实际目标地址:
(*_fn[IDX])(); // rough equivalent in C
.globl _asmfn
_asmfn:
jmp *_fn+8*IDX(%rip)
IDX
旨在使用一些CPP宏来构造,以提供一系列嵌入式DLL向量,每个向量唯一地映射到_fn
函数指针数组中的一个槽。
这可以在一个简单的测试程序中工作,但是当我实际将它放入共享库(目前在OSX上进行测试)时,在尝试向_asmfn代码传递时出现总线错误:
Invalid memory access of location 0x10aa1f320 rip=0x10aa1f320
这段代码的最终目标是Windows,虽然我还没有在那里尝试过(我想我至少可以在OSX / intel的测试用例中证明这个程序集)。 amd64跳跃至少在名义上是正确的,还是我错过了什么?
关于trampolines on amd64的一个很好的参考。
修改
跳转 在Windows 7上正常工作(最终有机会测试)。但是,我仍然很想知道为什么它在OSX上失败了。总线错误是由KERN_PROTECTION_FAILURE引起的,这似乎表明操作系统保护阻止执行该代码。目标地址是分配的内存(它是由libffi生成的蹦床),但我相信它被正确标记为可执行内存。如果它是可执行内存问题,那就可以解释为什么我的独立测试代码有效(回调蹦床被编译,未分配)。
答案 0 :(得分:0)
使用PC相对寻址时,请记住偏移量必须在+ - 2GB范围内。这意味着你的跳台和蹦床不能相距太远。关于这样的蹦床,可以在Windows x64上进行传输而不需要破坏任何寄存器:
一个序列:
PUSH <high32>
MOV DWORD PTR [ RSP - 4 ], <low32>
RET
这适用于Win64和UN * X x86_64。虽然在UN * X上,如果该函数使用了redzone,那么你就是在破坏......
一个序列:
JMP [ RIP ]
.L: <tgtaddr64>
再次,适用于Win64和UN * X x86_64。
一个序列:
MOV DWORD PTR [ RSP + c ], <low32>
MOV DWORD PTR [ RSP + 8 ], <high32>
JMP [ RSP + 8 ]
这是Win64特有的,因为它(ab)使用Win64 ABI保留的32字节“参数空间”的一部分(在堆栈上的返回地址上面); UN * X x86_64相当于这将是(ab)使用保留的128字节“红色区域”的一部分(只是在下面的堆栈上的返回地址)那里:
MOV DWORD PTR [ RSP - c ], <low32>
MOV DWORD PTR [ RSP - 8 ], <high32>
JMP [ RSP - 8 ]
只有在调用蹦床时才能接受(覆盖)其中的内容,两者都可以使用。
如果可以在内存中直接构建这样一个与位置无关的寄存器中立蹦床 - 就像这样(对于方法1):
#include <stdint.h>
#include <stdio.h>
char *mystr = "Hello, World!\n";
int main(int argc, char **argv)
{
struct __attribute__((packed)) {
char PUSH;
uint32_t CONST_TO_PUSH;
uint32_t MOV_TO_4PLUS_RSP;
uint32_t CONST_TO_MOV;
char RET;
} mycode = {
0x68, ((uint32_t)printf),
0x042444c7, (uint32_t)((uintptr_t)printf >> 32),
0xc3
};
void *buf = /* fill in an OS-specific way to get an executable buffer */;
memcpy(buf, &mycode, sizeof(mycode));
__asm__ __volatile__(
"push $0f\n\t" // this is to make the "jmp" return
"jmp *%0\n\t"
"0:\n\t" : : "r"(buf), "D"(mystr), "a"(0));
return 0;
}
请注意,这并未考虑是否有任何非易失性寄存器被“调用”函数破坏;我也忽略了如何使trampoline缓冲区可执行(堆栈通常不在Win64 / x86_64上)。
答案 1 :(得分:0)