基于xposed框架对native层函数进行hook的方法、装置及电
子装置
技术领域
本发明涉及计算机技术领域,具体而言,涉及一种基于xposed框架对native层函数进行hook的方法、装置及电子装置。
背景技术
现有技术中,安卓的hook技术有Plt-Got替换hook技术、Xposed框架hook技术和substrate等native层内联hook框架。其中,Plt-Got替换hook技术由于对应用内存直接操作,只适用于hook应用自身native层函数,并不适用对全局(安卓系统中全部应用)的hook;Xposed框架仅在Java层hook,缺少native层hook的相关功能;而substrate等native层内联hook框架则兼容性、稳定性不高。相比较pc端的hook技术,安卓的hook技术还不够成熟,难以兼顾控制范围、稳定性和兼容性。
针对相关技术中存在的上述问题,目前尚未发现有效的解决方案。
发明内容
本发明实施例提供了一种基于xposed框架对native层函数进行hook的方法、装置及电子装置,以至少解决现有技术中xposed框架无法在native层hook的技术问题。
根据本发明的一个实施例,提供了一种基于xposed框架对native层函数进行hook的方法,包括:利用xposed框架的目标接口捕获应用被加载的时机;在应用被加载时,利用应用的类加载器反射查找用于加载so库的目标函数;利用目标函数加载用于hook目标native层函数的目标so库。
进一步地,应用的信息包括应用的apk包名,根据应用的信息判断应用是否为目标应用,包括:利用应用的apk包名与目标应用的包名进行匹配,以判断应用是否为目标应用。
进一步地,在利用应用的类加载器反射查找用于加载so库的目标函数之前,该方法还包括:利用目标接口获取被加载的应用的信息;根据应用的信息判断应用是否为目标应用,其中,在目标应用被加载时,利用目标应用的类加载器反射查找java.lang.system.load函数。
进一步地,目标so库在被加载之后,通过操作应用的内存,将got表中目标native层函数的地址替换为hook函数的地址。
根据本发明的另一个实施例,提供了一种基于xposed框架对native层函数进行hook的装置,包括:捕获模块,用于利用xposed框架的目标接口捕获应用被加载的时机;查找模块,用于在应用被加载时,利用应用的类加载器反射查找用于加载so库的目标函数;加载模块,用于利用目标函数加载用于hook目标native层函数的目标so库。
进一步地,该装置还包括:替换模块,用于目标so库在被加载之后,通过操作应用的内存,将got表中目标native层函数的地址替换为hook函数的地址。
进一步地,该装置还包括:获取模块,用于在利用所述应用的类加载器反射查找用于加载so库的目标函数之前,利用所述目标接口获取被加载的所述应用的信息;判断模块,用于根据所述应用的信息判断所述应用是否为目标应用,其中,在所述目标应用被加载时,利用所述目标应用的类加载器反射查找java.lang.system.load函数。
进一步地,应用的信息包括应用的apk包名,判断模块包括:匹配单元,用于利用应用的apk包名与目标应用的包名进行匹配,以判断应用是否为目标应用。
根据本发明的又一个实施例,还提供了一种存储介质,所述存储介质中存储有计算机程序,其中,所述计算机程序被设置为运行时执行上述任一项方法实施例中的步骤。
根据本发明的又一个实施例,还提供了一种电子装置,包括存储器和处理器,所述存储器中存储有计算机程序,所述处理器被设置为运行所述计算机程序以执行上述任一项方法实施例中的步骤。
通过本发明,在监听到应用加载时,通过应用的类加载器反射查找加载so库的函数,注入所需的so库,以利用so库实现在native层hook函数的效果,并且,利用了xposed框架的全局hook能力,通过xposed框架对孵化器进程流程的改动实现了对所有应用的hook,进而实现了针对native层的全局hook,提高了xposed框架在native层的适用性,解决了现有技术中xposed框架无法在native层hook的技术问题。
附图说明
此处所说明的附图用来提供对本发明的进一步理解,构成本申请的一部分,本发明的示意性实施例及其说明用于解释本发明,并不构成对本发明的不当限定。在附图中:
图1是根据本发明实施例的一种可选的基于xposed框架对native层函数进行hook的方法的流程图;
图2是根据本发明实施例的另一种可选的基于xposed框架对native层函数进行hook的方法的流程图;
图3是根据本发明实施例的基于xposed框架对native层函数进行hook的装置的示意图。
具体实施方式
为了使本技术领域的人员更好地理解本申请方案,下面将结合本申请实施例中的附图,对本申请实施例中的技术方案进行清楚、完整地描述,显然,所描述的实施例仅仅是本申请一部分的实施例,而不是全部的实施例,在不冲突的情况下,本申请中的实施例及实施例中的特征可以相互组合。基于本申请中的实施例,本领域普通技术人员在没有做出创造性劳动前提下所获得的所有其他实施例,都应当属于本申请保护的范围。
需要说明的是,本申请的说明书和权利要求书及上述附图中的术语“第一”、“第二”等是用于区别类似的对象,而不必用于描述特定的顺序或先后次序。应该理解这样使用的数据在适当情况下可以互换,以便这里描述的本申请的实施例能够以除了在这里图示或描述的那些以外的顺序实施。此外,术语“包括”和“具有”以及他们的任何变形,意图在于覆盖不排他的包含,例如,包含了一系列步骤或单元的过程、方法、系统、产品或设备不必限于清楚地列出的那些步骤或单元,而是可包括没有清楚地列出的或对于这些过程、方法、产品或设备固有的其它步骤或单元。
实施例1
本实施例提供了一种基于xposed框架对native层函数进行hook方法,可以应用于客户端侧,其中,客户端可以运行中移动终端、手持终端或类似的运算设备之中。运行在不同的运算设备仅是方案在执行主体上的差异,本领域人员可预见在不同运算设备中运行能够产生相同的技术效果。可选的,本发明实施例提供的方法可以通过xposed框架模块形式实现。
本实施例提供的基于xposed框架对native层函数进行hook方法,如图1所示,包括如下步骤:
步骤101,利用xposed框架的目标接口捕获应用被加载的时机。
本发明实施例需要应用在安装有xposed框架的安卓系统中,在执行步骤101之前,需要在安卓系统中刷入(安装)xposed框架,以利用xposed框架所提供的功能。
具体的,xposed框架提供了用于捕获应用被加载的时机的目标接口(IXposedHookLoadPackage接口),该接口在应用被加载的时候调用,以用于对应用进行hook。本发明实施例以目标接口作为hook入口,开始执行步骤102~步骤103的流程。
xposed框架通过更改安卓系统中的源码app_proccess中的app_main.c,以对zygote孵化器的文件进行替换。在安卓系统中每个apk(安卓安装包)在启动过程中,都会分裂(或者说复制)一个新的zygote孵化器进程,通过对安卓系统中zygote孵化器文件的替换,实现对zygote孵化器进程的执行流程的更改,使得每个apk启动之后的孵化器进程执行的流程为xposed框架所定义的流程,从而使xposed框架具有对全局(整个安卓系统中)全部应用进行hook的能力。
安卓系统正常的源码是通过AndroidRuntime::start()来启动com.android.internal.os.ZygotInit,而xposed框架更改后的代码,在调用com.android.internal.os.ZygotInit之前,需要执行xposed的替换代码de.rodv.android.xposed.XposedBridge。其中,de.rodv.android.xposed.XposedBridge和com.android.internal.os.ZygotInit是Java层的代码。其中,de.rodv.android.xposed.XposedBridge位于XposedBridge.java,在XposedBridge.java中,通过回调机制定义了函数hook前后调用相应的接口,包括IXposedHookLoadPackage接口。
在xposed框架的XposedBridge模块中实现了app_process模块中的一个关键c代码函数:
de_robv_android_xposed_XposedBridge_hookMethod_hookMethodNative,该函数用于更改dvmCallMethodV函数用来判断执行java和c代码执行流程的标志。在安卓系统中,需要通过执行函数dvmCallMethodV来判断代码是java层代码还是c层的代码,进而,在经过这个执行函数之后,根据判断结果确定是通过解释执行器执行还是通过可执行文件(Executable and Linkable Format,简称ELF)的方式执行,其中,Java层代码通过解释执行器执行,c层代码通过ELF方式执行。通过更改dvmCallMethodV函数用来判断执行java和c代码执行流程的标志,使得可以通过c指针跳转到了自定义的接口回调,也就是用户自定义的hook代码。
步骤102,在应用被加载时,利用应用的类加载器反射查找用于加载so库的目标函数。
xposed框架的hook是在Java层,为了对native层的函数进行hook,需要注入so库。so库是动态链接库,可以java.lang.system.load函数(目标函数)来加载so库。通过加载so库,可以在native层进行操作。本实施例中所加载的so库,用于基于全局偏移量表(GlobalOffset Table,简称got表)替换的原理实现对目标native层函数的hook。
其中,如果需要针对某个目标应用进行hook,可以在利用应用的类加载器反射查找用于加载so库的目标函数之前,利用目标接口获取被加载的应用的信息,并根据应用的信息判断应用是否为目标应用。应用的信息为apk包名,在根据应用的信息判断应用是否为目标应用时,利用应用的apk包名与目标应用的包名进行匹配,以判断应用是否为目标应用。
步骤103,利用目标函数加载用于hook目标native层函数的目标so库。
目标so库利用了PLT(Procedure Linkage Table,过程链接表)-got机制实现native层的hook。由于安卓底层是基于linux系统,linux的可执行文件格式为ELF,Android在底层的可执行文件也是ELF。plt-got机制进行hook的基础就是利用ELF文件的链接过程来实现的。
具体的,链接器在把应用所需要的共享库加载到内存后,并没有把共享库中的(native层)函数的地址写到got表中,而是延迟到函数的第一次调用时,才会对函数的地址进行定位。在第一次调用native函数时,步骤如下:
步骤11,进入puts@plt(plt表中的初始位置),执行plt表中的指令:跳转到got表中的指定位置。
步骤12,跳到got表中相应位置GOT[x],此时got表里保存的是pushl n的地址,实际上就是plt表中顺序执行下一步。
步骤13,执行plt表中pushl n,n为puts函数地址在got表中的位置,向堆栈中压入这个偏移量n的主要作用就是为了找到puts函数的符号名以及puts函数地址在got表项中所占的位置,以便在函数定位完成后将函数的实际地址写到这个位置。
步骤14,跳到plt表中PTL[0]的位置,执行将GOT[1](即共享库链表的地址)压栈。
步骤15,顺序执行plt表中的下一个位置PTL[1],具体指令为jmp GOT[2]。
步骤16,GOT[2]保存的是_dl_runtime_resolve函数的入口,执行_dl_runtime_resolve函数,该函数会找到puts函数的实际加载地址,并把它写到got表中,返回时就会进入puts函数内执行。
上述步骤是在第一次调用native函数时的执行过程,从第二次调用开始,GOT[x]中已保存有函数的地址,在步骤11之后,直接读取GOT[x]中的函数地址,并执行调用。
基于plt-got机制实现hook的具体方式为,将可执行文件ELF中Got表中的(需要替换的)地址进行替换,使得代码可以执行到需要的函数代码中。该机制而且对堆栈平衡几乎没有要求,这里便可以较稳定和高速的执行hook。
步骤103中so库基于上述plt-got机制来实现hook,在java.lang.system.load函数加载so库之后,初始化so库,将got表中的目标native层函数的地址替换为hook函数的地址。目标native函数是需要hook的函数。hook函数是预先配置的函数,通过c代码编写,用于实现需要执行的流程,可选的,hook函数可以在不改变目标native层函数原有流程的基础上,增加其他的流程。
本实施例通过步骤101~步骤103,在xposed框架的基础上,扩展了native层函数的hook功能,在监听到应用加载时,通过应用的类加载器反射查找加载so库的函数,注入所需的so库,以利用so库实现在native层hook函数的效果,并且,利用了xposed框架的全局hook能力,通过xposed框架对孵化器进程流程的改动实现了对所有应用的hook,进而实现了针对native层的全局hook,并且,对比现有技术中采用的substrate技术,本实施例的稳定性和运行速度有了很大的改善。
下面提供一个可选的实施方式的执行步骤,描述了在一个apk启动之后,针对于该apk运行时的native层函数的hook过程,如图2所示:
步骤21,通过回调方法handleLoadPackage监听到apk启动。
步骤22,获取apk包名,并进行过滤,确定与预先指定的需要hook的apk包名匹配。
步骤23,利用反射机制,查找加载so库的函数java.lang.system.load,并加载自定义的so库。
步骤24,操作应用的内存,对got表中需要hook的目标native层函数的地址进行替换,替换后的地址为hook函数的地址。
在应用运行时,如果需要对目标native层函数进行调用,实际调用的是hook函数。
其中,步骤21~步骤23是在Java层执行,步骤24以及应用运行时调用的native层函数是在native层执行。
一种可选的代码实现如下:
需要说明的是,在附图的流程图示出的步骤可以在诸如一组计算机可执行指令的计算机系统中执行,并且,虽然在流程图中示出了逻辑顺序,但是在某些情况下,可以以不同于此处的顺序执行所示出或描述的步骤。
通过以上的实施方式的描述,本领域的技术人员可以清楚地了解到根据上述实施例的方法可借助软件加必需的通用硬件平台的方式来实现,当然也可以通过硬件,但很多情况下前者是更佳的实施方式。基于这样的理解,本发明的技术方案本质上或者说对现有技术做出贡献的部分可以以软件产品的形式体现出来,该计算机软件产品存储在一个存储介质(如ROM/RAM、磁碟、光盘)中,包括若干指令用以使得一台终端设备(可以是手机,计算机,服务器,或者网络设备等)执行本发明各个实施例所述的方法。
实施例2
在本实施例中还提供了一种基于xposed框架对native层函数进行hook的装置,该装置用于实现上述实施例1及其优选实施方式,对于本实施例中未详述的术语或实现方式,可参见实施例1中的相关说明,已经进行过说明的不再赘述。
如以下所使用的术语“模块”,是可以实现预定功能的软件和/或硬件的组合。尽管以下实施例所描述的装置较佳地以软件来实现,但是硬件,或者软件和硬件的组合的实现也是可以被构想的。
图3是根据本发明实施例的基于xposed框架对native层函数进行hook的装置的示意图,如图3所示,该装置包括捕获模块10,查找模块20和加载模块30。
其中,捕获模块用于利用xposed框架的目标接口捕获应用被加载的时机;查找模块用于在应用被加载时,利用应用的类加载器反射查找用于加载so库的目标函数;加载模块用于利用目标函数加载用于hook目标native层函数的目标so库。
可选的,该装置还包括:替换模块,用于目标so库在被加载之后,通过操作应用的内存,将got表中目标native层函数的地址替换为hook函数的地址。
可选的,该装置还包括:获取模块,用于在利用所述应用的类加载器反射查找用于加载so库的目标函数之前,利用所述目标接口获取被加载的所述应用的信息;判断模块,用于根据所述应用的信息判断所述应用是否为目标应用,其中,在所述目标应用被加载时,利用所述目标应用的类加载器反射查找java.lang.system.load函数。
可选的,应用的信息包括应用的apk包名,判断模块包括:匹配单元,用于利用应用的apk包名与目标应用的包名进行匹配,以判断应用是否为目标应用。
通过本发明,在监听到应用加载时,通过应用的类加载器反射查找加载so库的函数,注入所需的so库,以利用so库实现在native层hook函数的效果,并且,利用了xposed框架的全局hook能力,通过xposed框架对孵化器进程流程的改动实现了对所有应用的hook,进而实现了针对native层的全局hook,提高了xposed框架在native层的适用性,解决了现有技术中xposed框架无法在native层hook的技术问题。
需要说明的是,上述各个模块是可以通过软件或硬件来实现的,对于后者,可以通过以下方式实现,但不限于此:上述模块均位于同一处理器中;或者,上述各个模块以任意组合的形式分别位于不同的处理器中。
显然,本领域的技术人员应该明白,上述的本发明的各模块或各步骤可以用通用的计算装置来实现,它们可以集中在单个的计算装置上,或者分布在多个计算装置所组成的网络上,可选地,它们可以用计算装置可执行的程序代码来实现,从而,可以将它们存储在存储装置中由计算装置来执行,并且在某些情况下,可以以不同于此处的顺序执行所示出或描述的步骤,或者将它们分别制作成各个集成电路模块,或者将它们中的多个模块或步骤制作成单个集成电路模块来实现。这样,本发明不限制于任何特定的硬件和软件结合。
实施例3
本发明的实施例还提供了一种存储介质,该存储介质中存储有计算机程序,其中,该计算机程序被设置为运行时执行上述任一项方法实施例中的步骤。
可选地,在本实施例中,上述存储介质可以包括但不限于:U盘、只读存储器(Read-Only Memory,简称为ROM)、随机存取存储器(Random Access Memory,简称为RAM)、移动硬盘、磁碟或者光盘等各种可以存储计算机程序的介质。
实施例4
本发明的实施例还提供了一种电子装置(如移动终端),该电子装置包括存储器和处理器,该存储器中存储有计算机程序,该处理器被设置为运行计算机程序以执行上述任一项方法实施例中的步骤。
可选地,上述电子装置还可以包括传输设备以及输入输出设备,其中,该传输设备和上述处理器连接,该输入输出设备和上述处理器连接。
以上所述仅为本发明的优选实施例而已,并不用于限制本发明,对于本领域的技术人员来说,本发明可以有各种更改和变化。凡在本发明的原则之内,所作的任何修改、等同替换、改进等,均应包含在本发明的保护范围之内。