Android socket_android hook技术

Android socket_android hook技术什么是InlineHookInlineHook即内部跳转Hook,通过替换函数开始处的指令为跳转指令,使得原函数跳转到自己的函数,通常还会保留原函数的调用接口。与GOT表Hook相比,InlineHook具有更广泛的适用性,几乎可以Hook任何函数,不过其实现更为复杂,考虑的情况更多,并且无法对一些太短的函数Hook。其基本原理请参阅网上其他资料。需要解决的问题1.Arm模式与Thumb模

什么是Inline Hook

Inline Hook即内部跳转Hook,通过替换函数开始处的指令为跳转指令,使得原函数跳转到自己的函数,通常还会保留原函数的调用接口。与GOT表Hook相比,Inline Hook具有更广泛的适用性,几乎可以Hook任何函数,不过其实现更为复杂,考虑的情况更多,并且无法对一些太短的函数Hook。
其基本原理请参阅网上其他资料。

需要解决的问题

1.Arm模式与Thumb模式的区别
2.跳转指令的构造
3.PC相关指令的修正
4.线程处理
5.其他一些细节

Arm模式与Thumb模式的区别

arm版本7及以上的体系中,其指令集分为ARM指令集和Thumb指令集。Arm指令为4字节对齐,每条指令长度均为32位;Thumb指令为2字节对齐,又分为Thumb16、Thumb32,其中Thumb16指令长度为16位,Thumb32指令长度为32位。

在对一个函数进行Inline Hook时,首先需要判断当前函数指令是Arm指令还是Thumb指令,指令使用目标地址值的bit[0]来确定目标地址的指令类型。bit[0]的值为1时,目标程序为Thumb指令;bit[0]值为0时,目标程序为ARM指令。其相关实现代码为以下宏:

// 设置bit[0]的值为1
#define SET_BIT0(addr) (addr | 1)
// 设置bit[0]的值为0
#define CLEAR_BIT0(addr) (addr & 0xFFFFFFFE)
// 测试bit[0]的值,若为1则返回真,若为0则返回假
#define TEST_BIT0(addr) (addr & 1)
只听到从架构师办公室传来架构君的声音:
门外无人问落花,绿阴冉冉遍天涯。有谁来对上联或下联?

跳转指令的构造

跳转指令主要分为以下两种:

1.B系列指令:B、BL、BX、BLX
2.直接写PC寄存器

Arm的B系列指令跳转范围只有4M,Thumb的B系列指令跳转范围只有256字节,然而大多数情况下跳转范围都会大于4M,故我们采用LDR PC, [PC, ?]构造跳转指令。另外Thumb16指令中并没有合适的跳转指令,如果单独使用Thumb16指令构造跳转指令,需要使用更多的指令完成,并且在后续对PC相关指令的修正也更加繁琐,故综合考虑下,决定放弃对ARMv5的支持。

另外,Arm处理器采用3级流水线来增加处理器指令流的速度,也就是说程序计数器R15(PC)总是指向“正在取指”的指令,而不是指向“正在执行”的,即PC总是指向当前正在执行的指令地址再加2条指令的地址。比如当前指令地址是0×8000, 那么当前pc的值,在thumb下面是0×8000 + 2 2, 在arm下面是0×8000 + 4 2。
对于Arm指令集,跳转指令为:

此代码由Java架构师必看网-架构君整理
LDR PC, [PC, #-4] addr

LDR PC, [PC, #-4]对应的机器码为:0xE51FF004,addr为要跳转的地址。该跳转指令范围为32位,对于32位系统来说即为全地址跳转。
对于Thumb32指令集,跳转指令为:

LDR.W PC, [PC, #0]
addr

LDR.W PC, [PC, #0]对应的机器码为:0x00F0DFF8,addr为要跳转的地址。同样支持任意地址跳转。
其相关实现代码为:

此代码由Java架构师必看网-架构君整理
// Arm Mode if (TEST_BIT0(item->target_addr)) { int i; i = 0; if (CLEAR_BIT0(item->target_addr) % 4 != 0) { ((uint16_t *) CLEAR_BIT0(item->target_addr))[i++] = 0xBF00; // NOP } ((uint16_t *) CLEAR_BIT0(item->target_addr))[i++] = 0xF8DF; ((uint16_t *) CLEAR_BIT0(item->target_addr))[i++] = 0xF000; // LDR.W PC, [PC] ((uint16_t *) CLEAR_BIT0(item->target_addr))[i++] = item->new_addr & 0xFFFF; ((uint16_t *) CLEAR_BIT0(item->target_addr))[i++] = item->new_addr >> 16; } // Thumb Mode else { ((uint32_t *) (item->target_addr))[0] = 0xe51ff004; // LDR PC, [PC, #-4] ((uint32_t *) (item->target_addr))[1] = item->new_addr; }

首先通过TEST_BIT0宏判断目标函数的指令集类型,其中若为Thumb指令集,多了下面一个额外处理:

if (CLEAR_BIT0(item->target_addr) % 4 != 0) {
    ((uint16_t *) CLEAR_BIT0(item->target_addr))[i++] = 0xBF00;  // NOP
}

对bit[0]的值清零,若其值4字节不对齐,则添加一个2字节的NOP指令,使得后续的指令4字节对齐。这是因为在Thumb32指令中,若该指令对PC寄存器的值进行了修改,则该指令必须是4字节对齐的,否则为非法指令。

ARM HOOK 图解
原理图

HOOK流程图

这里写图片描述
PC相关指令的修正

架构君码字不易,如需转载,请注明出处:https://javajgs.com/archives/147455
0
   

发表评论