ykrishhh/android-reverse-engineering

GitHub: ykrishhh/android-reverse-engineering

一份涵盖 APK 分析、Smali、Frida 及 Xposed 的 Android 逆向工程完整实战指南与代码工具包。

Stars: 0 | Forks: 0

# Android 逆向工程工具包 [![GitHub stars](https://img.shields.io/github/stars/ykrishhh/android-reverse-engineering?style=social)](https://github.com/ykrishhh/android-reverse-engineering) [![GitHub forks](https://img.shields.io/github/forks/ykrishhh/android-reverse-engineering?style=social)](https://github.com/ykrishhh/android-reverse-engineering/network/members) [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT) [![Platform](https://img.shields.io/badge/Platform-Android-3DDC84?logo=android)](https://www.android.com/) [![Frida](https://img.shields.io/badge/Dynamic%20Analysis-Frida-black)](https://frida.re) [![Xposed](https://img.shields.io/badge/Framework-Xposed-yellow)](https://github.com/rovo89/Xposed) [![Discord](https://img.shields.io/badge/Discord-Community-5865F2?logo=discord)](https://discord.gg/android-re) 这是我刚开始接触 Android 应用逆向时希望能拥有的所有东西。包含实用的工作流、可直接复制粘贴的代码片段,以及真正好用的工具配置。 ## 目录 - [环境配置与工具](#setup--tools) - [APK 分析工作流](#apk-analysis-workflow) - [静态分析](#static-analysis) - [Smali 基础](#smali-basics) - [Frida 动态插桩](#frida-dynamic-instrumentation) - [Xposed 框架](#xposed-framework) - [Kernel Hooking 概念](#kernel-hooking-concepts) - [DEX 文件格式](#dex-file-format) - [Native 库分析](#native-library-analysis) - [反调试绕过](#anti-debug-bypasses) - [练习应用](#practice-apps) - [资源](#resources) - [免责声明](#disclaimer) ## 环境配置与工具 在任何平台上进行 Android 逆向工程所需的基础工具。 ### 核心工具安装 ``` # --- Linux / macOS --- # jadx — Dex 到 Java 反编译器 brew install jadx # macOS sudo apt install jadx # Debian/Ubuntu # apktool — APK 资源解码器和重打包工具 brew install apktool # macOS sudo apt install apktool # Debian/Ubuntu # Android SDK (adb, dexdump 等) # 从 https://developer.android.com/studio 下载 # Frida pip install frida-tools frida # dex2jar # 从 https://github.com/pxb1988/dex2jar/releases 下载 # --- Termux (Android) --- pkg install jadx apktool dex2jar pip install frida-tools frida objection ``` ### 推荐工具列表 | 工具 | 用途 | 安装方式 | |------|---------|---------| | **jadx** | 将 DEX 反编译为可读的 Java 源码 | `brew install jadx` | | **apktool** | 解码/重构 APK 资源、Smali | `brew install apktool` | | **Frida** | 动态插桩和 hooking | `pip install frida-tools` | | **Xposed Framework** | 无需修改 APK 的系统级 hooking | [GitHub](https://github.com/rovo89/Xposed) | | **Objection** | 基于 Frida 的移动安全工具包 | `pip install objection` | | **dex2jar** | 将 DEX 转换为 JAR 以便进行 Java 分析 | [GitHub](https://github.com/pxb1988/dex2jar) | | **JEB Pro** | 商业 Android 反编译工具 (AST, Smali, Java) | [网站](https://www.pnfsoftware.com/) | | **Ghidra** | 免费的逆向工程套件 — 反编译 native .so 库 | [GitHub](https://github.com/NationalSecurityAgency/ghidra) | | **IDA Pro** | 用于 native code 的工业级标准反汇编器 | [Hex-Rays](https://hex-rays.com/ida-pro/) | | **Burp Suite** | 用于 API 拦截的 HTTP/HTTPS 代理 | [PortSwigger](https://portswigger.net/burp) | ## APK 分析工作流 我针对每个 APK 遵循的逐步流程。每次都很有效。 ``` APK File │ ├─→ 1. RENAME to .zip, EXTRACT │ └─→ AndroidManifest.xml, classes.dex, lib/, res/ │ ├─→ 2. DECOMPILE with jadx │ └─→ Readable Java source code │ ├─→ 3. DECODE RESOURCES with apktool │ └─→ Smali code, decoded XML, layouts │ ├─→ 4. ANALYZE with dex2jar + JD-GUI │ └─→ Browse decompiled JAR interactively │ ├─→ 5. HOOK at runtime with Frida │ └─→ Bypass SSL pinning, dump data, trace calls │ └─→ 6. PATCH Smali and REBUILD └─→ apktool b modified_apk/ -o patched.apk ``` ### 快速开始命令 ``` # 反编译为 Java 源代码 jadx -d output/ target.apk # 解码为 Smali + 资源 apktool d target.apk -o decoded/ # 将 DEX 转换为 JAR d2j-dex2jar target.apk -o target-d2j.jar # 重新构建修改后的 APK apktool b decoded/ -o patched.apk # 对重新构建的 APK 进行签名 apksigner sign --ks my-key.keystore patched.apk # 安装到设备 adb install patched.apk ``` ## 静态分析 在不运行的情况下阅读和理解代码。 ### Manifest 分析 ``` # 解码 AndroidManifest.xml apktool d target.apk cat decoded/AndroidManifest.xml ``` 需要检查的关键项: - **权限**:`uses-permission` 声明能暴露应用的功能权限 - **导出组件**:`android:exported="true"` — 可被其他应用访问 - **Intent 过滤器**:定义哪些 intent 会触发组件 - **Debuggable 标志**:`android:debuggable="true"` 启用调试附加 - **网络安全配置**:明文流量规则 ### jadx 深入探索 ``` # 带资源反编译 jadx --deobf -d output/ target.apk # 在所有 class 中搜索特定字符串 grep -r "api_key\|secret\|password\|token" output/sources/ # 查找硬编码 URL grep -r "http://" output/sources/ | grep -v "https://" ``` ### 隐藏 API 枚举 ``` # 列出所有导出的 activities, services, receivers aapt dump badging target.apk | grep -E "activity|service|receiver" # 完整的 permission 转储 aapt dump permissions target.apk ``` ## Smali 基础 Smali 是 Android Dalvik/ART 虚拟机的汇编语言。学习 Smali 是“我能看懂代码”和“我能修改代码”之间的分水岭。 ### Smali 语法参考 ``` # Class 声明 .class public Lcom/example/MyClass; .super Ljava/lang/Object; .source "MyClass.java" # Method 签名 # method_name(param1_type, param2_type)return_type .method public login(Ljava/lang/String;Ljava/lang/String;)Z .locals 4 # .locals defines register count (v0..v3 + p0..p1) # p0 = "this" (for non-static methods) # p1, p2 = method parameters # String assignment const-string v0, "admin" # Method invocation invoke-virtual {p1, v0}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z move-result v1 # Conditional branch if-eqz v1, :fail # Return true const/4 v0, 0x1 return v0 :fail const/4 v0, 0x0 return v0 .end method ``` ### 常见 Smali 指令 | 指令 | 含义 | |-------------|---------| | `const-string v0, "text"` | 将字符串加载到寄存器 | | `const/4 v0, 0x1` | 加载整型常量 | | `invoke-virtual {v0, v1}, L...;->method(L...;)V` | 调用实例方法 | | `invoke-static {v0}, L...;->method()V` | 调用静态方法 | | `move-result v0` | 将返回值移动到寄存器 | | `return v0` | 从方法返回值 | | `return-void` | 返回 void | | `if-eqz v0, :label` | 寄存器等于零时跳转 | | `if-nez v0, :label` | 寄存器不等于零时跳转 | | `goto :label` | 无条件跳转 | | `iget-object v0, p0, L...;->field:L...;` | 读取对象字段 | | `iput v0, p0, L...;->field:I` | 写入整型字段 | ### 实战:绕过登录检查(Smali 补丁) ``` # BEFORE (原始登录 method): .method public checkCredentials(Ljava/lang/String;)Z .locals 2 invoke-virtual {p0, p1}, Lcom/app/Auth;->validate(Ljava/lang/String;)Z move-result v0 return v0 .end method # AFTER (已 patch — 始终返回 true): .method public checkCredentials(Ljava/lang/String;)Z .locals 2 const/4 v0, 0x1 return v0 .end method ``` ## Frida 动态插桩 Frida 将 JavaScript 注入到运行中的进程,实现实时的 hooking 和追踪。在几乎每次任务中,这都是我首选的工具。 ### 环境配置 ``` pip install frida-tools frida # 验证服务器是否在设备上运行 adb push frida-server--android- /data/local/tmp/ adb shell "chmod 755 /data/local/tmp/frida-server" adb shell "/data/local/tmp/frida-server &" ``` ### SSL Pinning 绕过 ``` // ssl_bypass.js — Bypass SSL certificate pinning Java.perform(function() { var TrustManagerImpl = Java.use("com.android.org.conscrypt.TrustManagerImpl"); TrustManagerImpl.verifyChain.implementation = function(untrustedChain, trustAnchorChain, host, clientAuth, ocspData, tlsSctData) { console.log("[+] SSL pinning bypassed for: " + host); return untrustedChain; }; var SSLContext = Java.use("javax.net.ssl.SSLContext"); SSLContext.init.overload("[Ljavax.net.ssl.KeyManager;", "[Ljavax.net.ssl.TrustManager;", "java.security.SecureRandom").implementation = function(km, tm, sr) { console.log("[+] SSLContext initialized with custom TrustManager"); this.init(km, tm, sr); }; // OkHttp3 pinning try { var CertificatePinner = Java.use("okhttp3.CertificatePinner"); CertificatePinner.check.overload("java.lang.String", "java.util.List").implementation = function(hostname, peerCertificates) { console.log("[+] OkHttp3 pinning bypassed for: " + hostname); }; } catch(e) {} }); ``` ``` frida -U -l ssl_bypass.js -f com.target.app ``` ### 方法追踪 ``` // trace_methods.js — Log all calls to a class Java.perform(function() { var TargetClass = Java.use("com.target.app.AuthManager"); var methods = TargetClass.class.getDeclaredMethods(); methods.forEach(function(method) { var methodName = method.getName(); TargetClass[methodName].overloads.forEach(function(overload) { overload.implementation = function() { console.log("[*] " + methodName + "(" + Array.from(arguments).join(", ") + ")"); var result = this[methodName].apply(this, arguments); console.log("[*] " + methodName + " returned: " + result); return result; }; }); }); }); ``` ### 字符串解密 ``` // decrypt_strings.js — Hook encryption methods and log plaintext Java.perform(function() { var CryptoUtils = Java.use("com.target.app.CryptoUtils"); CryptoUtils.decrypt.overload("java.lang.String").implementation = function(encrypted) { var result = this.decrypt(encrypted); console.log("[DECRYPT] " + encrypted + " -> " + result); return result; }; }); ``` ### Root 检测绕过 ``` // root_bypass.js — Circumvent common root checks Java.perform(function() { var RootDetection = Java.use("com.target.app.Security"); // Bypass isRooted() RootDetection.isRooted.implementation = function() { console.log("[+] isRooted() forced false"); return false; }; // Bypass SafetyNet / Play Integrity try { var SafetyNet = Java.use("com.google.android.gms.safetynet.SafetyNetApi"); SafetyNet.attest.overload().implementation = function() { console.log("[+] SafetyNet attest bypassed"); return null; }; } catch(e) {} }); ``` ### Objection — 让 Frida 更简单 ``` pip install objection # 启动 objection 会话 objection -g com.target.app explore # 绕过 SSL pinning android sslpinning disable # Root 检测绕过 android root disable # 列出 activities android hooking list activities # 监控文件访问 android hooking watch file_access ``` ## Xposed 框架 Xposed 通过在框架级别修改 Android 运行时 (ART) 来实现系统级的 hooking。LSPosed 才是你想要的 —— 原版的 Xposed 基本上已经死了。 ### 安装(已 Root 的设备) ``` # 安装 LSPosed (现代化的 Xposed fork) # 从 https://github.com/LSPosed/LSPosed/releases 下载 # 通过 recovery 或 adb 安装 adb push LSPosed-v1.9.2.zip /sdcard/ # 通过 TWRP recovery 刷入 # 或者使用 Magisk Manager 安装 Zygisk + LSPosed 模块 ``` ### 示例 Xposed 模块 ``` // Example: Intercept WebView URL loading package com.example.xposedhook; import de.robv.android.xposed.IXposedHookLoadPackage; import de.robv.android.xposed.XC_MethodHook; import de.robv.android.xposed.XposedBridge; import de.robv.android.xposed.XposedHelpers; import de.robv.android.xposed.callbacks.XC_LoadPackage; public class WebViewHook implements IXposedHookLoadPackage { @Override public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) { if (!lpparam.packageName.equals("com.target.app")) return; // Hook WebView.loadUrl() XposedHelpers.findAndHookMethod( "android.webkit.WebView", lpparam.classLoader, "loadUrl", String.class, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) { String url = (String) param.args[0]; XposedBridge.log("[WebView] Loading: " + url); // Redirect to our proxy if (url.contains("target.com")) { param.args[0] = url.replace("target.com", "attacker-proxy.com"); } } } ); } } ``` ### Hook SharedPreferences ``` // Intercept SharedPreferences reads XposedHelpers.findAndHookMethod( "android.app.SharedPreferencesImpl", lpparam.classLoader, "getString", String.class, String.class, new XC_MethodHook() { @Override protected void afterHookedMethod(MethodHookParam param) { String key = (String) param.args[0]; String value = (String) param.getResult(); XposedBridge.log("[SharedPrefs] " + key + " = " + value); } } ); ``` ## Kernel Hooking 概念 适用于当用户态 hooking 不足以满足需求时的深度系统级插桩。大多数人不需要用到它,但当你需要时,它是无可替代的。 ### Linux Kernel Tracepoints ``` // Example: Using kprobes to trace system calls #include #include static int handler_pre(struct kprobe *p, struct pt_regs *regs) { printk(KERN_INFO "[TRACE] openat called with arg: %s\n", (char *)regs->regs[1]); return 0; } static struct kprobe kp = { .symbol_name = "do_sys_openat2", .pre_handler = handler_pre, }; static int __init trace_init(void) { return register_kprobe(&kp); } static void __exit trace_exit(void) { unregister_kprobe(&kp); } ``` ### eBPF (Extended Berkeley Packet Filter) ``` // eBPF program to trace file opens (BCC syntax) #include #include struct event_t { u32 pid; char filename[256]; }; BPF_PERF_OUTPUT(events); int trace_open(struct pt_regs *ctx) { struct event_t event = {}; event.pid = bpf_get_current_pid_tgid() >> 32; bpf_probe_read_user_str(&event.filename, sizeof(event.filename), (void *)PT_REGS_PARM1(ctx)); events.perf_submit(ctx, &event, sizeof(event)); return 0; } ``` ### 概念总结 | 层级 | 技术 | 工具 | |-------|-----------|------| | 用户态 | 函数 hooking、JNI 拦截 | Frida, Xposed | | 框架层 | ART 方法替换 | LSPosed 模块 | | Native (ELF) | GOT/PLT 补丁、inline hook | Frida Gadget, Substrate | | Kernel | kprobes, tracepoints, eBPF | bcc, bpftrace | | 硬件层 | JTAG/SWD、内存转储 | OpenOCD, JTAGulator | ## DEX 文件格式 理解 Dalvik Executable 格式对于高级补丁操作至关重要。大多数人会跳过这一步,但之后就会吃大亏。 ### DEX 结构概览 ``` DEX File ├── Header (magic, checksum, SHA-1, file size) ├── String IDs (all string literals) ├── Type IDs (class/interface references) ├── Proto IDs (method prototypes) ├── Field IDs (field references) ├── Method IDs (method references) ├── Class Definitions (one per class) │ ├── class_idx │ ├── access_flags │ ├── superclass_idx │ ├── source_file_idx │ ├── class_data │ │ ├── static_fields │ │ ├── instance_fields │ │ ├── direct_methods │ │ └── virtual_methods │ └── code_item (bytecode) ├── Data Section (annotations, etc.) └── Map List (section offsets) ``` ### 使用 Python 解析 DEX ``` #!/usr/bin/env python3 """Minimal DEX header parser""" import struct def parse_dex_header(filepath): with open(filepath, 'rb') as f: magic = f.read(8) checksum = struct.unpack(' ykrishhh 维护 — 安全研究员与开发者

标签:Android逆向工程, Docker支持, Frida, Xposed, 云安全监控, 目录枚举, 移动安全, 静态分析