全面详解 Smali(Android 专属汇编语言)

发布时间:2026/6/13 10:17:05

全面详解 Smali(Android 专属汇编语言) 目录一、基础认知什么是 Smali1. 诞生背景2. 核心特点3. 必备工具链入门必装二、Smali 文件整体结构文件格式1. 类声明 .class修饰符和 Java 一一对应类名规则安卓固定格式2. 源文件声明 .source可选3. 字段定义 .field对应 Java 成员变量语法基础数据类型对照表重中之重必须背示例4. 方法定义 .method核心90% 逆向都在改方法基础语法特殊方法名参数写法规则5. 寄存器声明 .registers / .local1.registers n2.local vx, 变量名:类型寄存器分类关键概念6. 注解 .annotation三、Smali 核心指令集高频必学指令1. 数据赋值指令最基础1) const 系列给寄存器赋常量2) move 系列寄存器之间传值2. 对象创建 实例化new-instance 创建对象调用构造方法 invoke-direct3. 方法调用指令四大 invoke逆向核心4. 字段读写get/put读字段 get写字段 put5. 运算指令加减乘除6. 跳转 条件判断分支逻辑无条件跳转条件跳转if 系列标签7. 返回指令 return8. 数组操作四、完整实战示例Java ↔ Smali 对照示例 1最简单方法示例 2if 判断逻辑五、Smali 学习路线 逆向实战用途1. 为什么安卓逆向必须学 Smali2. 入门学习顺序建议3. 常见入门修改案例练手六、常见坑 注意事项总结Smali 是Android Dalvik/ART 虚拟机的汇编语言也是安卓逆向、APK 破解、改包、脱壳、插桩、逆向分析必学核心。下面从原理、语法、指令、实操、常用场景完整讲解。一、基础认知什么是 Smali1. 诞生背景Android 应用源码Java/Kotlin编译流程Java/Kotlin 源码 → javac/kotlinc → .class 字节码 → dx/d8 工具 → .dex 文件 .dex 文件 → 安装到手机 → Dalvik/ART 虚拟机执行.dex是安卓虚拟机的可执行文件二进制格式人类无法直接阅读。Smali.dex的文本化汇编表示由baksmali反编译、smali回编译工具实现二进制 dex ↔ 文本 Smali互转。简单总结PC 端Java → Class 字节码Android 端Dex → Smali 汇编2. 核心特点面向寄存器架构区别于 x86/ARM 面向栈汇编Smali 大量使用虚拟寄存器。语法类汇编但带类 / 方法 / 字段面向对象特征兼容 Java OOP。纯文本、可直接修改、重新打包回 APK是安卓逆向最主流操作语言。区分Dalvik旧安卓和ARTAndroid 5.0 主流指令基本通用。3. 必备工具链入门必装baksmali / smalidex ↔ smali 转换核心工具ApktoolAPK 解包、资源反编译、smali 提取、重打包最常用JADXSmali → Java 源码对照学习必备边看 Java 边看 SmaliNotepad/VS Code Smali 高亮插件代码编辑二、Smali 文件整体结构文件格式一个标准.smali文件对应 Java 中的一个 Class 类整体分 6 大区块顺序固定1. 类声明.class定义当前类的访问权限、类名、父类、接口语法.class [访问修饰符] [类类型] L完整类名; .super L父类名; # 继承的父类 .implements L接口名; # 实现接口可多个修饰符和 Java 一一对应public公开private私有protected受保护static静态final不可继承 / 不可重写abstract抽象类interface接口类名规则安卓固定格式Java 包名.替换为/首尾加L和;示例Javacom.example.TestSmaliLcom/example/Test;示例.class public Lcom/demo/Hello; .super Ljava/lang/Object; .implements Ljava/lang/Runnable;2. 源文件声明.source可选标记该类对应哪个 Java 源文件混淆后的 APK 通常会删掉。.source Hello.java3. 字段定义.field对应 Java 成员变量分为实例字段和静态字段。语法# 普通成员变量 .field [修饰符] 变量名:类型; # 静态成员变量 .field [修饰符] static 变量名:类型;基础数据类型对照表重中之重必须背Java 类型Smali 类型标识说明booleanZ布尔byteB字节shortS短整型intI整型最常用longJ长整型占 2 个寄存器floatF浮点doubleD双精度占 2 个寄存器charC字符对象 / 类L 类名引用类型数组[类型一维数组[[ 二维数组示例# Java: private int a 10; .field private a:I 0xa # Java: public static String str; .field public static str:Ljava/lang/String; # Java: boolean[] arr; .field arr:[Z4. 方法定义.method核心90% 逆向都在改方法对应 Java 构造方法、普通方法、静态方法。基础语法.method [修饰符] 方法名(参数类型)返回值类型 # 方法体寄存器、指令、逻辑 .end method特殊方法名clinit静态代码块类加载时执行init构造方法实例化对象时执行参数写法规则参数连续拼接无分隔符最后接返回值。示例对照// Java public int add(int x, int y) { return xy; }# Smali .method public add(II)I .end method// Java: public void setStr(String s) public void setStr(Ljava/lang/String;)VVvoid无返回值5. 寄存器声明.registers/.localSmali 是寄存器架构所有运算、传参、变量都依赖虚拟寄存器。1.registers n声明整个方法一共使用 n 个寄存器写在方法第一行。2.local vx, 变量名:类型给局部寄存器起别名方便阅读混淆后常删除。寄存器分类关键概念Smali 寄存器分两类v 寄存器局部寄存器v0, v1, v2...存放局部变量、临时数据p 寄存器参数寄存器p0, p1, p2...存放方法入参规则非静态方法p0固定代表当前对象 this静态方法没有thisp0开始才是真正参数示例演示public class Demo{ public void test(int a){} }对应 Smali.method public test(I)V .registers 3 # 总寄存器数v0 v1 p0 p1 # p0 this # p1 入参 int a .end method记忆静态方法无 this非静态方法 p0 永远是 this。6. 注解.annotation对应 Java 注解逆向中一般忽略只做了解即可。三、Smali 核心指令集高频必学指令Smali 指令格式统一指令 目标寄存器, 源寄存器/常量下面按使用频率排序全是逆向日常用到的指令。1. 数据赋值指令最基础1) const 系列给寄存器赋常量const/4 v0, 0x0 # 4位小常量v0 0 const/16 v0, 0x100 # 16位常量 const v0, 0x12345678 # 32位整数常量 const-string v0, hello # 字符串赋值v0 hello2) move 系列寄存器之间传值move v0, v1 # v0 v1 move-object v0, v1 # 对象/引用类型赋值String、自定义类必须用 move-result v0 # 接收方法调用的返回值极常用2. 对象创建 实例化new-instance 创建对象# Java: String s new String(); new-instance v0, Ljava/lang/String;调用构造方法 invoke-directinit就是构造函数invoke-direct {v0}, Ljava/lang/String;-init()V3. 方法调用指令四大 invoke逆向核心根据方法权限 / 类型分为 4 种必须分清invoke-virtual调用普通 public/protected 实例方法最常见invoke-virtual {p0, v0}, Lcom/demo/Test;-setText(Ljava/lang/CharSequence;)V{p0,v0}参数列表第一个是 this后面是入参。invoke-direct调用private 方法、构造方法initinvoke-static调用static 静态方法不需要 thisinvoke-static {v0}, Ljava/lang/System;-currentTimeMillis()Jinvoke-interface调用接口方法调用完方法后有返回值必须搭配 move-resultinvoke-virtual {p0}, Lxxx;-getInfo()I move-result v0 # v0 接收返回的 int4. 字段读写get/put读写类的成员变量 / 静态变量读字段 getiget读取实例普通字段iget-object读取对象类型实例字段sget读取静态字段sget-object读取静态对象字段写字段 putiput写入实例普通字段iput-object写入实例对象字段sput写入静态字段sput-object写入静态对象字段示例# Java: this.num 10; const v1, 0xa iput v1, p0, Lcom/demo/Test;-num:I5. 运算指令加减乘除全部基于寄存器运算add-int v0, v1, v2 # v0 v1 v2 sub-int v0, v1, v2 # 减法 mul-int v0, v1, v2 # 乘法 div-int v0, v1, v2 # 除法 neg-int v0, v1 # 取反6. 跳转 条件判断分支逻辑对应 Javaif/else、for、whileSmali 全靠跳转指令实现。无条件跳转goto :label # 跳转到标签 :label 位置条件跳转if 系列if-eq v0, v1, :label # 相等则跳转 () if-ne v0, v1, :label # 不等则跳转 (!) if-lt v0, v1, :label # 小于则跳转 () if-gt v0, v1, :label # 大于则跳转 () if-le v0, v1, :label # 小于等于 () if-ge v0, v1, :label # 大于等于 () if-eqz v0, :label # v0 0 跳转 if-nez v0, :label # v0 ! 0 跳转超级常用判非空、判断布尔标签:label是跳转标记自定义名称以:开头。7. 返回指令 returnreturn-void # 无返回值 return; return v0 # 返回基础类型值 return-object v0 # 返回对象/字符串8. 数组操作new-array v0, v1, [I # 创建 int 数组 aget v0, v1, v2 # 读数组元素 aput v0, v1, v2 # 写数组元素四、完整实战示例Java ↔ Smali 对照示例 1最简单方法Java 代码public class Hello { public int calc(int a, int b) { return a b; } }对应完整 Smali.class public LHello; .super Ljava/lang/Object; .method public calc(II)I .registers 3 add-int v0, p1, p2 # p1a, p2b 相加 → v0 return v0 # 返回 v0 .end method示例 2if 判断逻辑Javapublic void check(int num){ if(num 10){ return; } // do something }Smali.method public check(I)V .registers 2 if-gt p1, 0xa, :cond_0 # num10 跳转到 cond_0 # 不满足条件执行代码 return-void :cond_0 return-void .end method五、Smali 学习路线 逆向实战用途1. 为什么安卓逆向必须学 SmaliAPK 改包核心改文字、改逻辑、去广告、破解会员、屏蔽弹窗都要改 Smali。脱壳分析加固 APK 脱壳后拿到的就是 Smali 代码。插桩 / 埋点Android 热修复、埋点、动态代理、HOOK 底层原理都是操作 Smali。对抗反调试、逆向分析分析恶意 APP、木马、风控逻辑只能读 Smali。Jadx 反编译出错时Java 代码乱码 / 解析失败只能靠原生 Smali 分析。2. 入门学习顺序建议熟记数据类型标识、寄存器规则p/v掌握const/move/invoke/get/put/if/goto/return七大高频指令拿简单 APK用 Apktool 解包JADX Smali 对照阅读尝试简单修改改字符串、修改判断条件比如if-nez改if-eqz实现逻辑翻转学习签名、重打包、安装测试形成闭环3. 常见入门修改案例练手去除启动页广告找到广告延时判断直接return-void破解简单会员找到isVip()方法固定返回true修改弹窗删除弹窗调用的invoke-virtual指令六、常见坑 注意事项寄存器数量不能乱改.registers数值必须和实际使用寄存器总数一致改错直接闪退。对象必须用 move-object /aget-object普通 move 会崩溃。long /double 占 2 个连续寄存器处理时不要跨寄存器读写。方法参数列表、类名、分号;漏写一个字符就打包失败。混淆后的 Smali类名 / 变量名变成 a、b、c逻辑不变耐心按指令逐行分析即可。总结Smali 本质是Android 虚拟机的汇编语言语法简洁、指令固定、面向寄存器 面向对象混合。 不用像 x86/ARM 汇编学复杂架构只要背熟类型、寄存器、高频指令配合 Java 对照练习一周即可上手基础修改与分析是安卓逆向、安全、APP 二次开发的入门必修课。

相关新闻