汤姆的苹果 - CTF APK逆向题解

学习 · 6 天前

题目简介

题目名称:汤姆的苹果

题目类型:Android APK逆向

考察知识点:Android逆向、异或加密、静态分析、Smali字节码理解


解题思路

这是一道典型的Android APK逆向题,主要考察点:

  1. APK文件结构解析
  2. Smali字节码的静态分析能力
  3. 简单异或加密的识别与破解

整体思路:

  • 解压/反编译APK获取核心代码
  • 定位关键验证逻辑(按钮点击事件处理)
  • 识别加密算法
  • 暴力破解或还原算法得到flag

详细解题步骤

步骤1:APK文件初步分析

首先将APK作为ZIP解压,观察目录结构:


汤姆的苹果_extracted/

├── AndroidManifest.xml

├── classes.dex          # 核心Dalvik字节码

├── res/                 # 资源文件

└── META-INF/            # 签名信息

步骤2:定位主Activity和关键代码

使用androguard静态分析,找到主Activity:


from androguard.misc import AnalyzeAPK

a, d, dx = AnalyzeAPK('汤姆的苹果.apk')

print(a.get_main_activity())

# 输出: com.example.myfirstc.MainActivity

MainActivity的onCreate方法逻辑:

  • 获取Button控件 (id=2131230807)
  • 获取EditText输入框 (id=2131230864)
  • 设置点击事件监听器 MainActivity$a

步骤3:深入分析点击事件监听器

MainActivity$a就是按钮点击事件的处理类,它会调用Lb/b/a/b类进行验证。

步骤4:发现核心加密验证逻辑

Lb/b/a/c类的handleMessage方法中,我们发现了关键的比较逻辑:


# 填充加密后的字符数组

fill-array-data      v0, +000001fh

fill-array-data-payload

  b'z\x00p\x00}\x00{\x00g\x00v\x00}\x00u\x00o\x00t\x00z\x00$\x00%\x00.\x00/\x00(\x00.\x00-\x00/\x00v\x00w\x00v\x00t\x00a\x00'

提取加密字符串:去掉0字节后得到密文:


zp}{gv}uotz$%./(.-/vwvta

步骤5:分析Lb/b/a/b加密类

<clinit><init>a方法中,发现了加密流程:


# 异或操作核心代码

aget-char                 v4, v3, v2

sget                      v5, Lb/b/a/b;->c I

xor-int/2addr             v4, v5    ; v4 = v4 XOR v5

int-to-char               v4, v4

aput-char                 v4, v3, v2

步骤6:识别加密算法

通过分析,我们发现这是固定值单字节异或加密

明文每个字符 ↔ 异或 ↔ 固定密钥值 ↔ 比较密文

步骤7:暴力破解密钥

由于是单字节异或,直接暴力枚举0-255所有可能:


encrypted = [ord(c) for c in 'zp}{gv}uotz$%./(.-/vwvta']

  

for key in range(256):

    result = []

    valid = True

    for b in encrypted:

        d = b ^ key

        if d < 32 or d > 126:

            valid = False

            break

        result.append(chr(d))

    if valid:

        flag = ''.join(result)

        if '{' in flag and '}' in flag:

            print(f'密钥 {key}: {flag}')

运行结果:


密钥  28 (0x1c): flag{jaishf89234213jkjh}

步骤8:验证解密正确性

手动验证解密过程(前6个字符):

| 位置 | 密文 | ASCII | 密钥 | 异或结果 | 明文 |

| 0 | z | 122 | 28 | 122 ^ 28 = 102 | f |

| 1 | p | 112 | 28 | 112 ^ 28 = 108 | l |

| 2 | } | 125 | 28 | 125 ^ 28 = 97  | a |

| 3 | { | 123 | 28 | 123 ^ 28 = 103 | g |

| 4 | g | 103 | 28 | 103 ^ 28 = 123 | { |

| 5 | v | 118 | 28 | 118 ^ 28 = 106 | j |

前6字符解密结果:flag{j,格式正确!


最终Flag


flag{jaishf89234213jkjh}

解题总结

本题考点

  1. Android逆向基础:理解APK结构、dex文件、Smali字节码
  2. 静态分析能力:能够通过字节码分析出程序流程
  3. 密码学基础:识别并破解简单的异或加密
  4. 工具使用:androguard、androguard等逆向工具的使用

关键突破点

  1. 定位handleMessage方法:这里存储了加密后的字符数组
  2. 识别异或加密xor-int/2addr指令是关键提示
  3. 暴力破解:单字节异或的密钥空间只有256种可能,暴力破解完全可行

可能的坑点

  1. 误以为是多字节异或(密钥是数组),浪费时间
  2. 误以为密钥是"tomato"或"apple"等题目相关关键词,走弯路
  3. 忽略了fill-array-data-payload中的0字节

解题脚本

完整的解密Python脚本:


# 加密字符串从smali中提取,去除0字节

encrypted_str = 'zp}{gv}uotz$%./(.-/vwvta'

encrypted = [ord(c) for c in encrypted_str]

  

# 单字节异或暴力破解

for key in range(256):

    flag = ''.join([chr(b ^ key) for b in encrypted])

    if 'flag{' in flag and '}' in flag:

        print(f'密钥={key}')

        print(f'Flag={flag}')

        break

运行结果:


密钥=28

Flag=flag{jaishf89234213jkjh}