C/C++知识点之android 内联 hook
小标 2019-04-01 来源 : 阅读 1645 评论 0

摘要:本文主要向大家介绍了C/C++知识点之android 内联 hook,通过具体的内容向大家展示,希望对大家学习C/C++知识点有所帮助。

本文主要向大家介绍了C/C++知识点之android 内联 hook,通过具体的内容向大家展示,希望对大家学习C/C++知识点有所帮助。

C/C++知识点之android 内联 hook

先回顾下 x86 下的内联 hook.
1.原理是找到你要 hook 的地址。
2.保存这个地址原来的数据。(这里要保存至少 5 个字节的数据因为一个 call指令为 5 个字节
3.把这个地址修改成 call 0Xxxxx(5 个字节 ) 也就是对应 opcode 为 E9 0Xxxxx  后面四个字节为一个函数地址
4.填充0Xxxxx  公式为 自己的函数地址-当前地址-5
5.把原来的那个 5 个字节的 opcode 还原重新从 hook点开始执行
arm  下
第一点有 俩种模式Arm模式与Thumb模式
在Arm版本7及以上的体系中,其指令集分为Arm指令集和Thumb指令集。Arm指令为4字节对齐,每条指令长度均为32位;Thumb指令为2字节对齐,又分为Thumb16、Thumb32,其中Thumb16指令长度为16位,Thumb32指令长度为32位。
第二点函数调用指令为:
B系列指令:B、BL、BX、BLX
PC寄存器 相当于 eip
第三点不这俩种模式流水线级数不同。arm一般为 3 级 。也就是说在 arm模式下 pc 指向下一条指令的向一条。因为 hook是 pc 要回退 4 个字节(4字节对齐)
因此对应:


LDR PC, [PC, #-4]
addr


而Thumb(32位)不用回退


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


因为也就相当于 LDR.W PC, [PC, #0]/LDR PC, [PC, #-4] 对应x86 中的 call 对应 opcode
call : E9
LDR.W PC, [PC, #0]:0x00F0DFF8  (LDR.W强制以 4 字节)
LDR PC, [PC, #-4]   :0xE51FF004
后面就与 x86 方式一样了修改地址:


x86 
call 0Xxxxx
arm
LDR PC, [PC, #-4]
Thumb(32位)
addr
LDR.W PC, [PC, #0]
addr


最后要注意一个非常容易忽略的点就是地址一般为 4 个字节,也就是说Thumb(32位)的每条指令是 2 个字节对齐的因此只能 2 个字节的写。而 arm 每条指令为 4 字节对齐。因此应该考虑有时候只有 2 字节,也就必须后俩个字节用 nop填充。因为指令没有 4 字节对齐为非法指令。
也就是写法为:


//开始 hook
//arm 方式就一种
//thumb 方式有俩种  一种是转成arm 再 hook  一种是直接 hook
static void doInlineHook(struct inlineHookItem *item)
{
    //修改页属性
    mprotect((void *) PAGE_START(CLEAR_BIT0(item->target_addr)), PAGE_SIZE * 2, PROT_READ | PROT_WRITE | PROT_EXEC);

    if (item->proto_addr != NULL) {
        *(item->proto_addr) = TEST_BIT0(item->target_addr) ? (uint32_t *) SET_BIT0((uint32_t) item->trampoline_instructions) : item->trampoline_instructions;
    }
    //Arm指令为4字节对齐,每条指令长度均为32位;Thumb指令为2字节对齐,
    // 又分为Thumb16、Thumb32,其中Thumb16指令长度为16位,Thumb32指令长度为32位。
    //这里要注意的是:
    //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
    //
    //LDR PC, [PC, #-4]对应的机器码为:0xE51FF004,addr为要跳转的地址。
    //该跳转指令范围为32位,对于32位系统来说即为全地址跳转。
    //对于Thumb32指令集,跳转指令为:
    //
    //LDR.W PC, [PC, #0]  不要回退刚好指向下一条
    //addr
    //
    //LDR.W PC, [PC, #0]对应的机器码为:0x00F0DFF8,addr为要跳转的地址。同样支持任意地址跳转。
    //thumb 模式(Thumb32指令集)为俩字节对齐
    if (TEST_BIT0(item->target_addr)) {
        int i;
        i = 0;
        //判断是否为4 字节对齐 用NOP填充
        if (CLEAR_BIT0(item->target_addr) % 4 != 0) {
            ((uint16_t *) CLEAR_BIT0(item->target_addr))[i++] = 0xBF00;  // NOP
        }
        //LDR伪指令 LDR.W 强制32位
        //俩个字节为一组
        //LDR.W PC, [PC, #0]对应的机器码为:0x00F0DFF8  每次一个四字节要分为俩个2 字节
        ((uint16_t *) CLEAR_BIT0(item->target_addr))[i++] = 0xF8DF;
        ((uint16_t *) CLEAR_BIT0(item->target_addr))[i++] = 0xF000; // LDR.W PC, [PC]
        //一个四字节地址  同样分为俩个2 字节
        //取低四位
        ((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 模式  指令为4字节对齐
    else {
        //四个字节为一组
        ((uint32_t *) (item->target_addr))[0] = 0xe51ff004; // LDR PC, [PC, #-4]
        //下一条4字节地址
        ((uint32_t *) (item->target_addr))[1] = item->new_addr;
    }

    mprotect((void *) PAGE_START(CLEAR_BIT0(item->target_addr)), PAGE_SIZE * 2, PROT_READ | PROT_EXEC);

    item->status = HOOKED;

    cacheflush(CLEAR_BIT0(item->target_addr), CLEAR_BIT0(item->target_addr) + item->length, 0);
}

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标编程语言C/C+频道!

本文由 @小标 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程