一直对android的逆向分析很感兴趣,这些年也陆陆续续反编译了一些android的项目,今天开始对这方面的知识做一下总结。先从android的apk文件开始讲起。
APK文件
android工程编译完成会得到我们想要的apk安装包,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文件
可以直接在Dalvik虚拟机上加载运行的文件,由java文件经过IDE编译生成。Dalvik虚拟机的指令码不是标准的Jvm指令码,而是使用了自己独有的一套指令集(类似汇编语言),这个也是我们今天要讲的重点。dex文件中共用了很多类名称,常量字符串,使它的体积更小,运行效率更高。
resources.arsc文件
二进制资源文件,包括字符串等。
Smali简介
Dalvik虚拟机和Jvm一样,也有自己的一套指令集,类似汇编语言,但是比汇编简单许多,只要你会java,了解android的相关知识,就可以轻松的看懂,如果得到这些汇编文件呢,利用apktool或者dex2jar工具包(网上很多),反编译classes.dex文件,就可以得到以smali为后缀的文件,这些smali文件就是Dalvik的寄存器语言。
Smali文件结构解
Smali文件与java中的类是一一对应的,包括内部类和匿名内部类也会生成对应的smali文件(典型的比如实现某个接口的匿名内部类),所以你会看到.smali文件比.java文件更多。
smali文件是由Dalvik指令组成的,它有自己的一套规则,它的指令都是以“.”开头,常用的指令如下:
指令 | 说明 |
---|---|
.class | 包名+类名 |
.super | 父类类名 |
.source | 源文件名称 |
.implements | 接口实现 |
.field | 定义字段 |
.method/.end method | 方法的开始与结束 |
.locals | 方法内使用的v开口的寄存器个数 |
.prologue | 表示方法中代码的开始处 |
.line | 对应java中的行数 |
.param | 指定了方法的参数 |
.paramter | 和.paramter含义相同 |
.param | 指定了方法的参数 |
.annotation/.end annotation | 注解的开始和结束 |
现在来看下smali文件的结构:
1.头文件
格式如下:
.class <访问权限修饰符> [非权限修饰符] <类名>
.super <父类名>
.source <源文件名称>
访问权限修饰符即所谓的public,protected,private,而非权限修饰符则指的是final,abstract,static,两者都可以为空。
举例如下:
.class public final Llutey/FTPServer/preferences/PreferencesFactory;
.super Ljava/lang/Object;
.source "PreferencesFactory.java"
如果原java代码有经过混淆,那一般.class里面的类名和.source的源文件名会不一样,以下是经过混淆的(类名正常是xxx/PreferencesFactory,混淆以后变成xxx/d):
.class public final Llutey/FTPServer/preferences/d;
.super Ljava/lang/Object;
.source "PreferencesFactor
2.接口实现
格式如下:
#interfaces
.implements <接口名称>
举例如下:
# interfaces
.implements Landroid/view/View$OnClickListener;
其中# interfaces为注释
3.注解
如果一个类中使用了注解,就会出现.annotation,格式如下:
#annotations
.annotation [注解的属性] <注解类名>
[注解字段=值]
...
.end annotation
举例如下:
# annotations
.annotation build Landroid/annotation/TargetApi;
value = 0xb