Android的inline hook

21 篇文章 0 订阅
11 篇文章 1 订阅

arm平台与其他平台的inline hook原理一致,均为函数arm字节码替换
由于指令集的特点,arm平台的inline hook较为复杂:
1、存在arm指令集和thumb指令集
2、无法单纯使用B指令直接跳转,因为b指令跳转范围优先
3、存在literal指令,与当前PC值相关,需要对指令进行修正

以arm指令集作为hook实例
由于arm架构特性,每次修改代码需要刷新cache,因为指令icache和数据dchche是分开的。

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)

跳转指令

因为b系列指令跳转范围有限,所以我们使用LDR PC, [PC, ?]构造跳转指令

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

对于Arm指令集,跳转指令为:

LDR PC, [PC, #-4]
addr

对应的机器码为:0xE51FF004,addr为要跳转的地址。该跳转指令范围为32位,对于32位系统来说即为全地址跳转。

对于Thumb32指令集,跳转指令为:

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

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

注意arm要4字节对齐,thumb要2字节对齐。不是对齐的要填充nop对齐。

// thumb Mode
if (TEST_BIT0(item->target_addr)) {
	int i;

	i = 0;

//首先通过TEST_BIT0宏判断目标函数的指令集类型,其中若为Thumb指令集,多了下面一个额外处理,对bit[0]的值清零,若其值4字节不对齐,则添加一个2字节的NOP指令,使得后续的指令4字节对齐。这是因为在Thumb32指令中,若该指令对PC寄存器的值进行了修改,则该指令必须是4字节对齐的,否则为非法指令。
	if (CLEAR_BIT0(item->target_addr) % 4 != 0) {
		((uint16_t *) CLEAR_BIT0(item->target_addr))[i++] = 0xBF00;  // NOP
	}
//下面这4行,前2行是LDR.W PC, [PC, #0]对应的机器码为:0x00F0DFF8,后两行是addr,要跳转的地址
	((uint16_t *) CLEAR_BIT0(item->target_addr))[i++] = 0xF8DF;//litterending
	((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;
}
// arm Mode
else {
	((uint32_t *) (item->target_addr))[0] = 0xe51ff004;	// LDR PC, [PC, #-4]
	((uint32_t *) (item->target_addr))[1] = item->new_addr;
}

然后就是该内存属性为可写,刷新cache

mprotect((void*)(target_addr & ~4095), 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC);//改权限,加写
	
	
	clearcache((void*)target_addr, (void*)(target_addr + 4));

后续如果比如需要修正PC,因为如果hook替换函数要在我们代码里写原来被hook覆盖代码使用到了pc相关内容,需要修复,可以参考博客

http://ele7enxxh.com/Android-Arm-Inline-Hook.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值