Android inline hook手记[转载]

原网址:http://blog.dbgtech.net/blog/?p=51

作者:NetRoc

Android inline hook手记

说到Inline hook,了解这个词的同志们都应该知道,无非是修改目标函数处的指令,跳转到自己的函数,并且提供调用原函数的stub,即可完成整个流程。但是在ARM下面情况和我们熟悉的x86有所不同。ARM芯片的运行状态分为arm和thumb两种模式,分别有不同的指令集,arm指令为定长32位,thumb指令为定长16位(thumb-2中进行了扩展,可以使用32位thumb指令)。同一段代码中可以混用两套指令集,通过一些带有interworking功能的跳转或者load指令可以在两种模式间切换。做ARM下的inline,首先遇到的就是指令模式的问题。另外,ARM架构下,CPU也具有分开的指令缓存和数据缓存,类似x86下的DTLB和ITLB。但是在实现过程中发现,arm的缓存作用非常明显,而且刷新机制不太确定,因此自修改代码需要经常主动控制缓存的刷新。这一点,可以通过NDK的API cacheflush实现。

下面简单说说一些主要问题:

  • 关于页保护

    这一点对于熟悉Linux编程的同志们应该不是问题,mprotect修改为PROT_READ | PROT_WRITE | PROT_EXEC即可。页面大小可以通过包含ndk下面<asm/page.h>文件,里面定义的一系列宏用于获得页面大小和进行对齐运算。

  • 关于模式转换和跳转

    Arm下主要的分支指令如BX,BLX等,都可以切换指令模式。详见arm的用户手册。这里主要讨论模式的选择和切换时机。只有一个问题需要注意,arm处理器执行时,由于流水线的关系,会预取两条指令,因此当前指令取到的pc值,始终是之后第三条指令的地址。比如当前指令地址是0x8000,那么当前pc的值,在thumb下面是0x8000 + 2 * 2, 在arm下面是0x8000 + 4 * 2。

    由于运行时我没有找到简便的办法能够确切知道被hook的目标函数指令集,所以这个问题留给了hook的使用者来决定。Hook之前应通过逆向工具获知所有目标函数是arm还是thumb指令。

    如果要根据目标函数指令集的不同而对hook函数采用不同的 编译选项,显然是一件麻烦的事情。而arm模式的指令由于单条指令包含的语义更多,是我们的首选。因此可以考虑主仅使用arm指令编译hook函数,而在跳转的同时切换到arm模式。

    关于跳转插入的指令方面,由于arm指令带立即数的跳转范围只有4M,thumb的跳转范围只有256字节。所以首选ldr pc,xxxx指令来实现。对于arm指令的目标,这个指令很容易选择。如下:

    ldr pc, [pc,#-4]

    32位跳转绝对地址

    指令为单个32位数字:0xE51FF004。

    但是thumb模式下的16位ldr指令没有办法向pc中load,选择就很成问题。如果单纯使用16位thumb指令的话,跳转部分需要占用大量字节数,而因为arm下面编译器常常使用pc的值作为基址来计算地址,被搬动过的指令中就极有可能存在这种指令。搬动过后的代码中就必须对这部分指令进行修正,而又由于thumb所能够支持的立即数很小,跳转范围也很小,这种修正往往非常麻烦,需要用几条同等指令来替换一条指令。经过考虑,还是决定放弃对ARMv5的支持,直接使用ARMv6T2之后支持的thumb-2指令集。thumb-2支持32位thumb指令,也支持ldr以pc为目标寄存器:

    ldr.w pc,[pc,#0]

    32位跳转绝对地址

    指令为单个32位数字:0x00F0DFF8

    所有需要跳转的地址,需要注意的是bit0的处理。如果bit0为1,跳转后会切换到thumb指令模式,如果bit0为0,会切换至arm模式。当目标为arm的时候,我们不需要特殊处理,编译器会处理地址的计算。但是当目标为thumb的时候,从hook指令跳转到hook函数,以及调用原始函数的时候,都需要注意地址bit0的处理。

  • 关于搬出来的原始指令

    按照win32下Detours库的实现方式,被HOOK函数的前面几条指令,会搬到一个trampoline中,并在这些指令后添加跳转至原代码后续部分的指令。在搬动过程中,需要对被移动的指令进行地址修正。在处理ARM平台inline的过程中也需要作这样的工作。但是实际上在处理的时候会发现,要做到这一点是非常困难的。ARM下常常会生成下面这种将pc作为地址参照的指令块

    而由于arm平台寻址范围较小,编译器通常选择将数据和指令在内存中的存放混杂在一起。thumb模式下,由于指令中能包含的立即数非常小,这种问题会表现得异常突出,修正的时候也常常一条指令被拉长为数条。因此代码修正会有非常大的工作量。这部分问题由于太消耗时间,我也仅仅是对arm下的inline进行研究性实现,也就没有管这个问题了。实际项目如果要用到hook,这个部分花费的时间应该比单纯hook跳转的实现要大得多。在不考虑并发和效率的情况下,当hook函数中要调用原函数时,可以考虑临时恢复hook,并在调用完成后再次hook来解决。但是始终是相当不优雅的实现。

  • 关于线程处理

    修改hook目标的指令时,和x86平台下一样,也需要注意有可能某些线程刚好执行到被修改的指令中的问题。Win32下可以枚举线程并修改context到被搬迁的指令中去。但是Linux内核系统下很难进行线程的控制。估计可以采用接管信号处理,并向进程内所有线程调用pthread_kill来实现。

时间: 2024-11-08 20:58:35

Android inline hook手记[转载]的相关文章

android inline hook

最近终于沉下心来对着书把hook跟注入方面的代码敲了一遍,打算写几个博客把它们记录下来. 第一次介绍一下我感觉难度最大的inline hook,实现代码参考了腾讯GAD的游戏安全入门. inline hook的大致流程如下: 首先将目标指令替换为跳转指令,跳转地址为一段我们自己编写的汇编代码,这段汇编代码先是执行用户指定的代码,如修改寄存器的值,然后执行被替换掉的原指令2,最后再跳转回原指令3处,恢复程序的正常运行. 为了避开注入过程,我们通过hook自己进程加载的动态连接库进行演示. 1.实现

Android Art Hook 技术方案

Android Art Hook 技术方案 by 低端码农 at 2015.4.13 www.im-boy.net 0x1 开始 Anddroid上的ART从5.0之后变成默认的选择,可见ART的重要性,目前关于Dalvik Hook方面研究的文章很多,但我在网上却找不到关于ART Hook相关的文章,甚至连鼎鼎大名的XPosed和Cydia Substrate到目前为止也不支持ART的Hook.当然我相信,技术方案他们肯定是的,估计卡在机型适配上的了. 既然网上找不到相关的资料,于是我决定自己

android 5 HOOK 技术研究之 ADBI 项目

简介 adbi 是一个android平台的二进制注入框架,源码开放在github上 :  ADBI 项目 ,从hook技术的分类来说,其属于so注入+inline hook, 这种方式的套路是:基于linux系统的ptrace机制,attach一个目标进程,注入一个动态链接库进入目标进程的地址空间,然后用so里边的函数地址替换目标进程地址空间里原有的函数地址(老的函数地址一般也需要保存起来). 源码目录 hijack:  可执行程序,用于注入一个so到目标进程 libbase:  注入库,提供h

Ring3 下 API Inline Hook 优化方案探索与实现

??本博文由CSDN博主zuishikonghuan所作,版权归zuishikonghuan所有,转载请注明出处:http://blog.csdn.net/zuishikonghuan/article/details/51302024 ?? 以前写过两篇"[Win32] API Hook(1)在32/64位系统上的实现"博客,介绍并给出了 API inline hook 代码,如下: ????blog.csdn.net/zuishikonghuan/article/details/47

Cydia Substrate框架Android so hook分析

最近需要用到Android so hook,于是分析了一下比较流行的Cydia Substrate框架 CydiaSubstrate框架的核心函数是MSHOOKFunction,官方使用说明如下: 现在Android 默认编译出来的都是thumb指令集的,就分析一下这个模式下的HOOK吧. 在使用MSHOOKFunction HOOK前,先用IDA attach到进程先看下准备HOOK的函数,前面18个字节的二进制指令如下: 52ABF480 30 B5       PUSH          

Android Native Hook技术(一)

原理分析 ADBI是一个著名的安卓平台hook框架,基于 动态库注入 与 inline hook 技术实现.该框架主要由2个模块构成:1)hijack负责将so注入到目标进程空间,2)libbase是注入的so本身,提供了inline hook能力. 源码目录中的example则是一个使用ADBI进行hook epoll_wait的示例. hijack hijack实现动态库注入功能,通过在目标进程插入dlopen()调用序列,加载指定so文件.要实现这个功能,主要做两件事情: 获得目标进程中d

使用cydia substrate 来进行android native hook

? cydia不仅可以hook java代码,同样可以hook native代码,下面举一个例子来进行android native hook 我是在网上找到的supermathhook这个项目,在他基础上修改的,本来是为了仓促应对阿里的ctf 这个项目位置: 这个项目是用来hook jni 代码的,而我是用来hook dvmDexFileOpenPartial这个函数的,所以必须使用 Mshookfunction这个函数,这个函数在libsubstrate.so中,自己去官网下载就可以了. 接下

iOS冰与火之歌番外篇 - 在非越狱手机上进行App Hook(转载)

作者简介:郑旻(花名蒸米),阿里巴巴移动安全部门资深安全工程师,香港中文大学移动安全(Android & iOS)方向博士,曾在腾讯.百度以及硅谷的FireEye实习.在博士期间发表了多篇移动安全方向的论文(BlackHat.AsiaCCS等),去过10多个不同的国家做论文演讲. 曾帮助Apple公司修复了多处iOS安全问题,并且Apple在官网表示感谢.同时也是蓝莲花战队和Insight-labs的成员,在业余时间多次参加信息安全竞赛(Defcon.AliCTF.GeekPwn等),并取得优异

Inline Hook

本文讲 用inline hook的方式修改NtOpenKey函数的一个小例子, 自己的学习笔记 hook 计算机里面一般是指 挂钩某函数,也可以是替换掉原来的函数. inline hook 是直接在以前的函数替里面修改指令,用一个跳转或者其他指令来达到挂钩的目的. 这是相对普通的hook来说,因为普通的hook只是修改函数的调用地址,而不是在原来的函数体里面做修改.一般来说 普通的hook比较稳定使用. inline hook 更加高级一点,一般也跟难以被发现.所以很多人比如病毒制作者都比较推崇