APK逆向分析-攻防世界安卓逆向CTF
字数 1267 2025-08-22 12:23:00

Android逆向分析实战教学文档

一、基础逆向分析方法

1.1 工具准备

  • 静态分析工具:JADX、JEB、Android Killer
  • 动态分析工具:Frida、Xposed
  • 辅助工具:apktool、smali2java

1.2 基本分析流程

  1. APK解包:使用apktool或直接拖入分析工具
  2. 代码查看
    • 使用JADX/JEB查看Java代码
    • 使用Android Killer查看smali代码
  3. 关键点定位
    • 查找MainActivity
    • 查找按钮点击事件
    • 查找字符串比较逻辑

二、CTF题目实战分析

2.1 Ph0en1x-100题目分析

关键代码:

getSecret(getFlag()).equals(getSecret(encrypt(sInput)))

解题步骤:

  1. 使用Frida hook getSecret方法:
Java.perform(function() {
    let MainActivity = Java.use("com.ph0en1x.android_crackme.MainActivity");
    MainActivity["getSecret"].implementation = function (string) {
        console.log('getSecret is called, string: ' + string);
        let ret = this.getSecret(string);
        console.log('getSecret ret value is ' + ret);
        return ret;
    };
});
  1. 分析发现getSecret是MD5加密
  2. 逆向逻辑:getFlag()encrypt(sInput)需要相等
  3. encrypt函数是ASCII减一操作,逆向处理:
s = 'ek`fz@q2^x/t^fn0mF^6/^rb`qanqntfg^E`hq|'
for i in range(0, len(s)):
    print(chr(ord(s[i])+1), end='')

2.2 ill-intentions题目分析

关键点:

  1. 广播接收器处理:
if (msgText.equalsIgnoreCase("ThisIsTheRealOne")) {
    // 启动对应Activity
}
  1. 正确的Activity包含native方法:
public native String perhapsThis(String str, String str2, String str3);
  1. 字符串处理逻辑:
def doBoth(input):
    return translate(customEncodeValue(input))

def translate(input):
    # 数字替换逻辑
    table = {1:'W', 2:'h', 3:'a', 4:'t', 5:'i', 6:'s', 7:'d', 8:'o', 9:'n', 0:'e'}
    # ...

解决方案:

  1. 修改smali添加日志输出:
const-string v0, "Message-"
invoke-static {v0, v6}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
  1. 使用adb触发广播:
adb shell am start -n com.example.hellojni/com.example.application.IsThisTheRealOne

2.3 ERROR404题目分析

关键加密逻辑:

public String a() {
    byte[] mid_flag = new byte[0x23];
    byte[] fake_flag = flag.getBytes();
    for(int i = 0x0; i < fake_flag.length; i = i + 0x1) {
        fake_flag[i] = (byte)((fake_flag[i] + 0x14) ^ (fake_flag[i] + 0x12));
        mid_flag[i] = (byte)((enc_flag[i] ^ (fake_flag[i] + 0x11)) - 0xb);
    }
    // ...
}

2.4 CTF-easy题目分析

关键点:

  1. 直接比较:
if(this.n.getText().toString().equals(this.i())) {
    // 正确
}
  1. 解密脚本:
p = [-40, -62, 107, 66, 0x82, ...]
q = [-57, -90, 53, -71, 0x8B, ...]
v2=[]
v4=[]
for i in range(len(p)):
    v2.append(p[i]^q[i])
v3 = v2[0]
# ...后续处理

2.5 献给最好的你题目分析

加密流程:

  1. 输入密码 → Base64编码
  2. 大小写转换
  3. AgfJA2vYz2fTztiWmtL3AxrOzNvUiq==比较

解密方法:

将目标字符串再次大小写转换后Base64解码

2.6 Easy-apk1题目分析

验证逻辑:

if (v0.length == 4 && v14.length() == 19 
    && Long.parseLong(xx1(v0[0]),16) + Long.parseLong(xx1(v0[1]),16) - Long.parseLong(xx1(v0[2]),16) == 0x11337452L
    && Long.parseLong(xx1(v0[0]),16) * Long.parseLong(xx1(v0[1]),16) == 0x10E02D1DAE11BF3CL
    && Long.parseLong(xx1(v0[2]),16) - Long.parseLong(xx1(v0[1]),16) == 0x1F3CBF1CL
    && md5(v0[3]).equals("b7e20e3e9d02209c9f3284cb29ed719d"))

xx1函数分析:

public static String xx1(String arg4) {
    char[] v0 = "0123456789ABCDEF".toCharArray();
    StringBuilder v1 = new StringBuilder("");
    byte[] v4 = arg4.getBytes();
    for(int v2 = 0; v2 < v4.length; ++v2) {
        v1.append(v0[(v4[v2] & 0xF0) >> 4]);
        v1.append(v0[v4[v2] & 15]);
    }
    return v1.toString().trim();
}

实际功能:将字符串转换为16进制表示

2.7 AreYouRich题目分析

密码生成逻辑:

byte[] v1 = new byte[]{0x40, 0x30, 0x30, 49};
String v8 = "abcdefghij";
byte[] v3 = v8.getBytes();
for (v5 = 0; v5 < v3.length; v5++) {
    v3[v5] = (byte)(v3[v5] ^ 34);
}
String a1 = new String(v3);
String a2 = new String(v1);
String password = a1 + a2;

解决方案:

  1. 修改smali代码绕过金钱检查
  2. 或逆向找到正确的用户名密码组合

三、高级技巧总结

3.1 Frida高级用法

  1. Hook构造函数:
Java.use("com.example.Class").$init.overload(...).implementation = ...
  1. 修改返回值:
let ret = this.method(args);
return modified_ret;

3.2 Smali修改技巧

  1. 条件判断修改:
# 原始
if-eqz v0, :cond_0

# 修改为
if-nez v0, :cond_0
  1. 常量修改:
const/4 v0, 0x0  # 改为0x1

3.3 动态调试技巧

  1. 使用adb logcat查看日志
  2. IDA Pro动态调试so文件
  3. 注入代码打印关键变量

四、常见加密算法识别

  1. MD5:32位哈希,常见于MessageDigest.getInstance("MD5")
  2. SHAMessageDigest.getInstance("SHA-1/SHA-256")
  3. Base64:特征字符集A-Za-z0-9+/,常以=结尾
  4. 异或加密:常见^运算符
  5. AES/DESCipher.getInstance("AES/DES")

五、实战注意事项

  1. 注意字符串编码问题(UTF-8/GBK)
  2. 注意大小端问题(尤其在so逆向中)
  3. 注意加解密顺序(如先Base64再异或)
  4. 注意代码混淆(名称混淆、控制流混淆)
  5. 多尝试不同工具交叉验证分析结果

六、附录:常用工具命令

  1. apktool
apktool d app.apk -o output_dir
apktool b output_dir -o new.apk
  1. adb
adb install app.apk
adb shell am start -n package/activity
adb logcat | grep "keyword"
  1. Frida
frida -U -f package -l script.js
frida-ps -U
  1. jarsigner
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore my.keystore app.apk alias_name
Android逆向分析实战教学文档 一、基础逆向分析方法 1.1 工具准备 静态分析工具 :JADX、JEB、Android Killer 动态分析工具 :Frida、Xposed 辅助工具 :apktool、smali2java 1.2 基本分析流程 APK解包 :使用apktool或直接拖入分析工具 代码查看 : 使用JADX/JEB查看Java代码 使用Android Killer查看smali代码 关键点定位 : 查找MainActivity 查找按钮点击事件 查找字符串比较逻辑 二、CTF题目实战分析 2.1 Ph0en1x-100题目分析 关键代码: 解题步骤: 使用Frida hook getSecret 方法: 分析发现 getSecret 是MD5加密 逆向逻辑: getFlag() 和 encrypt(sInput) 需要相等 encrypt 函数是ASCII减一操作,逆向处理: 2.2 ill-intentions题目分析 关键点: 广播接收器处理: 正确的Activity包含native方法: 字符串处理逻辑: 解决方案: 修改smali添加日志输出: 使用adb触发广播: 2.3 ERROR404题目分析 关键加密逻辑: 2.4 CTF-easy题目分析 关键点: 直接比较: 解密脚本: 2.5 献给最好的你题目分析 加密流程: 输入密码 → Base64编码 大小写转换 与 AgfJA2vYz2fTztiWmtL3AxrOzNvUiq== 比较 解密方法: 将目标字符串再次大小写转换后Base64解码 2.6 Easy-apk1题目分析 验证逻辑: xx1函数分析: 实际功能:将字符串转换为16进制表示 2.7 AreYouRich题目分析 密码生成逻辑: 解决方案: 修改smali代码绕过金钱检查 或逆向找到正确的用户名密码组合 三、高级技巧总结 3.1 Frida高级用法 Hook构造函数: 修改返回值: 3.2 Smali修改技巧 条件判断修改: 常量修改: 3.3 动态调试技巧 使用adb logcat查看日志 IDA Pro动态调试so文件 注入代码打印关键变量 四、常见加密算法识别 MD5 :32位哈希,常见于 MessageDigest.getInstance("MD5") SHA : MessageDigest.getInstance("SHA-1/SHA-256") Base64 :特征字符集 A-Za-z0-9+/ ,常以 = 结尾 异或加密 :常见 ^ 运算符 AES/DES : Cipher.getInstance("AES/DES") 五、实战注意事项 注意字符串编码问题(UTF-8/GBK) 注意大小端问题(尤其在so逆向中) 注意加解密顺序(如先Base64再异或) 注意代码混淆(名称混淆、控制流混淆) 多尝试不同工具交叉验证分析结果 六、附录:常用工具命令 apktool : adb : Frida : jarsigner :