安卓那档事01
认识APK
apk,全称Android Package,相当于一个压缩文件,zip后缀和rar后缀都可以解压。
对于一个常见的apk,解压后可以看到:
目录/文件 | 注释 |
---|---|
assets | 里面存放的是apk的静态资源文件,比如视频,音频,图片等 |
lib | 里面存放了不同框架下使用的so文件,文件是由c或cpp编译的动态链接库。 armeabi-v7a基本通用所有android设备,arm64-v8a只适用于64位的android设备,x86常见用于android模拟器 |
META-INF | 保存了签名信息的文件,一般主要用于验证apk完整性 |
res | 存放资源文件,包括图片,字符串等等。apk的样子也一般由其中的layout文件设计。 |
AndroidManifest.xml | APK的应用清单信息,它描述了应用的名字,版本,权限,引用的库文件等等信息 |
classes.dex | classes.dex是java源码编译后生成的java字节码文件,APK运行的主要逻辑 |
resources.arsc | resources.arsc是编译后的二进制资源文件,它是一个映射表,映射着资源和id,通过R文件中的id就可以找到对应的资源 |
像上图的kotlin文件夹,说明这个apk全部功能或者部分功能是由kotlin开发的。
双开APK
双开:简单来说,就是手机同时运行两个或多个相同的应用,例如同时运行两个微信
原理 | 解释 |
---|---|
修改包名 | 让手机系统认为这是2个APP,这样的话就能生成2个数据存储路径,此时的多开就等于你打开了两个互不干扰的APP |
修改Framework | 对于有系统修改权限的厂商,可以修改Framework来实现双开的目的,例如:小米自带多开 |
通过虚拟化技术实现 | 虚拟Framework层、虚拟文件系统、模拟Android对组件的管理、虚拟应用进程管理 等一整套虚拟技术,将APK复制一份到虚拟空间中运行,例如:平行空间 |
以插件机制运行 | 利用反射替换,动态代{过}{滤}理,hook了系统的大部分与system—server进程通讯的函数,以此作为“欺上瞒下”的目的,欺骗系统“以为”只有一个apk在运行,瞒过插件让其“认为”自己已经安装。例如:VirtualApp |
汉化APK
汉化:使用专门的工具对外文版的软件资源进行读取、翻译、修改、回写等一系列处理,使软件的菜单、对话框、提示等用户界面显示为中文,而程序的内核和功能保持不变,这个过程即为软件汉化
基本上字符串都是在arsc里,建议一键汉化,然后再润色。 少量没汉化到的字符串可以使用工具去定位去逐个汉化
初识AndroidManifest.xml
AndroidManifest.xml文件是整个应用程序的信息描述文件,定义了应用程序中包含的Activity,Service,Content provider和BroadcastReceiver组件信息。
每个应用程序在根目录下必须包含一个AndroidManifest.xml文件,且文件名不能修改。它描述了package中暴露的组件,他们各自的实现类,各种能被处理的数据和启动位置。
属性 | 定义 |
---|---|
versionCode | 版本号,主要用来更新,例如:12 |
versionName | 版本名,给用户看的,例如:1.2 |
package | 包名,例如:com.zj.52pj.demo |
uses-permission android:name="" | 应用权限,例如:android.permission.INTERNET 代表网络权限 |
android:label="@string/app_name" | 应用名称 |
android:icon="@mipmap/ic_launcher" | 应用图标路径 |
android:debuggable="true" | 应用是否开启debug权限 |
了解JVM、Dalvik、ART
- JVM是JAVA虚拟机,运行JAVA字节码程序
- Dalvik是Google专门为Android设计的一个虚拟机,Dalvik有专属的文件执行格式dex(Dalvik executable)
- Art(Android Runtime)相当于Dalvik的升级版,本质与Dalvik无异
smali
smali是Dalvik的寄存器语言,smali代码是dex反编译而来的。
关键字
名称 | 注释 |
---|---|
.class | 类名 |
.super | 父类名,继承的上级类名名称 |
.source | 源名 |
.field | 变量 |
.method | 方法名 |
.register | 寄存器 |
.end method | 方法名的结束 |
public | 公有 |
protected | 半公开,只有同一家人才能用 |
private | 私有,只能自己使用 |
.parameter | 方法参数 |
.prologue | 方法开始 |
.line xxx | 位于第xxx行 |
数据类型对应
smali类型 | java类型 | 注释 |
---|---|---|
V | void | 无返回值 |
Z | boolean | 布尔值类型,返回0或1 |
B | byte | 字节类型,返回字节 |
S | short | 短整数类型,返回数字 |
C | char | 字符类型,返回字符 |
I | int | 整数类型,返回数字 |
J | long (64位 需要2个寄存器存储) | 长整数类型,返回数字 |
F | float | 单浮点类型,返回数字 |
D | double (64位 需要2个寄存器存储) | 双浮点类型,返回数字 |
string | String | 文本类型,返回字符串 |
Lxxx/xxx/xxx | object | 对象类型,返回对象 |
常用指令
关键字 | 注释 |
---|---|
const | 重写整数属性,真假属性内容,只能是数字类型 |
const-string | 重写字符串内容 |
const-wide | 重写长整数类型,多用于修改到期时间。 |
return | 返回指令 |
if-eq | 全称equal(a=b),比较寄存器ab内容,相同则跳 |
if-ne | 全称not equal(a!=b),ab内容不相同则跳 |
if-eqz | 全称equal zero(a=0),z即是0的标记,a等于0则跳 |
if-nez | 全称not equal zero(a!=0),a不等于0则跳 |
if-ge | 全称greater equal(a>=b),a大于或等于则跳 |
if-le | 全称little equal(a<=b),a小于或等于则跳 |
goto | 强制跳到指定位置 |
switch | 分支跳转,一般会有多个分支线,并根据指令跳转到适当位置 |
iget | 获取寄存器数据 |
1 |
|
简单跟着吾爱作者分析了一下。
寄存器
在smali里的所有操作都必须经过寄存器来进行:本地寄存器用v开头数字结尾的符号来表示,如v0、 v1、v2。 参数寄存器则使用p开头数字结尾的符号来表示,如p0、p1、p2。特别注意的是,p0不一定是函数中的第一个参数,在非static函数中,p0代指“this",p1表示函数的第一个 参数,p2代表函数中的第二个参数。而在static函数中p0才对应第一个参数(因为Java的static方法中没有this方法)
学习链接:
https://www.52pojie.cn/thread-1695796-1-1.html
https://www.52pojie.cn/thread-1701353-1-1.html