基于Smali源码的安卓功能捆绑研究
2020-03-09 09:00:38 Author: www.freebuf.com(查看原文) 阅读量:189 收藏

在日常分析恶意软件过程中发现了很多恶意软件的捆绑方式,例如将两个app放入同一个安装包中同时释放,将一个app绑在另一个的头部释放等等。网上也有很多用来捆绑两个app的工具,但是总的来说还是很暴力不够优雅。以学习研究为目的,近期深入研究了安卓逆向后的smali源码,想到是否能够从底层源码进行功能捆绑。在进行多次实验后,发现此方法可行,接下来会从Smali机器语言、功能捆绑实现方法、自动化流程三个方面介绍基于Smali源码的安卓功能捆绑实现方法与原理。

Smali机器语言

首先简要介绍一下smali,Smali是用于Dalvik(Android虚拟机)的反汇编程序实现,Smali支持注解、调试信息、行数信息等基本Java的基本特性。对应着来说,Smali和二进制逆向后的汇编语言很像,里面有寄存器、函数跳转等,需要着重知道的几个点如下:

Smali文件结构

一个Smali文件对应的是一个Java的类,对应一个.class文件,如果有内部类,需要写成ClassName$InnerClassA、ClassName$InnerClassB的形式。

Smali语言对象

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虚拟机指令,其合集称为Dalvik指令集,其中包括:移位操作、返回操作、常量操作、调用操作、判断操作和属性操作等。具体指令内容可以参考Android官方的Dalvik相关文档。

了解认识Smali源码后就可以从samli代码上进行修改,如何修改源码使功能捆绑到另一个app而且保证功能的完整性,应该注意哪些重要的环节会在下面详细说明。

具体实现方法

目标apk反编译

利用安卓反编译工具,这里我使用的是apktool(可以在网上自行下载),将目标apk反编译成源文件格式。执行命令:

“java -jar apktool.jar d + 目标.apk”

反编译后的源文件及其用途:

image.png

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源码在同一功能的实现上会分为多个文件,多个文件具有相同功能名称并用”$”区分不同的文件,如下图:

image.pngCache功能通过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”。

image.png

②通过keytool工具生成秘钥

keytool -genkey -alias key.keystore -keyalg RSA -validity 30000 -keystore key.keystore

根据提示运行结束后会在当前目录下回生成一个key.keystore文件,该文件为所需秘钥。

运行与调试

将回编译后的apk在安卓虚拟机或是手机上运行,捆绑后的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原创奖励计划,未经许可禁止转载


文章来源: https://www.freebuf.com/articles/terminal/228180.html
如有侵权请联系:admin#unsafe.sh