当前位置: 首页 > news >正文

关于 smali:3. Smali 与 APK 结构理解

一、APK 解包工具:apktool, jadx, dex2jar

当我们拿到一个 APK 文件进行逆向时,通常的目标是:

  • 分析 Java 层源码(逻辑、加密、通信等)

  • 修改资源或 Smali 代码实现功能修改

  • 尝试定位加固方式、脱壳、定位敏感函数

而实现这些目标,需要用到不同的工具来解析 APK 的不同部分。

1.1 工具 1:apktool —— 解包 & 重打包 + Smali 分析

功能:

  • 反编译 APK 为 Smali 代码

  • 提取 AndroidManifest.xml 和资源文件(res、assets)

  • 支持修改后再 重新打包 APK

输出内容:

myapp/
├── AndroidManifest.xml       ← 已反编译的清晰 XML
├── smali/                    ← Smali 代码目录
├── res/                      ← layout、drawable 等资源
├── assets/                   ← 加密配置、脚本文件等
└── original/                 ← META-INF 等签名信息

使用方式:

apktool d myapp.apk -o myapp
apktool b myapp -o newapp.apk

优点:

  • 结构清晰,可修改资源文件和 Smali

  • 支持重打包,非常适合二次修改

  • 可搭配签名工具重新签名

缺点:

  • 无法恢复 Java 源码(Smali 是汇编级中间代码)

1.2 工具 2:jadx —— Java 源码查看神器(GUI + CLI)

功能:

  • 将 DEX 文件反编译为 Java 源码

  • 提供 GUI 界面浏览、搜索类、方法、字符串

  • 也可以命令行导出所有 Java 代码

使用方式:

GUI 方式(推荐):

jadx-gui myapp.apk
  • 可搜索类名、字符串、方法名

  • 可定位到 Java 层代码逻辑

  • 可导出为整个项目 .java 文件

CLI 导出:

jadx -d output_dir myapp.apk

优点:

  • Java 源码级别还原,阅读体验好

  • 快速定位加密函数、网络通信、关键逻辑

  • 可搜索代码片段、敏感 API 使用等

缺点:

  • 不是 100% 恢复原代码,变量名、结构可能会乱

  • 不能直接用于修改和重打包

1.3 工具 3:dex2jar + jd-gui —— 老牌 Java 源码还原工具链

功能:

  • 将 DEX 文件转换为 .jar

  • 用 Java 反编译工具查看 .jar 的 Java 源码

使用方式:

dex2jar myapp.apk -o myapp.jar

然后用 jd-gui 打开生成的 JAR 文件查看源码。

优点:

  • 最早的 Java 源码查看方式之一

  • jd-gui 查看变量、函数较直观

缺点:

  • dex2jar 在处理多 dex / 新版 APK 时容易出错

  • jd-gui 不如 jadx-gui 强大(不能搜索,UI 老旧)

1.4 工具之间的配合策略

目标使用工具说明
阅读 Java 代码jadx-gui推荐第一步,快速理解逻辑
修改资源或代码apktool提取 smali/res/,修改再打包
深度分析/自动脚本apktool + fridaSmali Hook、定位类名
压缩包分析(手动)unzip APK解压 apk 查看 META-INF / assets 手工分析
生成 .jar 查看dex2jar + jd-gui不推荐主力使用,适合老项目

1.5 推荐的完整工作流

  • apktool d myapp.apk → 拿到 Smali + 资源 + Manifest

  • jadx-gui myapp.apk → 找 Java 关键函数、参数、逻辑

  • 分析混淆/加密 → 对照 Smali 和 Java 定位加壳/关键代码

  • 修改 Smali 或资源 → 用 apktool 修改后 b 打包

  • 重新签名 APK(使用 apksignerjarsigner

1.6 实战举例

实战目的使用方式
找到某个 API Token 的加载逻辑jadx 搜索字符串 → 定位 Java 函数
修改登录校验apktool 找到 Smali → 修改跳过检查
Hook 某个函数jadx 找类名函数名 → Frida 脚本注入
脱壳分析加固apktool 查看 Manifest + Smali → 判断加固方案
恢复加密算法实现jadx 找 Java 加密逻辑 → Smali 跟踪字段流

二、APK 编译 / 反编译流程(反编译到 smali,修改后重新打包)

2.1 整体流程概览

要做的是:

原始 APK → [反编译] → Smali 代码 & 资源文件 → [修改] → [重新打包] → 签名 → 安装运行测试

用的核心工具是:

  • apktool负责 APK → Smali & 资源 的反编译、再打包

  • keytool / apksignerAPK 签名

  • 模拟器或真机:测试打包后的 APK

2.2 反编译 APK 到 Smali

工具:apktool

命令:

apktool d your_app.apk -o your_app_src

反编译结果目录结构:

your_app_src/
├── AndroidManifest.xml   ← Android 应用的配置文件(反编译后的 XML)
├── smali/                ← 主 dex 的 Smali 代码
├── smali_classes2/       ← 第二个 dex(如有)
├── res/                  ← 应用 UI 资源
├── assets/               ← 各种配置、脚本、加密数据
├── unknown/              ← 非标准结构
└── original/             ← 原始 META-INF 信息等

2.3 修改 Smali 或资源

可以修改的内容包括:

内容路径示例
Java逻辑smali/修改跳过登录校验
字符串res/values/strings.xml修改 App 名
布局res/layout/改按钮显示
ManifestAndroidManifest.xml增加权限等

示例:跳过登录逻辑

找到如下 Smali 函数:

.method public isLogin()Z.locals 1const/4 v0, 0x1    # 改成返回 truereturn v0
.end method

2.4 重新打包 APK

命令:

apktool b your_app_src -o new_app.apk

这将把修改过的 Smali + 资源重新打包成一个新的 APK。

2.5 给 APK 签名(非常关键)

Android 不允许安装未签名 APK,必须使用 debug 签名或你自己的 keystore。

1)使用 debug 签名快速签名:

# 如果你用的是 Android SDK,自带 debug.keystore
apksigner sign --ks ~/.android/debug.keystore --ks-key-alias androiddebugkey --ks-pass pass:android --key-pass pass:android --out signed_new_app.apk new_app.apk

2)自己生成签名:

# 生成签名(仅需一次)
keytool -genkey -v -keystore my-release-key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias myalias

签名命令:

apksigner sign --ks my-release-key.jks --out signed.apk new_app.apk

2.6 安装并测试 APK

adb install -r signed.apk

或者将 APK 拖进模拟器中测试(如雷电、夜神、Pixel)。

2.7 常见问题

问题解决方式
安装失败:未签名一定要使用 apksigner 签名
打包失败:资源异常检查 res/ 文件是否手动修改破坏结构
安装后闪退使用 logcat 查看崩溃日志
找不到类路径检查是否为 smali_classes2 或其他目录

2.8 补充技巧:快速调试 Smali 改动

  • 给函数添加日志:
const-string v0, "TAG"
const-string v1, "Login function called!"
invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
  • 替换函数返回值(绕过登录):
const/4 v0, 0x1
return v0
  • 强制跳转 Activity(改 Intent)

2.9 小结 

  • apktool 反编译 APK 为 Smali + 资源

  • 修改 Smali 或资源文件以实现绕过或定制

  • 使用 apktool b 打包、apksigner 签名

  • 安装并调试新 APK,结合 logcat 分析


三、Manifest 与资源文件分析

3.1 AndroidManifest.xml 分析详解

APK 中的 AndroidManifest.xml 是核心配置文件,控制应用的权限、组件、入口点等信息。通过 apktool 反编译后,它会变成可读的 XML,路径如下:

your_app/
├── AndroidManifest.xml

Manifest 的主要组成部分

<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.app"android:versionCode="10"android:versionName="1.0.0"><!-- 权限声明 --><uses-permission android:name="android.permission.INTERNET"/><uses-permission android:name="android.permission.READ_SMS"/><!-- 特性声明 --><uses-feature android:name="android.hardware.camera" android:required="false"/><!-- 应用声明 --><applicationandroid:label="@string/app_name"android:icon="@mipmap/ic_launcher"android:allowBackup="true"><!-- 主入口 Activity --><activity android:name=".MainActivity"><intent-filter><action android:name="android.intent.action.MAIN"/><category android:name="android.intent.category.LAUNCHER"/></intent-filter></activity><!-- 其他组件 --><activity android:name=".LoginActivity"/><service android:name=".MyService"/><receiver android:name=".AlarmReceiver"/><provider android:name="androidx.core.content.FileProvider"android:authorities="com.example.app.fileprovider"android:exported="false"/></application>
</manifest>

Manifest 可分析的关键点

项目作用用途
package应用包名定位主类、资源路径
<uses-permission>声明权限判断敏感操作(如读短信、网络、相机)
<application>应用入口看启动配置、资源入口
<activity>声明 Activity找到界面跳转逻辑入口
<service>后台服务检查是否有后台恶意逻辑
<receiver>广播监听是否监听短信、系统事件等
<provider>文件或数据库访问接口判断是否有导出风险点

示例:如何通过 Manifest 快速定位入口类?

<activity android:name=".MainActivity"><intent-filter><action android:name="android.intent.action.MAIN"/><category android:name="android.intent.category.LAUNCHER"/></intent-filter>
</activity>

主界面是 .MainActivity,真实路径是:

smali/com/example/app/MainActivity.smali

3.2 res 目录资源文件分析

资源文件主要用于界面布局、文字、图片等。路径:

your_app/
├── res/
│   ├── layout/           # XML 界面布局
│   ├── values/           # 字符串、颜色、样式等
│   ├── drawable*/        # 图片资源
│   ├── mipmap*/          # 启动图标等

layout 目录(布局 XML)

<!-- res/layout/activity_login.xml -->
<LinearLayout ... ><TextView android:text="@string/login_title"/><EditText android:id="@+id/username"/><EditText android:id="@+id/password"/><Button android:onClick="doLogin"/>
</LinearLayout>
  • 可以帮助你快速识别按钮/控件绑定的方法名

  • 比如 onClick="doLogin"LoginActivity.smali 里找 doLogin 方法

values 目录(字符串/样式)

<!-- res/values/strings.xml -->
<resources><string name="app_name">极验验证器</string><string name="login_title">请输入账号密码</string>
</resources>
  • 用于分析文本提示、隐藏字符串等

  • Java/Smali 中引用方式:@string/app_nameR.string.app_name

drawable/mipmap(图标/图片资源)

  • drawable 通常为按钮背景、状态图标

  • mipmap 是 APP 图标ic_launcher.png

可用工具查看其中是否嵌入敏感信息,比如二维码、恶意图标伪装等。

3.3 资源 ID 映射机制(R.java 与 Smali 的关系)

  • Java 中:R.layout.activity_login

  • 编译后:0x7f0a0010(整数资源 ID)

  • 在 Smali 中的使用方式:

const v0, 0x7f0a0010
invoke-virtual {p0, v0}, Lcom/example/app/MainActivity;->setContentView(I)V

可以通过 jadx-gui 打开 APK 找到 R.java 对应的映射关系来反查 ID。

实战分析思路总结

场景Manifest 线索res 线索后续操作
找主界面<intent-filter>MainActivitylayout XML 中 onClick 函数进入 smali 分析函数
判断功能权限uses-permission 中包含 READ_SMSRECORD_AUDIO检查是否监听短信/语音等
监听短信广播<receiver>SmsReceiver分析是否有钓鱼或信息拦截
定位文件导出风险点<provider android:exported="true">判断是否有任意文件读取风险点
找图形验证码组件layout 中 ImageView、Buttonlayout/activity_login.xml分析点击事件和图像加载逻辑

3.4 小结:Manifest + 资源分析的意义

  •  快速定位关键组件入口(Activity/Service/Receiver)

  •  判断敏感权限申请与组件导出(安全评估)

  •  配合布局文件找 UI 操作对应方法(逆向入口)

  •  结合 Smali 对照分析逻辑代码


四、Dex 文件格式基础(了解 Smali 背后是 Dalvik bytecode)

什么是 DEX 文件?

  • DEX 是 Android 平台用于执行的二进制格式的字节码文件,由 Java 编译而来。

  • 一个 APK 中可能有一个或多个 DEX 文件(比如 classes.dex, classes2.dex 等)。

  • 它是 Dalvik 虚拟机(早期 Android)ART(Android Runtime) 执行的对象。

4.1 DEX 文件的整体结构

一个 DEX 文件的结构如下图:

+--------------------+
| Header             |  # dex 文件头部
+--------------------+
| String IDs         |  # 所有字符串索引表
+--------------------+
| Type IDs           |  # 所有类型(类)索引表
+--------------------+
| Proto IDs          |  # 所有方法签名(参数/返回类型)
+--------------------+
| Field IDs          |  # 所有字段(类成员变量)
+--------------------+
| Method IDs         |  # 所有方法的签名
+--------------------+
| Class Definitions  |  # 每个类的结构体定义
+--------------------+
| Data Section       |  # 所有字节码、常量、注解等原始数据
+--------------------+

所有这些部分都以**“索引+引用+数据”**的方式来组织,这就解释了为什么在 Smali 里经常看到 .field, .method, .proto, .string, .type 等信息。

4.2 关键字段详细说明

段名说明对应 Smali
Header包含 magic、版本、校验和等信息与 Smali 无直接关系
String IDs所有字符串常量,如类名、方法名、字段名.method, .field 中用到的字符串
Type IDs所有类型(如 Ljava/lang/String;所有类/参数类型
Proto IDs方法的签名(参数类型+返回值)方法声明部分 .method public test(II)V
Field IDs类字段:所属类 + 名称 + 类型.field public name:Ljava/lang/String;
Method IDs方法签名(所属类 + 名称 + 签名).method public test(I)V
Class Defs每个类的信息:字段、方法、超类等每个 .smali 文件
Data Section字节码、注解、数组、调试信息.locals, 指令等都是来自这里

4.3 从 Java 到 DEX 到 Smali 的关系图

// Java代码
public int sum(int a, int b) {return a + b;
}

编译成 DEX(字节码):

[method_id] sum (II)I
[proto_id]  params: int, int → return: int
[code_item] add-int v0, p1, p2

反编译成 Smali:

.method public sum(II)I.locals 1add-int v0, p1, p2return v0
.end method

可以看到:

DEX 字节码结构Smali 表现说明
method_id.method方法定义
proto_id(II)I参数签名
code_item指令块add-int / return
field_id.field成员变量
string_id方法名、字段名、类名被引用的字符串

4.4 DEX 中的字节码与 Smali 指令对应

Smali 指令DEX 字节码行为说明
const v0, 1加载常量立即数加载
move v0, p1寄存器移动值拷贝
add-int v0, v1, v2两数相加算术操作
return v0方法返回指定值返回
invoke-virtual {p0}, Lxxx;->method()V虚方法调用方法跳转
iget v0, p0, Lxxx;->field:I获取成员字段对象字段读取
sput v0, Lxxx;->staticField:I写静态字段静态变量写入

4.5 为什么需要理解DEX 格式?

  • 更深入理解 Smali 指令意义(知道它来源于哪段 DEX 字节码)

  • 定位问题更方便(某个类 Smali 错误,找其 DEX 结构)

  • 参与二进制级分析(脱离 Smali,直接 patch DEX)

  • 配合 tools(baksmali、dexdump、dex2jar)分析数据段、方法偏移等

4.6 小结

内容意义
DEX 是 Dalvik/ART 的执行格式所有 Smali 指令来源
每个类在 DEX 中有一个 ClassDefSmali 对应一个 class
所有调用/变量/类/方法 都是“索引+引用”机制提高执行效率和体积压缩
DEX 格式理解有助于进阶分析DEX Patch、反调试、脱壳等
http://www.xdnf.cn/news/675091.html

相关文章:

  • LWIP 中,lwip_shutdown 和 lwip_close 区别
  • 深入剖析Java CompletableFuture:原理、陷阱与高并发场景优化指南
  • R语言基础| 可视化初探(ggplot2)
  • 预测式外呼与自动外呼的区别
  • 【博客系统】博客系统第十弹:实现对数据库存储的用户密码进行加密功能、更新登录接口的密码校验功能
  • 【监控】pushgateway中间服务组件
  • openresty+lua+redis把非正常访问的域名加入黑名单
  • threejs顶点UV坐标、纹理贴图
  • SQL Server 和 MySQL 对比
  • 实现单例模式的6种方法(Python)
  • 开源多模态新标杆——BAGEL本地部署教程:7B参数撬动万亿数据
  • 《算法和数据结构》算法篇
  • 车载通信网络 --- OSI模型:网络层
  • SQL 查询慢的常见原因分析
  • 【新品发布】嵌入式人工智能实验箱EDU-AIoT ELF 2正式发布
  • 机器学习-决策树
  • 洛谷 P5091:【模板】扩展欧拉定理
  • MacOS内存管理-删除冗余系统数据System Data
  • 第六章 文件的其他操作命令
  • 计算机组成原理——CISC与RISC
  • 【基于STM32的新能源汽车智能循迹系统开发全解析】
  • 什么是DevOps的核心目标?它如何解决传统开发与运维之间的冲突?​
  • 使用java8开发mcp server
  • 让学习回归到技术上来(技术 !=== 死记硬背)
  • name ‘selective_scan_fn‘ is not defined运行出现这个错误
  • 修改 Ubuntu Installer 从串口输出的方法
  • 电子邮箱设置SSL:构建邮件传输的加密护城河
  • Qwen2.5-VL视觉-语言模型做图片理解调研
  • 深入解析Spring Boot与Redis的集成实践
  • 麒麟系统 Linux(aarch64处理器)系统java项目接入海康SDK问题