一、Android应用程序架构
安卓应用程序使用JAVA语言编写。安卓的SDK工具负责将你编写的代码,用到的数据和资源文件编译进APK文件中。apk文件包含了一个安卓应用程序的所有内容,并且被安卓设备用来安装应用程序。
apk实际上就是一个标准的zip格式,修改后缀名,进行解压就可以看到内部结构。
如上图所示,每个文件夹都有各自不同的作用。
assets文件夹
保存一些额外的资源文件,如游戏的声音文件,字体文件等等,在代码中可以用AssetManager获取assets文件夹的资源。
lib文件夹
存放用C/C++编写的,用NDK编译生成的so文件,供java端调用。
META-INF文件夹
存放apk签名信息,用来保证apk包的完整性和系统安全。
在IDE编译生成一个apk包时,会对里面所有的文件做一个校验计算,并把计算结果存放在META-INF文件夹内,apk在安装的时候,系统会按照同样的算法对apk包里面的文件做校验,如果结果与META-INF里面的值不一样,系统就不会安装这个apk,这就保证了apk包里的文件不能被随意替换。
res文件夹
存放资源文件,包括icon,xml文件。
AndroidManifest.xml文件
应用程序配置文件,每个应用都必须定义和包含的,它描述了应用的名字、版本、权限、引用的库文件等信息。
classes.dex文件
传统Class文件是由一个Java源码文件生成的.Class文件,而Android是把所有Class文件进行合并优化,然后生成一个最终的class.dex文件。它包含APK的可执行代码,是分析Android软件时最常见的目标。
resources.arsc文件
二进制资源文件,包括字符串等。
二、何为smali语言?
smali是将Android字节码用可阅读的字符串形式表现出来的一种语言,可以称之为Android字节码的反汇编语言。
利用apktool或者Android Killer工具,反编classes.dex文件,就可以得到以smali为后缀的文件。
通过对smali文件的解读可以获取源码的信息。
三、如何将Java文件转换成smali文件?
打开idea,依次点击菜单栏上的File->Settings->Plugins->Marketplace,下载java2smali插件。下载好后重启idea。
新建一个class文件,简单写一个demo类。
鼠标放到demo类中,依次点击菜单栏上的Build->Compile to Smali,则会自动生成一个.smali文件。
四、如何看懂smali代码?
用Java简单写了一个demo类,Demo.class文件
package com.crawler;
public class Demo {
public static void main(String[] args) {
Demo demo = new Demo();
Integer calc = demo.calc(1);
System.out.println(calc);
}
private Integer calc(Integer i){
++i;
return i;
}
}
自动转换生成的Demo.smali文件
.class public Lcom/crawler/Demo;
.super Ljava/lang/Object;
.source “Demo.java”
.method public constructor ()V
.registers 1
.prologue
.line 3
invoke-direct {p0}, Ljava/lang/Object;->()V
return-void
.end method
.method private calc(Ljava/lang/Integer;)Ljava/lang/Integer;
.registers 3
.param p1, “i” # Ljava/lang/Integer;
.prologue
.line 12
invoke-virtual {p1}, Ljava/lang/Integer;->intValue()I
move-result v0
add-int/lit8 v0, v0, 0x1
invoke-static {v0}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;
move-result-object p1
.line 13
return-object p1
.end method
.method public static main([Ljava/lang/String;)V
.registers 4
.param p0, “args” # [Ljava/lang/String;
.prologue
.line 6
new-instance v1, Lcom/crawler/Demo;
invoke-direct {v1}, Lcom/crawler/Demo;->()V
.line 7
.local v1, "demo":Lcom/crawler/Demo;
const/4 v2, 0x1
invoke-static {v2}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;
move-result-object v2
invoke-direct {v1, v2}, Lcom/crawler/Demo;->calc(Ljava/lang/Integer;)Ljava/lang/Integer;
move-result-object v0
.line 8
.local v0, "calc":Ljava/lang/Integer;
sget-object v2, Ljava/lang/System;->out:Ljava/io/PrintStream;
invoke-virtual {v2, v0}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V
.line 9
return-void
.end method
smali语言基础语法
示例1: .class关键字
.class public Lcom/crawler/Demo;
这是一个公开类,在com.crawler包下的Demo类。
L 表示类
示例2: .super关键字
.super Ljava/lang/Object;
父类是Object,所有的类都继承Object类。
示例3: .source关键字
.source “Demo.java”
当前类的源文件名。
示例4: .method关键字和.end method关键字
# direct methods
.method public constructor ()V
.registers 1
.prologue
.line 3
invoke-direct {p0}, Ljava/lang/Object;->()V
return-void
.end method
这是一个构造方法。
每个类都会有一个构造方法,虽然在java中省略了。
public Demo(){
super();
}
.method开始,.end method结束。
V 表示void。
invoke-direct 表示调用方法。其后{}表示传入的参数。
p0 在构造方法中表示this,指一个对象。
示例5: .registers关键字
.registers 1
表示寄存器有1个
示例6: .registers关键字
.prologue
代表函数的开始位置,其上为类似.registers的关键字,其下为函数逻辑。
示例7: .line N关键字
.line 3
代表还原成java代码在源文件第3行
作者:爬虫入坑记
链接:https://juejin.cn/post/7117281589721038879
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。