文章目录
在日常分析恶意软件过程中发现了很多恶意软件的捆绑方式,例如将两个app放入同一个安装包中同时释放,将一个app绑在另一个的头部释放等等。网上也有很多用来捆绑两个app的工具,但是总的来说还是很暴力不够优雅。以学习研究为目的,近期深入研究了安卓逆向后的smali源码,想到是否能够从底层源码进行功能捆绑。在进行多次实验后,发现此方法可行,接下来会从Smali机器语言、功能捆绑实现方法、自动化流程三个方面介绍基于Smali源码的安卓功能捆绑实现方法与原理。
首先简要介绍一下smali,Smali是用于Dalvik(Android虚拟机)的反汇编程序实现,Smali支持注解、调试信息、行数信息等基本Java的基本特性。对应着来说,Smali和二进制逆向后的汇编语言很像,里面有寄存器、函数跳转等,需要着重知道的几个点如下:
一个Smali文件对应的是一个Java的类,对应一个.class文件,如果有内部类,需要写成ClassName$InnerClassA、ClassName$InnerClassB的形式。
Object类型,即引用类型的对象,在引用时,使用L开头,后面紧接着的是完整的包名,比如:java.lang.String对应的Smali语法则是Ljava/lang/String。
Smali引用方法的模板如下:
Lpackage/name/ObjectName;->MethodName(III)Z
第一部分Lpackage/name/ObjectName;用于声明具体的类型,以便JVM寻找。
第二部分MethodName(III)Z,其中MethodName为具体的方法名,()中的字符,表示了参数数量和类型,即3个int型参数,Z为返回值的类型,即返回Boolean类型
在Smali中,如果需要存储变量,必须先声明足够数量的寄存器。声明可使用的寄存器数量的方式为:.registers N,N代表需要的寄存器的总个数,同时,还有一个关键字.locals,它用于声明非参数的寄存器个数(包含在registers声明的个数当中),也叫做本地寄存器,只在一个方法内有效。
常用的Dalvik虚拟机指令,其合集称为Dalvik指令集,其中包括:移位操作、返回操作、常量操作、调用操作、判断操作和属性操作等。具体指令内容可以参考Android官方的Dalvik相关文档。
了解认识Smali源码后就可以从samli代码上进行修改,如何修改源码使功能捆绑到另一个app而且保证功能的完整性,应该注意哪些重要的环节会在下面详细说明。
利用安卓反编译工具,这里我使用的是apktool(可以在网上自行下载),将目标apk反编译成源文件格式。执行命令:
“java -jar apktool.jar d + 目标.apk”
反编译后的源文件及其用途:
Assets目录
该文件夹为安卓系统原生资源文件,该文件夹下的文件不会被编译,同时Android提供了一个工具类,方便操作获取assets文件下的文件。可将apk所需外部加载的资源信息,如图片、配置等放于该文件夹下。
Lib目录
目录下的子目录armeabi含有so文件。Eclipse在打包的时候会根据文件名的命名规则(lib***.so)去打包so文件,开头和结尾必须分别为“lib”和“.so”,否则不会打包到apk文件中。
Res目录
存放应用程序资源文件,包括图片,字符串等等,可根据自身需要直接对其进行修改。在apk回编译时会自动识别路径并加载已被修改的程序资源。
Smali目录
该目录主要是dex文件反编译得到的smali文件,也是在自动化捆绑过程中主要修改的文件目录。进行功能捆绑时需要直接在smali源文件上进行smali源码的插入与修改。应用程序反编译可能会出现多个smali文件目录,在进行源码修改过程中需要找准文件修改位置再进行操作。
AndroidManifest.xml
此文件是apk中最重要的文件之一。它是apk的全局配置文件,提供了android系统所需要的关于该应用的必要信息。主要包括:应用名称、版本、权限、引用的库文件、应用入口、调用服务声明等信息。
该文件可用于定位应用程序入口点、添加新的应用权限、声明新的服务和事件。在捆绑功能时要对该文件进行大量修改。
利用安卓反编译工具,将需要捆绑的apk反编译并提取需要的功能。反编译后的文件需要提取以下重要部分:apk所需权限、服务、事件以及功能实现的smali源码。
在捆绑过程中并不是将整个apk依附在另一个apk之上,是将需要捆绑的apk中所需的功能进行提取并插入到其他的apk之中。因此需要提取修改的文件类型及数量较多,具体提取方法如下:
提取所需权限、服务、事件
根据反编译后AndroidManifest.xml文件中标签类别进行提取,例如<uses-permission />、<service />、<receiver></receiver>、<activity />等,分别对权限、服务、事件进行相应的提取。提取时应注意提取的元素要与所需应用功能相对应,不要提取多余的元素。
提取smali源码
提取源码前要根据配置文件找到应用入口从而定位smali位置存放位置,smali源码在同一功能的实现上会分为多个文件,多个文件具有相同功能名称并用”$”区分不同的文件,如下图:
Cache功能通过8个smali文件实现,提取时需要将8个文件同时提取才能保证功能的完整性。
修改目标apk源文件
在进行捆绑操作的过程中需要修改如下几类文件:AndroidManifest.xml、两个apk反编译后的smali源码文件、Assets资源文件。
1、AndroidManifest.xml文件修改:
①对比目标apk自身权限与待插入功能所需权限,添加所需权限声明;
②添加带插入功能所需的服务<service />与事件<receiver></receiver>声明;
③确定应用程序入口位置,活动中的<intent-filter>标签包含
”<action android:name =“android.intent.action.MAIN”/>”则是应用程序的入口点。
④根据程序入口点修改添加服务与事件”<… android:name= >”中的路径信息。
2、Smali源码修改:
①根据程序入口点找到所在smali文件,找到入口特征:
”.method protected onCreate(Landroid/os/Bundle;)V”定位程序入口位置;
②修改寄存器值”.locals x”,在程序起调自身后添加待插入功能的函数调用;
③将需捆绑功能smali文件复制到入口文件所在目录下,修改所有smali文件中包名路径,与入口文件路径相同。
文件回编译
“apktool b[uild] <target dir> -o <app_path>”
输入修改后的文件路径与捆绑后的应用名称,apktool工具会将整个文件重新编译,并在当前目录下生成apk安装包。
安装包签名
所有重编译的安卓程序需要签名后才可以在手机上安装运行,可使用apksigner.jar对apk进行签名。
java -jar ApkSigner.jar -keystore keystorePath -alias alias [-pswd password] apkPath(or directory)
获取秘钥有以下两种方法:
①编译过程中使用的安卓密钥可使用安装Android studio时构建的Android调试密钥库,调试密钥库位于系统目录中的“.android”隐藏目录中,默认密码为“android”。
②通过keytool工具生成秘钥
keytool -genkey -alias key.keystore -keyalg RSA -validity 30000 -keystore key.keystore
根据提示运行结束后会在当前目录下回生成一个key.keystore文件,该文件为所需秘钥。
运行与调试
将回编译后的apk在安卓虚拟机或是手机上运行,捆绑后的apk正常安装运行则说明各个功能捆绑成功,之后可根据捆绑功能进行具体功能测试。
运行过程中可能会出现以下错误状况:
解决方法:检查apk是否完成签名,比较签名前后apk大小,签名成功的apk会比签名前的apk大;检查AndroidManifest.xml文件中插入元素是否完整,所有标签是否配对。
解决方法:利用Android工具DDMS进行动态调试。
如果每一个app都需要手动操作以上步骤还是不够优雅,自动化完成才是最终的目的,在上面已经具体说明了重点环节和注意事项,接下来简单说一下自动化流程。
根据具体实现方法对自动化流程进行编程实现。主要有以下步骤:
步骤一:将待插入的功能提取后放置于同一文件夹下,方便程序捆绑时统一读取
步骤二:逆向目标apk,比较apk权限与功能所需要权限是否相同,并添加未声明权限与服务
步骤三:需找逆向后的apk入口,插入步骤一的功能,并根据插入功能数量修改smali源码信息
步骤四:添加修改标识
步骤五:回编译apk文件,并对apk签名
通过以上五个步骤即可将功能捆绑在已有app之上,捆绑结束后需要对新apk文件在实体手机上进行测试验证,具体验证方法如下:
1、安装测试:在实体手机(虚拟环境也行,不过可能会报错)上下载捆绑后的apk并安装,检测安装过程中是否提示错误信息。
2、运行测试:安装成功后运行软件,检测程序是否可以正常启动,原apk是否有损坏。
3、功能测试:验证原apk所有功能是否正常,检测捆绑功能可否正常运行,运行过程中是否出现报错信息。
以上方法可以在smali源码的基础上对安卓功能进行捆绑,过程比较复杂但是主要是以学习为目的,在这个过程中会对安卓有更深入的认识,大家可以根据流程学习操作,如有不对的地方,欢迎交流。
*本文原创作者:Kriston,本文属FreeBuf原创奖励计划,未经许可禁止转载