0x01 前言
0x02 简介
-
静态分析(Static Analysis):在不运行代码的情况下,用词法分析、语法分析等技术手段对程序文件扫描,生成反汇编代码,通过阅读反汇编代码掌握程序功能的一种技术。 -
然而在实际分析上,想要完全不运行程序是不太可能,通常是要先运行目标程序,从中寻找程序的突破口 生成反汇编代码的工具称反汇编工具或反编译工具,工具越强大,反汇编效果越好,能事半功倍
0x03 静态分析 Android 程序的方法
-
方法一: 阅读反汇编生成的Dalvik字节码,可以用IDA Pro分析dex文件,或者使用文本编辑器阅读baksmali反编译生成的smali文件; -
方法二: 阅读反汇编生成的java源码,可以使用dex2jar生成jar文件,然后再使用jd-gui阅读jar文件的代码。
快速定位Android程序的关键代码
-
信息反馈法: 先运行目标程序,然后根据程序运行时给出的反馈信息作为突破口寻找关键代码。 -
特征函数法: 跟信息反馈法类似。 -
顺序查看发: 从软件的启动代码开始,逐行的向下分析,掌握软件的执行流程。 -
代码注入法: 手动修改apk文件的反汇编代码,加入Log输出,配合LogCat查看程序执行到特定点时的状态数据。 -
栈跟踪法: 输出运行时的栈跟踪信息,然后查看栈上的函数调用序列来理解方法的执行流程。 -
方法剖析: 热点分析和性能优化。
0x04 阅读 smali 代码
那么,问题来了,什么是smali?
不要急,让我为大家一一道来:
要想了解smali,就得先理清APK、Dalvik字节码和smali文件之间的关系
APK文件
-
assets文件夹: 保存一些额外的资源文件,如游戏的声音文件,字体文件等等,在代码中可以用AssetManager获取assets文件夹的资源。 -
lib文件夹: 存放用C/C++编写的,用NDK编译生成的so文件,供java端调用。 -
META-INF文件夹: 存放apk签名信息,用来保证apk包的完整性和系统的安全。
在IDE编译生成一个apk包时,会对里面所有的文件做一个校验计算,并把计算结果存放在META-INF文件夹内,apk在安装的时候,系统会按照同样的算法对apk包里面的文件做校验,如果结果与META-INF里面的值不一样,系统就不会安装这个apk,这就保证了apk包里的文件不能被随意替换。比如拿到一个apk包后,如果想要替换里面的一幅图片,一段代码, 或一段版权信息,想直接解压缩、替换再重新打包,基本是不可能的。如此一来就给病毒感染和恶意修改增加了难度,有助于保护系 统的安全。 -
res文件夹: 存放资源文件,包括icon,xml文件 -
AndroidManifest.xml文件: 应用程序配置文件,每个应用都必须定义和包含的,它描述了应用的名字、版本、权限、引用的库文件等信息。 -
classes.dex文件: 传统 Class 文件是由一个 Java 源码文件生成的 .Class 文件,而 Android 是把所有 Class 文件进行合并优化,然后生成一个最终的 class.dex 文件。它包含 APK 的可执行代码,是分析 Android 软件时最常见的目标。由于dex文件很难看懂,可通过apktool反编译得到.smali文件,smali文件是对Dalvik虚拟机字节码的一种解释(也可以说是翻译),并非一种官方标准语言。通过对smali文件的解读可以获取源码的信息。 -
resources.arsc文件: 二进制资源文件,包括字符串等。 -
smali: smali是将Android字节码用可阅读的字符串形式表现出来的一种语言,可以称之为Android字节码的反汇编语言。利用apktool或者Android Killer,反编classes.dex文件,就可以得到以smali为后缀的文件,这些smali文件就是Dalvik的寄存器语言。
简单的说,smali就是Dalvik VM内部执行的核心代码,andorid逆向分析的关键点。
Dalvik字节码
-
Dalvik是andrord虚拟机,即Dalvik VM -
Dalvik字节码是他执行的语言 -
Dalvik的专属文件格式(.dex),就像上面apk文件中的class.dex -
Dalvik VM是基于寄存器的,基于寄存器的意思是,所有操作都必须经过寄存器来进行。
smali文件
smali文件结构
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
smali数据类型
-
基础数据类型: Z,B,S,C,I,L,F,D为基本数据类型,从上表可以看出,Dalvik字节码基本类型的描述符基本上是java基本类型的首字母,除了boolean对应为Z外 -
对象类型: L加上类或者接口的全称表示对象类型,即Lpackage/objectName,如String类型描述符为Ljava/lang/String,包com.biyou下面的test类的类型描述符为Lcom/biyou/test -
数组类型: 基本类型的数组为”[“加上基本类型描述符来表示,一维数组前面是一个”[“,多一个维度前面多加一个”[“,比如int类型,一维是:[I,二维是:[[I,依次类推。
对象类型的数组为”[“加上对象类型表示符来表示,如String类型表示为:[Ljava/lang/String。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.mali文件示例
MainActivity.smali
为例-
.class
与.super
指令会指明 smali 文件所保存的类的完整签名,和类的父类的完整签名。像上述文件类(Lcom/example/junior/MainActivity) -
像public,protected,private就是所谓的访问权限修饰符,非权限修饰符则指的是final,abstract,static,两者都可以为空。 -
另外如果原java代码有混淆,那一般.class里面的类名和.source的源文件名则不同,以下是经过混淆的
-
smali文件的字段的声明使用".field"指令,字段有静态字段和实例字段两种:
1、静态字段格式:
.field 访问权限 static 修饰关键字 字段名 字段类型.field public static HELLO:Ljava/lang/String
2、实例字段格式:.field 访问权限 修饰关键字 字段名 字段类型.field prviate button:Landroid/widget/Button
-
smali 文件中会自动生成一些注释,:“# instance fields”和“# virtual methods”
“# instance fields”表示实例字段,在它之后,每个类中的字段都会以 .field 指令声明,后面跟着字段的访问权限和完整的签名;“# virtual methods”表示接下来存放的是类的虚方法 -
smali 文件只支持单行注释,注释可放在一行开头,也可放在一行的任何地方,使用 # 标识注释的开始,井号后的部分都是注释
-
若类中包含 Java 注解,在 smali 文件中会以“# annotations”注释加以说明,接着会以 .annotation 指令开始,以 .end annotation 指令结束(声明一个注解)。.annotation 指令后跟着注解的类型和完整的签名,若类中有多个注解,则会有多个指令对
-
DEX 中的类包含类自己实现的实例方法“# direct methods”(用privat修饰的)和继承自父类的虚方法“# virtual methods”(用public和protected修饰的)。每个方法以 .method 指令开始,以 .end method 指令结束,.method 指令后跟着方法的访问权限和完整的签名 图中第199行表示方法的开始处,修饰符是static,访问权限是private,方法名是 assertMainThread, 参数为Ljava/lang/String;,V代表无返回值。 -
在一个方法中,除了真实执行的机器指令,还有其他指令,列举如下: .locals
:声明当前方法中使用的寄存器数目。对 DEX 中的每个方法,都可通过静态分析知道其使用了多少个寄存器。这样做的好处是,虚拟机执行 DEX 中类的方法时可提前为方法准备栈空间.param
:指定方法中的参数名,以便程序的调试。经过 Proguard(混淆工具)处理的 DEX 可能不含该信息 -
.prologue
:表示下面的部分是 DEX 指令.line
:保存 DEX 中的方法在 Java 源文件中的行号信息,以便调试。经过 Proguard 处理的 DEX 可能不含该信息
-
若一个类实现了接口,会在smali 文件中使用“ .implements
”指令指出,上述图中第六行
表明实现了Executor这个接口
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-
实例:SwitchCase -
实例代码:GitHub -
用 AndroidKiller 反编译实例 SwitchCase,然后打开反编译后的工程目录中的 smali/com/droider/switchcase/MainActivity.smali 文件,找到 packedSwitch() 的代码:
上述实例每句均带有注释,基本上都做好了分析,大家可对照注释一一学习
0x05 应用——smali插桩
-
使用上面的方法得到一个apk的smali文件 -
在关键部位添加自己的代码,需要遵循smili语法,例如在关键地方打log,输出关键信息 -
重新进行打包签名
0x06 总结
0x07 参考链接
E
N
D
关
于
我
们
Tide安全团队正式成立于2019年1月,是新潮信息旗下以互联网攻防技术研究为目标的安全团队,团队致力于分享高质量原创文章、开源安全工具、交流安全技术,研究方向覆盖网络攻防、系统安全、Web安全、移动终端、安全开发、物联网/工控安全/AI安全等多个领域。
团队作为“省级等保关键技术实验室”先后与哈工大、齐鲁银行、聊城大学、交通学院等多个高校名企建立联合技术实验室。团队公众号自创建以来,共发布原创文章370余篇,自研平台达到26个,目有15个平台已开源。此外积极参加各类线上、线下CTF比赛并取得了优异的成绩。如有对安全行业感兴趣的小伙伴可以踊跃加入或关注我们。
原文始发于微信公众号(Tide安全团队):静态分析android程序之阅读smali代码
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论