本发明涉及应用程序安全领域,特别是涉及一种应用程序的加固方法和装置。
背景技术:
随着网络技术的发展,网络已成为人们生活的一部分,给人们的生活带来了便利。为了满足不同的需求,提供各种服务的应用程序被开发和发布使用。应用程序的开发花费了开发者大量的人力和财力,然而,大量的应用程序被破解,重新打包,并构建了大量的山寨应用,并在山寨应用程序中植入恶意指令、广告插件及其它恶意行为等。用户下载和安装了山寨应用程序后,山寨应用程序内的恶意指令会窃取用户的数据,威胁用户的个人信息和财产安全。
技术实现要素:
基于此,有必要针对传统的应用程序破解后被植入恶意指令导致用户数据易被窃取的问题,提供一种应用程序的加固方法和装置,能提高应用程序的安全性,防止用户数据被窃取。
一种应用程序的加固方法,包括以下步骤:
静态扫描应用程序安装包,获取待加密的资源文件;
对所述待加密的资源文件进行加密,生成包含资源文件密文的应用程序安装包;
向所述包含资源文件密文的应用程序安装包添加解密模块,生成包含所述解密模块和资源文件密文的应用程序安装包。
一种应用程序的加固装置,包括:
扫描模块,用于静态扫描应用程序安装包,获取待加密的资源文件;
加密模块,用于对所述待加密的资源文件进行加密,生成包含资源文件密文的应用程序安装包;
添加模块,用于向所述包含资源文件密文的应用程序安装包添加解密模块,生成包含所述解密模块和资源文件密文的应用程序安装包。
上述应用程序的加固方法和装置,通过扫描应用程序安装包,获取待加密的资源文件,并对待加密的资源文件进行加密,并将解密模块添加到包含资源文件密文的应用程序安装包中,当系统运行应用程序时,使用解密模块对资源文件密文进行解密成资源文件明文,确保应用程序的正常执行,当使用破解工具从应用程序安装包里提取资源文件时,获取到的是资源文件密文,使得资源文件不被窃取及修改,提高了应用程序的安全性,防止用户数据被窃取。
附图说明
图1A中的终端的内部结构示意图;
图1B为一个实施例中服务器的内部结构示意图;
图2为一个实施例中应用程序的加固方法的流程图;
图3为另一个实施例中应用程序的加固方法的流程图;
图4为一个实施例中通过解密模块透明解密资源文件密文为资源文件明文的具体流程图;
图5为访问应用程序资源文件的示意图;
图6为一个实施例中应用程序的加固装置的结构框图;
图7为另一个实施例中应用程序的加固装置的结构框图。
具体实施方式
为了使本发明的目的、技术方案及优点更加清楚明白,以下结合附图及实施例,对本发明进行进一步详细说明。应当理解,此处所描述的具体实施例仅仅用以解释本发明,并不用于限定本发明。
可以理解,本发明所使用的术语“第一”、“第二”等可在本文中用于描述各种元件,但这些元件不受这些术语限制。这些术语仅用于将第一个元件与另一个元件区分。举例来说,在不脱离本发明的范围的情况下,可以将第一客户端称为第二客户端,且类似地,可将第二客户端称为第一客户端。第一客户端 和第二客户端两者都是客户端,但其不是同一客户端。
图1A中的终端的内部结构示意图。如图1A所示,该终端包括通过系统总线连接的处理器、存储介质、内存和网络接口、声音采集装置、显示屏、扬声器和输入装置。其中,终端的存储介质存储有操作系统,还包括一种应用程序的加固装置,该应用程序的加固装置用于实现一种应用程序的加固方法。该处理器用于提供计算和控制能力,支撑整个终端的运行。终端中的内存为存储介质中的应用程序的加固装置的运行提供环境,网络接口用于与服务器进行网络通信,如发送应用程序下载请求至服务器,接收服务器返回的应用程序安装包等。终端的显示屏可以是液晶显示屏或者电子墨水显示屏等,输入装置可以是显示屏上覆盖的触摸层,也可以是终端外壳上设置的按键、轨迹球或触控板,也可以是外接的键盘、触控板或鼠标等。该终端可以是手机、平板电脑或者个人数字助理。本领域技术人员可以理解,图1A中示出的结构,仅仅是与本申请方案相关的部分结构的框图,并不构成对本申请方案所应用于其上的终端的限定,具体的终端可以包括比图中所示更多或更少的部件,或者组合某些部件,或者具有不同的部件布置。
图1B为一个实施例中服务器的内部结构示意图。如图1B所示,该服务器包括通过系统总线连接的处理器、存储介质、内存和网络接口。其中,该服务器的存储介质存储有操作系统、数据库和应用程序的加固装置,数据库中存储有应用程序的安装包等,该应用程序的加固装置用于实现适用于服务器的一种应用程序的加固方法。该服务器的处理器用于提供计算和控制能力,支撑整个服务器的运行。该服务器的内存为存储介质中的应用程序的加固装置的运行提供环境。该服务器的网络接口用于据以与外部的终端通过网络连接通信,比如接收终端发送的应用程序的下载请求以及向终端返回应用程序安装包等。服务器可以用独立的服务器或者是多个服务器组成的服务器集群来实现。本领域技术人员可以理解,图1B中示出的结构,仅仅是与本申请方案相关的部分结构的框图,并不构成对本申请方案所应用于其上的服务器的限定,具体的服务器可以包括比图中所示更多或更少的部件,或者组合某些部件,或者具有不同的部件布置。
图2为一个实施例中应用程序的加固方法的流程图。如图2所示,一种应用程序的加固方法,包括以下步骤:
步骤202,静态扫描应用程序安装包,获取待加密的资源文件。
具体地,一个APK(应用程序安装包)安装包是一个ZIP格式的压缩文件,里面包含了一款移动APP(应用程序)里的所需的代码、图片、布局、声音、动画、字符串、XML(Extensible Markup Language,可扩展标记语言)文件、配置文件、资源索引文件及其它二进制数据。其中,图片、布局、声音、动画、字符串、XML文件及其它二进制数据属于APP的资源。它们以文件的形式保存在APK文件的assets、res目录中,res目录存储图片、布局、声音、动画、字符串、XML文件,assets目录存储其它二进制数据文件,布局文件是指存储在res/layout或者res/layout-xxx(xxx表示任何字符)中AXML文件(XML文件经过aidl编译生成的一种二进制文件),用来描述APP界面中各种控件的摆放位置及属性。
需要说明的是,应用程序的加固是指对应用程序的安装包进行安全重构,防止应用程序被反编译、恶意篡改、保护应用数据不被窃取及其它重打包后可以进行的恶意攻击等。
步骤202包括:静态扫描应用程序安装包,预判只在应用程序安装包的用户进程中加载的资源文件作为待加密的资源文件。
例如,当扫描发现应用程序内包括将图片资源A传递给创建桌面图标相关的API的代码逻辑时,则预判图片资源A将在系统服务进程中加载,因为图片资源A被系统服务进程加载,所以图片资源A将不被加密。
静态扫描应用程序安装包包括:
(1)读取资源文件的索引文件,获取每个资源文件对应的资源文件标识,并获取资源文件标识对应的资源文件保存在待加密资源列表中。
具体地,读取资源文件的索引文件(resources.arsc),获取索引文件中指向的第一个图片的路径,作为获取混淆后的res目录路径(某些App会将res目录改名,所以res文件名不固定,需从这里获取),保存为第一资源路径;读取资源文件的索引文件,获取第一资源路径内每个资源文件对应的资源文件ID(标 识)。将assets目录作为第二资源路径。遍历第一资源路径和第二资源路径里的所有资源文件,并将所有资源文件保存在待加密资源列表中。
(2)扫描配置文件,获取配置文件中引用到的资源文件标识,并获取引用到的资源文件标识对应的资源文件名称,加入到第一排除列表。
扫描配置文件AndroidManifest.xml,获取配置文件中引用到的所有资源文件ID,并获取资源文件ID对应的资源文件名称,并将对应的资源文件名称加入到第一排除列表中。
(3)扫描代码文件,获取调用了预设应用程序接口的资源文件标识,并获取该资源文件标识对应的资源文件名称,加入到第二排除列表。
可预先设置API接口数据库,扫描应用程序文件的代码时,检测到调用的API接口在预先设置的API接口数据库查找得到,则代码传入的资源参数所对应的资源文件不能加密。
扫描代码文件(classes.dex),获取调用了以下API的方法:
"Landroid/content/Intent$ShortcutIconResource;->fromContext(Landroid/content/Context;I)Landroid/content/Intent$ShortcutIconResource;";
"Landroid/app/Notification;-><init>()V";
"Landroid/app/Notification;-><init>(ILjava/lang/CharSequence;J)V";
"Landroid/app/Notification;->setLatestEventInfo(Landroid/content/Context;Ljava/lang/CharSequence;Ljava/lang/CharSequence;Landroid/app/PendingIntent;)V";
"Landroid/app/NotificationManager;->cancel(I)V";
"Landroid/app/NotificationManager;->cancel(Ljava/lang/String;I)V";
"Landroid/app/NotificationManager;->notify(ILandroid/app/Notification;)V";
"Landroid/app/NotificationManager;->notify(Ljava/lang/String;ILandroid/app/Notification;)V";
"Landroid/support/v4/app/NotificationCompat$Builder;-><init>(Landroid/content/Context;)V";
"Landroid/support/v4/app/NotificationCompat$Builder;->setSmallIcon(I)Landroid/support/v4/app/NotificationCompat$Builder";
"Landroid/app/WallpaperManager;->setResource(I)V";
"Landroid/widget/RemoteViews;-><init>(Ljava/lang/String;I)V"。
将上一步获取的方法的所有定义类型的指令(如指令字节码为0x14),其后面跟着的就是整型的值,将其作为资源文件ID,获取该资源文件ID对应的资源文件名称,将得到的资源文件名称加入第二排除列表中。
(3)将待加密资源列表中的资源文件减去第一排除列表和第二排除列表中的资源文件,剩余的资源文件作为待加密资源文件。
此外,还可从剩余的资源文件中筛选出图片、布局资源作为待加密资源文件。
步骤204,对该待加密的资源文件进行加密,生成包含资源文件密文的应用程序安装包。
具体地,根据安全需求,获取一对公钥和私钥,使用私钥对该待加密的资源文件进行加密,将加密后的资源文件打包进应用程序安装包中,生成包含资源文件密文的应用程序安装包,并将公钥与待加密资源列表作为资源文件打包进包含资源文件密文的应用程序安装包。
步骤206,向该包含资源文件密文的应用程序安装包添加解密模块,生成包含该解密模块和资源文件密文的应用程序安装包。
具体地,解密模块可为so解密模块,即内嵌在移动APP里的透明解密模块,它是由native语言开发的一个so文件。将so解密模块嵌入到应用程序安装包,具体包括:将so解密模块以资源文件的形式打包进Assets目录,生成包含解密模块的应用程序安装包。
Assets目录用于向移动APP提供二进制的文件存储能力。将so解密模块的arm版本与x86版本一起以资源文件的形式保存在Assets目录中。
将so解密模块以资源文件的形式打包进Assets目录中,生成包含解密模块的应用程序安装包的步骤包括:
(1)扫描配置文件,获取入口方法。
在AndroidManifest.xml文件中,描述有application结点、activity结点、service结点。每个结点都有若干属性,其中,android:name属性用于描述该结点 对应组件所在的类,android:process属性用于描述该结点对应组件所在的进程程,结点下面又会有子结点、孙子结点。当application结点包含android:name,将该组件所在的类添加到入口类集合,否则包含孙子结点<actionandroid:name="android.intent.action.MAIN"/>的activity组件所在的类添加到入口类集合;当service结点包含android:process属性时,将该组件所在的类添加到入口类集合。
将入口类集合的onCreate方法定为入口方法集合。
(2)在该入口方法中插入释放so解密模块,并加载so解密模块。
具体地,修改classes.dex文件中描述入口方法的代码指令,添加以下逻辑:释放so解密模块至APP目录;加载释放出来的so解密模块。
(3)调整该入口方法的寄存器。
由于入口方法的寄存器数量可能不足以执行新增的代码指令,所以需要进行调整,同时还要修改原本代码里的try和handler的指令偏移,使入口方法的原功能不受影响。
修改完dex文件后重新写入classes.dex的校验值,然后打包到包括解密模块的第一应用程序安装包,生成包括解密模块的第二应用程序安装包,输出为经加固的应用程序安装包。
上述应用程序的加固方法,通过扫描应用程序安装包,获取待加密的资源文件,并对待加密的资源文件进行加密,并将解密模块添加到包含资源文件密文的应用程序安装包中,当系统运行应用程序时,使用解密模块对资源文件密文进行解密成资源文件明文,确保应用程序的正常执行,当使用破解工具从应用程序安装包里提取资源文件时,获取到的是资源文件密文,使得资源文件不被窃取及修改,提高了应用程序的安全性,防止用户数据被窃取。
图3为另一个实施例中应用程序的加固方法的流程图。图3中的应用程序的加固方法与图2的区别在于,增加了在移动终端上安装及运行应用程序安装包的过程。如图3所示,一种应用程序的加固方法,包括以下步骤:
步骤302,静态扫描应用程序安装包,获取待加密的资源文件。
步骤304,对该待加密的资源文件进行加密,生成包含资源文件密文的应用 程序安装包。
步骤306,向该包含资源文件密文的应用程序安装包添加解密模块,生成包含该解密模块和资源文件密文的应用程序安装包。
步骤308,安装该包含解密模块和资源文件密文的应用程序安装包。
具体地,将加固后的APK安装包传给开发者用户,开发者用户使用自己的证书对该APK安装包进行签名,生成待发布的APK安装包,将待发布的APK安装包,上传到应用市场或其他发布途径,作为已发布APK安装包。用户通过各种可获取到APK,安装至移动终端上。该移动终端可为手机、平板电脑、个人数字助理等。
步骤310,在运行该应用程序安装包时,加载该解密模块,并挂钩系统函数,得到挂钩回调函数。
具体地,运行经加固的APP,加载so解密模块会在APP的功能代码之前先执行,将so解密模块从assets目录释放到APP目录,然后加载该so解密模块。
So解密模块首先会挂钩系统代码里的AssetManager类的open、openNonAsset函数,这两个函数在系统每次访问资源文件的过程中都会被调用,函数open经过C++编译器的编译后得到的符号名为:
_ZN7android12AssetManager4openEPKcNS_5Asset10AccessModeE;
方法openNonAsset有两个多态实现,经编译后,其符号名为:
_ZN7android12AssetManager12openNonAssetEPKcNS_5Asset10AccessModeE;
_ZN7android12AssetManager12openNonAssetEPKcNS_5Asset10AccessModeE
对于Android 5.0及以后的系统,方法openNonAsset的导出符号为:
_ZN7android12AssetManager12openNonAssetEPvPKcNS_5Asset10AccessModeE;
_ZN7android12AssetManager12openNonAssetEiPKcNS_5Asset10AccessModeE。
系统会把资源文件的全路径转给open、openNonAsset函数,这两个函数, 再从APK安装包里,读取该路径指向的资源文件密文,将其构造成第一类数据的对象,即_FileAsset类的对象,并最终返回指向该对象的Asset类指针。Asset类是_FileAsset的父类,系统上层不识别_FileAsset类,只通过Asset类的指针去访问一个资源文件。
So解密模块挂钩系统函数得到挂钩回调函数。具体地,So解密模块默认使用Got Hook进行挂钩,挂钩的是libandroid_runtime.so模块里的got表,部分移动的rom经过修改,libandroid_runtime.so模块,以致该挂钩方式失败,则使用Inline Hook进行挂钩,挂钩模块是libutils.so(android 4.0及以下版本)或libandroidfw.so(android 4.1及以上版本),挂钩了open、openNonAsset函数后,系统上层再调用这些函数,就会转到so解密模块的挂钩回调函数hook_open、hook_openNonAsset,同时保存挂钩前的原函数original_open、original_openNonAsset。随后,so解密模块就开始等待系统上层调用open、openNonAsset函数。
该挂钩系统函数包括以下符号:
"_ZN7android12AssetManager4openEPKcNS_5Asset10AccessModeE";
"_ZN7android12AssetManager12openNonAssetEPKcNS_5Asset10AccessModeE";
"_ZN7android12AssetManager12openNonAssetEPKcNS_5Asset10AccessModeEPi";
"_ZN7android12AssetManager12openNonAssetEPvPKcNS_5Asset10AccessModeE";
"_ZN7android12AssetManager12openNonAssetEiPKcNS_5Asset10AccessModeE"。
步骤312,通过解密模块透明解密资源文件密文为资源文件明文。
图4为一个实施例中通过解密模块透明解密资源文件密文为资源文件明文的具体流程图。如图4所示,通过解密模块透明解密资源文件密文为资源文件明文的步骤包括:
步骤402,获取资源文件访问请求。
具体地,当移动APP需要使用某些资源文件时,则产生获取资源文件访问请求。
步骤404,根据该访问请求中所指向的第一类数据,获取资源文件密文,解密该资源文件密文得到资源文件明文,并将该资源文件明文保存为第二类数据。
具体地,根据该访问请求,系统上层会首先调用AssetManager类的open、openNonAsset函数去打开访问请求中所指向的第一类数据,即_FileAsset类中的该资源文件,获取用于读取资源文件的Asset对象指针。由于open、openNonAsset函数已经被挂钩,该调用会跳转到挂钩回调函数hook_open、hook_openNonAsset中,通过传入参数(参数可为char*字符串指针)获取要待打开资源文件路径,若该路径不包含在待加密资源列表中,则直接返回ori_open、ori_openNonAsset的调用结果;若该路径包含在待加密资源列表中,则获取资源文件密文,解密该资源文件密文得到资源文件明文的步骤包括:
调用ori_open、ori_openNonAsset获取资源文件密文的Asset对象指针;
调用资源文件密文Asset对象指针的getBuffer函数,获取资源文件密文;
使用公钥解密资源文件密文,生成资源文件明文。
从资源文件明文数据构建第二类数据(第二类数据可为_HookAsset对象),若系统版本为Android 4.1及以下版本,则构建32位版的_HookAsset对象,32位版的_HookAsset对象与64位版的_HookAsset对象的差异在于32位版的参数或返回值里的size_t或offset_t类型为32位无符号整型,需要一个通用寄存器传值,而64位的是64位无符号整型,需要两个通用寄存器传值,将该对象转换为Asset对象指针返还给系统上层。_HookAsset类继承于Asset类,重载以下方法:
read返回文件指针所在偏移处指定长度的明文数据;
seek将文件指针置为指定依稀;
close释放明文数据内存;
getBuffer返回明文数据的起始地址;
getLength返回明文数据的长度;
getRemainingLength返回明文数据长度减文件偏移的差;
openFileDescriptor将资源文明文释放到文件系统,保存为第三类数据文件,再返回第三类数据文件的文件描述符;
isAllocated返回true;
getAssetSource获取资源文件路径。
步骤406,伪造用于访问第二类数据的对象。
具体地,伪造用于访问第二类数据的对象可为_HookAsset对象。
该伪造用于访问第二类数据的对象,该第二类数据的对象满足以下条件:
继承于系统的Asset类或Asset类的子类;
重载Asset类的所有方法,将所有对第一类数据的访问重定向为对第二类数据的访问;
重载Asset类的openFileDescriptor方法,将第二类数据保存为文件系统中的第三类数据,再返回该第三类数据的文件描述符。
步骤408,在挂钩回调函数中,用该伪造的第二类数据的对象替换第一类数据的对象,并将该第二类数据的对象表示的资源文件明文作为访问结果返回。
具体地,采用第二类数据(代表资源文件明文)的对象(_HookAsset对象)替换第一类数据(代表资源文件密文)的对象(_FileAsset对象),将第二类数据的对象表示的资源文件明文数据作为访问结果返回。
在一个实施例中,在挂钩回调函数中,用该伪造的第二类数据的对象替换第一类数据的对象,并将该第二类数据的对象作为访问结果返回的步骤之后,该应用程序的加固方法还包括:资源使用结束后,销毁第二类数据的对象。销毁第二数据的对象可防止其被破解工具提取,提高数据的安全性。同时,节省存储空间。
图5为访问应用程序资源文件的示意图。如图5所示,某APP应用程序访问一个资源文件(例如,使用setContentView(R.layout.activity)方法设置当前Activity的布局),安卓系统通过调用openNonAsset函数去获取资源文件res/layout/activity.xml的_FileAsset对象,由于该资源文件已经被加密,所以得到的是加密的资源文件,在随后Android系统使用Asset->read读取资源文件数据时,获取到无法识别数据导致进程崩溃。加载so解密模块,对该系统函数进行 挂钩,挂钩openNonAsset,用_HookAsset替换_FileAsset,将代表资源文件密文的_FileAsset对象替换为代表资源文件明文的_HookAsset对象,随后Android系统使用Asset->read读取数据时,调用的是_HookAsset->read,读取的是资源文件明文数据。
当调用的指定接口为Asset->openFileDescriptor接口时,指定资源文件目录可为assets/splash.png。将资源文件密文解密到/data/data/包名/files/txres/splash.png,以后再调用openFileDescriptor接口时,直接使用解密的资源文件明文。对于未调用该指定接口的资源文件,只在每次接收到操作请求后开始解密,不在文件系统中保存明文数据。通过指定接口调用资源文件,可以实现对资源系统透明,操作方便,且安全。
图6为一个实施例中应用程序的加固装置的结构框图。图6中的应用程序的加固装置为基于应用程序的加固方法所构建的虚拟装置,其所构建的功能模块不限于此处描述的划分,还可有其他划分方式,功能模块的功能描述不详细之处可参照应用程序的加固方法中描述。如图6所示,一种应用程序的加固装置,包括扫描模块610、加密模块620和添加模块630。
扫描模块610用于静态扫描应用程序安装包,获取待加密的资源文件。
具体地,一个APK(应用程序安装包)安装包是一个ZIP格式的压缩文件,里面包含了一款移动APP(应用程序)里的所需的代码、图片、布局、声音、动画、字符串、XML(Extensible Markup Language,可扩展标记语言)文件、配置文件、资源索引文件及其它二进制数据。其中,图片、布局、声音、动画、字符串、XML文件及其它二进制数据属于APP的资源。它们以文件的形式保存在APK文件的assets、res目录中,res目录存储图片、布局、声音、动画、字符串、XML文件,assets目录存储其它二进制数据文件,布局文件是指存储在res/layout或者res/layout-xxx(xxx表示任何字符)中AXML文件(XML文件经过aidl编译生成的一种二进制文件),用来描述APP界面中各种控件的摆放位置及属性。
进一步的,扫描模块610还用于静态扫描应用程序安装包,预判只在应用 程序安装包的用户进程中加载的资源文件作为待加密的资源文件。
进一步的,扫描模块610还用于读取资源文件的索引文件,获取每个资源文件对应的资源文件标识,并获取资源文件标识对应的资源文件保存在待加密资源列表中,再扫描配置文件,获取配置文件中引用到的资源文件标识,并获取引用到的资源文件标识对应的资源文件名称,加入到第一排除列表;以及扫描代码文件,获取调用了预设应用程序接口的资源文件标识,并获取该资源文件标识对应的资源文件名称,加入到第二排除列表;并将待加密资源列表中的资源文件减去第一排除列表和第二排除列表中的资源文件,剩余的资源文件作为待加密资源文件。
此外,还可从剩余的资源文件中筛选出图片、布局资源作为待加密资源文件。
加密模块620用于对该待加密的资源文件进行加密,生成包含资源文件密文的应用程序安装包。
具体地,根据安全需求,获取一对公钥和私钥,使用私钥对该待加密的资源文件进行加密,将加密后的资源文件打包进应用程序安装包中,生成包含资源文件密文的应用程序安装包,并将公钥与待加密资源列表作为资源文件打包进包含资源文件密文的应用程序安装包。
添加模块630用于向该包含资源文件密文的应用程序安装包添加解密模块,生成包含该解密模块和资源文件密文的应用程序安装包。
具体地,解密模块可为so解密模块,即内嵌在移动APP里的透明解密模块,它是由native语言开发的一个so文件。将so解密模块嵌入到应用程序安装包,具体包括:将so解密模块以资源文件的形式打包进Assets目录,生成包含解密模块的应用程序安装包。
Assets目录用于向移动APP提供二进制的文件存储能力。将so解密模块的arm版本与x86版本一起以资源文件的形式保存在Assets目录中。
将so解密模块以资源文件的形式打包进Assets目录中,生成包含解密模块的应用程序安装包的过程包括:
(1)扫描配置文件,获取入口方法。
在AndroidManifest.xml文件中,描述有application结点、activity结点、service结点。每个结点都有若干属性,其中,android:name属性用于描述该结点对应组件所在的类,android:process属性用于描述该结点对应组件所在的进程程,结点下面又会有子结点、孙子结点。当application结点包含android:name,将该组件所在的类添加到入口类集合,否则包含孙子结点<actionandroid:name="android.intent.action.MAIN"/>的activity组件所在的类添加到入口类集合;当service结点包含android:process属性时,将该组件所在的类添加到入口类集合。
将入口类集合的onCreate方法定为入口方法集合。
(2)在该入口方法中插入释放so解密模块,并加载so解密模块。
具体地,修改classes.dex文件中描述入口方法的代码指令,添加以下逻辑:释放so解密模块至APP目录;加载释放出来的so解密模块。
(3)调整该入口方法的寄存器。
由于入口方法的寄存器数量可能不足以执行新增的代码指令,所以需要进行调整,同时还要修改原本代码里的try和handler的指令偏移,使入口方法的原功能不受影响。
修改完dex文件后重新写入classes.dex的校验值,然后打包到包括解密模块的第一应用程序安装包,生成包括解密模块的第二应用程序安装包,输出为经加固的应用程序安装包。
上述应用程序的加固装置,通过扫描应用程序安装包,获取待加密的资源文件,并对待加密的资源文件进行加密,并将解密模块添加到包含资源文件密文的应用程序安装包中,当系统运行应用程序时,使用解密模块对资源文件密文进行解密成资源文件明文,确保应用程序的正常执行,当使用破解工具从应用程序安装包里提取资源文件时,获取到的是资源文件密文,使得资源文件不被窃取及修改,提高了应用程序的安全性,防止用户数据被窃取。
图7为另一个实施例中应用程序的加固装置的结构框图。如图7所示,一种应用程序的加固装置,包括扫描模块610、加密模块620和添加模块630,还包 括安装模块640、加载及挂钩模块650、请求获取模块660、明文获取模块670、对象伪造模块680、替换模块690、返回模块692、销毁模块694。
安装模块640用于安装该包含解密模块和资源文件密文的应用程序安装包。
具体地,将加固后的APK安装包传给开发者用户,开发者用户使用自己的证书对该APK安装包进行签名,生成待发布的APK安装包,将待发布的APK安装包,上传到应用市场或其他发布途径,作为已发布APK安装包。用户通过各种可获取到APK,安装至移动终端上。该移动终端可为手机、平板电脑、个人数字助理等。
加载及挂钩模块650用于在运行所述应用程序安装包时,加载该解密模块,并挂钩系统函数,得到挂钩回调函数,并通过该解密模块透明解密该资源文件密文为资源文件明文。
具体地,运行经加固的APP,加载so解密模块会在APP的功能代码之前先执行,将so解密模块从assets目录释放到APP目录,然后加载该so解密模块。
So解密模块首先会挂钩系统代码里的AssetManager类的open、openNonAsset函数,这两个函数在系统每次访问资源文件的过程中都会被调用,函数open经过C++编译器的编译后得到的符号名为:
_ZN7android12AssetManager4openEPKcNS_5Asset10AccessModeE;
方法openNonAsset有两个多态实现,经编译后,其符号名为:
_ZN7android12AssetManager12openNonAssetEPKcNS_5Asset10AccessModeE;
_ZN7android12AssetManager12openNonAssetEPKcNS_5Asset10AccessModeE
对于Android 5.0及以后的系统,方法openNonAsset的导出符号为:
_ZN7android12AssetManager12openNonAssetEPvPKcNS_5Asset10AccessModeE;
_ZN7android12AssetManager12openNonAssetEiPKcNS_5Asset10AccessModeE。
系统会把资源文件的全路径转给open、openNonAsset函数,这两个函数, 再从APK安装包里,读取该路径指向的资源文件密文,将其构造成第一类数据的对象,即_FileAsset类的对象,并最终返回指向该对象的Asset类指针。Asset类是_FileAsset的父类,系统上层不识别_FileAsset类,只通过Asset类的指针去访问一个资源文件。
So解密模块挂钩系统函数得到挂钩回调函数。具体地,So解密模块默认使用Got Hook进行挂钩,挂钩的是libandroid_runtime.so模块里的got表,部分移动的rom经过修改,libandroid_runtime.so模块,以致该挂钩方式失败,则使用Inline Hook进行挂钩,挂钩模块是libutils.so(android 4.0及以下版本)或libandroidfw.so(android 4.1及以上版本),挂钩了open、openNonAsset函数后,系统上层再调用这些函数,就会转到so解密模块的挂钩回调函数hook_open、hook_openNonAsset,同时保存挂钩前的原函数original_open、original_openNonAsset。随后,so解密模块就开始等待系统上层调用open、openNonAsset函数。
该挂钩系统函数包括以下符号:
"_ZN7android12AssetManager4openEPKcNS_5Asset10AccessModeE";
"_ZN7android12AssetManager12openNonAssetEPKcNS_5Asset10AccessModeE";
"_ZN7android12AssetManager12openNonAssetEPKcNS_5Asset10AccessModeEPi";
"_ZN7android12AssetManager12openNonAssetEPvPKcNS_5Asset10AccessModeE";
"_ZN7android12AssetManager12openNonAssetEiPKcNS_5Asset10AccessModeE"。
请求获取模块660用于获取资源文件访问请求。
具体地,当移动APP需要使用某些资源文件时,则产生获取资源文件访问请求。
明文获取模块670用于根据该访问请求中所指向的第一类数据,获取资源文件密文,解密该资源文件密文得到资源文件明文,并将该资源文件明文保存 为第二类数据。
对象伪造模块680用于伪造用于访问第二类数据的对象。
具体地,该伪造用于访问第二类数据的对象,该第二类数据的对象满足以下条件:
继承于系统的Asset类或Asset类的子类;
重载Asset类的所有方法,将所有对第一类数据的访问重定向为对第二类数据的访问;
重载Asset类的openFileDescriptor方法,将第二类数据保存为文件系统中的第三类数据,再返回该第三类数据的文件描述符。
替换模块690用于在挂钩回调函数中,用该伪造的第二类数据的对象替换第一类数据的对象。
返回模块692用于将该第二类数据的对象表示的资源文件明文作为访问结果返回。
具体地,采用第二类数据(代表资源文件明文)的对象(_HookAsset对象)替换第一类数据(代表资源文件密文)的对象(_FileAsset对象),将第二类数据的对象表示的资源文件明文数据作为访问结果返回。
销毁模块694用于在资源使用结束后,销毁第二类数据的对象。
销毁第二数据的对象可防止其被破解工具提取,提高数据的安全性。同时,节省存储空间。
本领域普通技术人员可以理解实现上述实施例方法中的全部或部分流程,是可以通过计算机程序来指令相关的硬件来完成,所述的程序可存储于一非易失性计算机可读取存储介质中,该程序在执行时,可包括如上述各方法的实施例的流程。其中,所述的存储介质可为磁碟、光盘、只读存储记忆体(Read-OnlyMemory,ROM)等。
以上所述实施例仅表达了本发明的几种实施方式,其描述较为具体和详细,但并不能因此而理解为对本发明专利范围的限制。应当指出的是,对于本领域的普通技术人员来说,在不脱离本发明构思的前提下,还可以做出若干变形和改进,这些都属于本发明的保护范围。因此,本发明专利的保护范围应以所附 权利要求为准。