Android下面有很多Hook的思路,如果要获取执行到某地址的寄存器信息或者某地址的访问者信息,那么异常Hook将会是一个较优的手段,本章节会介绍Android平台下异常Hook的方法,包括原理,流程和实际的代码。
1.1 实现原理
利用SIGILL异常去做Hook操作,具体可以是对我们想要的监控的地址设一个非法指令,然后当程序执行到非法指令位置时系统会回调我们预先设定好的异常处理函数,我们在这个异常处理函数里面恢复地址的原指令,获取context信息,然后打印寄存器信息即可。
下面列出各指令集的非法指令:
其实,一般我们为了长时间对某个地址监控,我们恢复目标地址的指令后还需要找时机去改目标地址,为下一次获取信息做准备。那么我们可以在获取到异常后,对目标地址的下一条指令做异常Hook操作,然后在下一个异常来临的时候,在异常处理函数中恢复当前异常指令并重新对目标地址写非法指令,以等待下一次目标地址被调用时获取我们想要的信息。
事实上,我们会通过sigaction这个API来设置SIGILL信号的异常处理函数ExceptionHookHandler。然后在这个函数里面判断到底是目标地址的异常还是目标地址的下一条指令异常,从而根据上面的描述处理不同的逻辑。而到了这里,会出现一个问题,arm指令间的地址都是相差 4 ,所以可以直接取当前偏移 +4去获取下一个地址位置,那么thumb2指令集呢?指令长度的不同令人不知道下一条指令地址是偏移 +2 还是 +4,这就需要去解析当前的指令了。
下面提供一个表格,Thumb2 编码表:
有了这个表,就可以解析出当前指令的长度了,即只有当opcode的[15:13]位为111且[12:11]不为00的情况下,这个指令是32位指令,采用偏移 +4 策略。
其他需要注意的就是写非法指令的时候需要修改对代码段增加写权限。
1.2 实现流程
图1-1 异常Hook流程图
1.3 实现代码
实现的入口函数如下,首先,构建一个sigaction结构体数据,这个结构体选好参数,填入处理函数的函数,然后传到sigaction函数里面,再调用自定义函数WriteillegalInstructionAndSaveOpcode对目标地址做非法写,然后保存原opcode。
下面看看函数ExceptionHookHandler的实现,这个函数会获取第三个参数传来的context,做判断,判断是否为目标地址,如果是的话,打印寄存器信息,恢复指令;如果是目标地址下面一个地址的信息,也恢复下当前opcode,然后重新往目标地址写非法指令,为下一次监听目的地址被执行而Hook。
再来看看WriteillegalInstructionAndSaveOpcode这个函数的实现过程,这个函数会通过地址最低位是否为1来判断是thumb指令或是arm指令,然后修改地址权限,针对不同指令集写不同的非法opcode。
恢复地址的函数ResumetheOrgInstruction大同小异,只不过是把原来被篡改成非法opcode的地址修改回原opcode,这里就不贴代码了。
最后这里会说说getCurAddrInstructionLength这个函数,可以根据之前在实现原理里面提到的方法解析opcode中[15:13]和[12:11]的位去判断当前指令是32bit还是16bit,里面增加了一个断言,只有thumb指令才这样去判断,这个函数返回的是当前指令的长度。 **1.4 ****小结 ** 本文介绍了异常Hook的原理,并通过流程图和代码直观地描述和说明整个异常Hook的执行过程。