注:本次学习来源于:52pojie的正己的《安卓逆向这档事》,部分知识来源于查资料或者chatgpt等ai
https://www.52pojie.cn/thread-1695141-1-1.html
https://github.com/ZJ595/AndroidReverse
https://aliyundrive.com/s/TJoKMK6du6x
JVM(Java Virtual Machine):
- 定义: Java 虚拟机是 Java 程序的运行环境,它提供了一个抽象的计算平台,使得 Java 程序能够在不同的硬件和操作系统上运行,实现了“一次编写,到处运行”的理念。
- 工作原理: JVM 接收 Java 编译器生成的字节码,并将其翻译成本地机器码,以在特定的硬件和操作系统上执行 Java 程序。
Dalvik:
- 定义: Dalvik 是 Google Android 操作系统上的一个虚拟机,用于执行 Android 应用程序的字节码。
- 工作原理: Dalvik 虚拟机使用基于寄存器的架构,与传统的基于堆栈的 Java 虚拟机(如标准的 JVM)有所不同。Android应用程序的代码首先会被编译成Java字节码(.class文件),然后通过Android开发工具链中的工具将Java字节码转换为Dalvik字节码(.dex文件),然后在 Android 设备上执行。
ART(Android Runtime):
- 定义: ART 是 Android 系统中的下一代运行时环境,取代了 Dalvik。ART 在 Android 5.0(Lollipop)及以后的版本中被引入为默认的运行时环境。
- 工作原理: 与 Dalvik 不同,ART 在应用安装时将字节码转换为本地机器码(Ahead-of-Time Compilation,AOT 编译),而不是在运行时即时编译。这有助于提高应用程序的性能,并减少在运行时的 CPU 和内存使用。ART 的引入带来了更好的性能、更低的功耗和更好的垃圾回收机制。
总体而言,JVM 是 Java 平台的标准虚拟机,而 Dalvik 和 ART 是针对 Android 平台的虚拟机和运行时环境。ART 的引入是为了提高 Android 设备上应用程序的性能和效率。
Android Runtime(ART)在 Android 应用程序安装时,将应用程序的字节码转换为本地机器代码,这一过程称为”Ahead-of-Time Compilation”(AOT 编译)。在 ART 中,这种预先编译的方式有助于提高 Android 应用程序的性能,并减少在运行时的 CPU 和内存使用。
具体步骤如下:
AOT 编译: 在 Android 应用程序安装时,ART 将 Dalvik 字节码转换为本地机器代码。这与 Dalvik 虚拟机的即时编译(Just-In-Time Compilation,JIT 编译)不同,JIT 编译是在应用程序运行时才将字节码转换为本地机器代码。
本地机器代码: 转换后的本地机器代码以及应用程序的其他资源被存储在设备上,这样在应用程序运行时就无需再进行实时的字节码到机器代码的转换,提高了应用程序的启动速度和执行效率。
执行: 在应用程序运行时,Android 系统执行已经转换为本地机器代码的应用程序,而不需要再解释和执行 Dalvik 字节码。
这种预先编译的方式是 ART 的一个重要特点,相较于 Dalvik 的即时编译,它带来了更好的性能、更低的功耗以及更好的垃圾回收机制。这也是为什么 Android 5.0(Lollipop)及以后版本中默认采用 ART 作为运行时环境的原因。
Smali 是一种与 Dalvik 虚拟机(现在逐渐被 ART 取代)相关的汇编语言,用于编写 Android 应用程序的 DEX 文件(Dalvik Executable)的人可读格式。DEX 文件包含 Dalvik 字节码,它是 Android 应用程序在运行时由 Dalvik 或 ART 运行时环境执行的二进制格式。
Smali语言允许开发者以文本形式编写Dalvik字节码的汇编代码。通过Smali,开发者可以查看和理解应用程序的Dalvik字节码,并进行反汇编、修改和分析。它提供了一种可读性更强、更易于理解和编辑的方式来操作Dalvik字节码。
Smali代码可以使用特定的工具(如smali/baksmali)进行转换,从Dalvik字节码到Smali代码的反汇编,以及从Smali代码到Dalvik字节码的汇编。
Smali的基础语法:
基本结构: Smali 代码以
.smali
为扩展名,每个.smali
文件通常对应一个类(Class)的 Dalvik 字节码。注释: 注释以
#
开头,可以是单行注释或放在行末。例如:1
2# 这是一个单行注释
const v0, 0x42 # 这是一条带有行末注释的指令寄存器: Dalvik 虚拟机使用寄存器进行操作,Smali 中的寄存器表示为
vN
,其中 N 是一个整数。例如:1
const v0, 0x42 # 将常量 0x42 存储到寄存器 v0 中
指令: 每一行都包含一个 Dalvik 字节码指令。指令的格式一般为:
1
<指令助记符> <目标寄存器>, <操作数1>, <操作数2>, ...
例如:
1
add-int v1, v2, v3 # 将 v2 和 v3 寄存器中的整数相加,结果存入 v1
标签: 标签用于标记代码的跳转目标,以冒号结尾。例如:
1
2
3:start
const v0, 0x42
goto :start方法定义: 方法定义包含方法的修饰符、返回值类型、方法名和参数列表。方法体用花括号包裹。例如:
1
2
3
4
5.method public static add(II)I
.registers 2
add-int v0, p0, p1
return v0
.end method字段引用: 引用字段时使用
sfield
(静态字段)或iget
(实例字段)指令。例如:1
sget-object v0, Lcom/example/Class;->staticField:Ljava/lang/String;
方法调用: 使用
invoke
指令调用方法,根据方法类型选择invoke-static
、invoke-direct
、invoke-virtual
等。例如:1
invoke-static {v0, v1}, Lcom/example/Class;->add(II)I
这只是 Smali 语法的一小部分,更详细的语法规则和指令集可以在 Smali 的官方文档或其他资源中找到。理解 Smali 语法对于进行 Android 应用程序的逆向工程和分析非常有帮助。
下面列出一些关键字及数字类型等
名称 | 注释 |
---|---|
.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 | 全称garden equal(a>=b),a大于或等于则跳 |
if-le | 全称little equal(a<=b),a小于或等于则跳 |
goto | 强制跳到指定位置 |
switch | 分支跳转,一般会有多个分支线,并根据指令跳转到适当位置 |
iget | 获取寄存器数据 |
# 寄存器 | |
在 Smali 中,寄存器是用来存储和处理数据的虚拟寄存器。这些虚拟寄存器用于在 Dalvik 字节码中执行各种操作。以下是有关 Smali 寄存器的详细说明: |
寄存器标识: 寄存器用
vN
表示,其中 N 是一个非负整数。例如,v0
、v1
、v2
等。常见寄存器:
v0
到v15
:这些是普通的虚拟寄存器,用于存储局部变量和中间计算结果。p0
到p<n>
:这些是参数寄存器,用于存储方法的参数。例如,p0
是第一个参数,p1
是第二个参数,以此类推。
寄存器分配: 在 Smali 代码中,通过
.registers
指令来定义寄存器的数量。例如:1
.registers 4
寄存器类型: 虚拟寄存器可以存储不同类型的数据,包括整数、浮点数、对象引用等。在使用寄存器之前,通常需要使用
.local
或.parameter
指令声明寄存器的类型。例如:1
.local v0, "integerVariable":I
寄存器的作用域: 寄存器的作用域通常限定在方法的范围内。在一个方法中定义的寄存器在该方法的整个生命周期内可用。
寄存器的使用: 寄存器用于存储临时变量、方法参数和中间计算结果。例如,下面的 Smali 代码演示了将两个寄存器中的整数相加并将结果存储到另一个寄存器的操作:
1
add-int v2, v0, v1 # 将 v0 和 v1 寄存器中的整数相加,结果存储到 v2
寄存器重用: Dalvik 虚拟机会在需要时自动重用寄存器,因此在 Smali 代码中,同一个寄存器可能在不同的位置用于存储不同的数据。
寄存器的生命周期: 寄存器的生命周期由其作用域决定。在方法执行期间,局部变量寄存器用于存储临时值,方法结束时这些寄存器的内容将被销毁。
总体而言,Smali 寄存器是 Dalvik 字节码中的虚拟寄存器,用于在方法执行期间存储和处理数据。在编写 Smali 代码时,理解寄存器的分配、作用域和类型是非常重要的。
因为在之前已经安装了LSPosed,之后再装核心破解的app,再点击通知栏模块未启用的通知,进去启用,勾选系统框架,再重启即可。
之后因为签名验证导致无法安卓也能安装成功了
1 | adb install 教程demo(更新).apk |
第二关的任务是收集硬币并完成一键3连,长按之后弹出请先充值大会员哦!
,所以一般只需定位到字符串,之后修改跳转逻辑
实验使用jadx-gui,文本搜索大会员
此外还可以通过开发者助手,先界面资源分析,之后赋值按钮的十六进制,再通过MT管理器搜索,搜索类型整数,选择十六禁止,即可。
破解的方法可以有几种:修改判断、强制跳转、修改寄存器的值
- 修改判断: 比如if-ge改为if-le,if-eqz改为ifnez
- 强制跳转:使用goto,比如
goto :label_name
(比如在vip功能执行之前加个标签:goto_666
,之后再函数开头的地方直接goto :goto_666
) - 修改寄存器的值:如果是基于寄存器进行判断,可以修改寄存器,从而使判断逆转,比如将下面
const/4 v0, 0x0
修改为const/4 v0, 0x1
1 | .method public final isvip()Z |