实现Android ARM64平台下Inline Hook框架

        Android阵营新出机型的cpu基本都是64位了,虽然可以向下兼容armeabi-v7a,但是使用32位的so毕竟不能充分发挥64位cpu的潜力,所以以后arm64-v8a用的会越来越多。但是整个安卓生态圈似乎还没有开源发布的ARM64内联HOOK方案,所以自己动手写了个,姑且取名And64InlineHook吧,需要注意的是仍然是Alpha版。

        关于Inline Hook的背景知识这里不再阐述,我仅支持了相对简单的函数首指令改写方案,原则上也支持函数任意位置HOOK(需自行处理堆栈),不支持短函数,也暂不支持AArch32 state。

        由于arm64-v8a指令集都是固定的32位,指令地址也因而是4字节对齐,相比变长指令处理起来会相对容易,但是没办法直接操作PC寄存器,A64处理跳转起来会比A32和T32繁琐。

        首先是计算需要覆盖的指令数,我的方案是计算目标函数和转接函数的距离,然后决定是使用 B直接转跳 还是 BR寄存器绝对转跳,其中B只会影响一条指令,是比较优的路径,但是它的转跳范围不能超过0b00001111111111111111111111111100;BR需要占用4-5条指令(就我目前的方案而言,即把地址直接写在代码里),因为我们需要设法把地址加载到寄存器,这就需要类似下面的操作,然后为什么是5条指令?因为对于LOAD操作我们需要考虑内存对齐,于是可能需要一条额外的NOP指令来填充。

0x00000000  LDR X, #0x4
0x00000004  BR X
0x00000008  DCD ...
0x0000000C  DCD ...
        上面X是64位寄存器,显而易见这会造成寄存器污染,所以我们需要挑一个尽可能不被使用的寄存器,也就不需要去设法保护它,这里我选了X17,其实X16也行。

        接着就是重头戏指令修复。把覆盖掉的指令一条条复制到我们的跳板Trampoline里,并对所有含PC-relative address操作数的指令进行重定位。至于哪些指令需要被修复,你可以查阅armv8a指令手册(我上传了份从ARM官网下载的pdf,应该是最新修订的,http://download.csdn.net/download/rrrfff/9992241) 或者 在线文档http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.100069_0608_00_en/index.html。

         大概有以下几类指令,分别由__fix_branch_imm、__fix_cond_comp_test_branch、__fix_loadlit、__fix_pcreladdr完成具体修复,具体可以去看源码,不过可能会比较乱,当然了这玩意后期基本不需要什么维护,也别想着以后ARM128还能用:

// branch_imm
b
bl
// compbranch
cbz
cbnz
// condbranch
b.c
// loadlit
ldr
ldr
ldrsw
prfm
// pcreladdr
adr
adrp
// testbranch
tbz
tbnz
// condbranch
beq
bne
bcs
bhs
bcc
blo
bmi
bpl
bvs
bvc
bhi
bls
bge
blt
bgt
ble
        其中值得一提的大概有几点,一是__fix_loadlit,因为涉及到LOAD操作,自然要考虑内存对齐,然而LOAD的目的寄存器可能是32、64甚至128位,所以需要考虑的情形就有3种;二是对于BL这种带链接跳转,如果转化成BR需要先把返回地址写到LR(X30)里;此外就是代码中引用的地址可能就在我们覆盖的范围内,这种情况很少,但是还是简单处理了下,对相应地址进行了修复,参考process_fix_map。

你可能感兴趣的:(Android,C/C++)