传统JMP 只支持32位的程序, 64位程序的地址有 8个字节 ,直接JMP只支持4个字节,跳转的地址和HOOK地址相减超过4个字节 就会出错了
在64位 可以这样跳,
push rax 保存寄存器
mov rax,目标绝对地址
jmp rax
pop rax 还原寄存器
很简单,如果你分配的内存地址是64位的话。如: 504BEA0000, 根据我帖子里的回复,你可以这样
方法一:
48 B8 0000EA4B50000000 - mov rax,000000504BEA0000
FF E0 - jmp rax
指令和机器码:
mov rax, 64位地址 的机器码就是 “48 B8 64位地址的little-endian(需要64位即8个字节)”
jmp rax 的机器码 FF E0
这个方法会占用12个字节。如果你还要保存rax寄存器内容和还原寄存器,你还需要额外的2两个字节,即14个字节。
方法二:
如果跳转前后的地址都是32位的,就如我前面截图上的那个,那么地址的换算和32位没有什么区别,都是用的相对偏移。
方法三:
如果你用我前面提到的另外一种64位跳转方法,如
504BEA0006 - FF 25 00000000 - jmp qword ptr [504BEA000C]
504BEA000C - 00 00 - add [rax],al
504BEA000E - EA 4B500000 0000 - jmp 0000:0000504B
我是把64位的跳转地址000000504BEA0000作为数据直接写到跳转语句504BEA0006的下面504BEA000C处。那么跳转语句永远都是FF 25 00000000, 它会读取接下来的8个字节作为跳转地址来使用的。而这个地址就是你申请到的内存地址。可以看到这种方法需要14个连续字节,且不改变寄存器的内容。
当然你也可以把跳转地址的数据写到其他的地方如: 04BEA000D处。 那么跳转语句的FF 25 00000000就变成FF 25 01000000, 其中01000000 little-endian读下来就是00000001=1 即关于504BEA000C的相对地址是1。这后面4个字节其实就是数据地址关于504BEA000C的偏移量。和32位的原理是相同的。
总之,以上三种方法各有特色也各有利弊。方法一和三对于32和64位地址是通用的。方法二适用当地址是32位的情况下。而对于第一种方法需要修改寄存器,但是不需要计算跳转地址,而且寻址范围包括整个64位可用地址空间。第三种方法不修改寄存器,但需要计算偏移地址,而且和32位一样寻址空间限制在32位即前后2GB的范围内。所以根据你的需要自己取舍吧。
安卓内存逆向交流【群】916759588