2025数字中国创新大赛-移动互联网(APP)安全积分争夺赛决赛 Writeup
字数 1639 2025-08-30 06:50:35
2025数字中国创新大赛-移动互联网(APP)安全积分争夺赛决赛Writeup解析
1. crackme题目解析
关键函数分析
定位到关键函数verify_system_password,使用了CCCrypt函数进行AES加密。
AES加密分析
CCCrypt函数原型及相关枚举量:
- 加密算法:AES
- 操作模式:CBC模式(根据上下文推断)
- 填充方式:PKCS7Padding(iOS默认)
解密方法
由于题目使用了标准AES加密,只需获取以下信息即可解密:
- 密钥(Key)
- 初始化向量(IV)
- 加密模式
- 填充方式
解密脚本示例(Python):
from Crypto.Cipher import AES
import base64
def decrypt_aes(ciphertext, key, iv):
cipher = AES.new(key, AES.MODE_CBC, iv)
plaintext = cipher.decrypt(ciphertext)
return plaintext.rstrip(b'\0') # 去除可能的填充
2. ezapk题目解析
流量包分析
从流量包中提取出APK文件,使用jadx反编译。
验证逻辑
验证逻辑在so文件中,分析发现是魔改的RC4算法。
RC4魔改点
- S数组初始化顺序:1→255→0(标准RC4是0→255)
- 输入处理:对连续相同字符进行类似长度编码的操作
解密方法
- 还原魔改的RC4初始化过程:
def rc4_init(key):
S = list(range(256))
# 魔改的初始化顺序
j = 0
for i in range(1, 256): # 从1开始
j = (j + S[i] + key[i % len(key)]) % 256
S[i], S[j] = S[j], S[i]
# 最后处理0
i = 0
j = (j + S[i] + key[i % len(key)]) % 256
S[i], S[j] = S[j], S[i]
return S
- 处理输入的长度编码:
def decode_input(encoded):
# 示例:flag{aa_bbb_cccc_dddd_hahahaha}
# 需要根据实际动调结果编写解码逻辑
pass
3. Task_get_vip题目解析
DEX释放逻辑
APK运行时会在/data/user/0/com.example.wyy/files/yongye.dex释放一个DEX文件。
验证逻辑
在com.example.wyy.ui.play.PlayFragment中找到验证逻辑:
- 使用MP3文件的MD5前6位作为RC4密钥
- 对数据进行RC4解密
解题步骤
- 提取MP3文件
- 计算MD5哈希并取前6位作为密钥
- 使用标准RC4解密数据
示例代码:
import hashlib
def get_key(mp3_file):
with open(mp3_file, 'rb') as f:
data = f.read()
md5 = hashlib.md5(data).hexdigest()
return md5[:6].encode()
# 然后使用标准RC4解密
4. taskDB题目解析
数据库加密
使用android-database-sqlcipher组件加密SQLite数据库。
密码生成逻辑
密码为APK签名的MD5值,位于com.example.managepatients.utils.SecureDatabaseHelper类中。
解题步骤
- 提取APK签名
- 计算MD5得到数据库密码
- 使用密码打开SQLite数据库
- 修改用户密码为电话号码(需分析密码存储处理逻辑)
密码存储处理逻辑示例:
// 伪代码,需根据实际分析
String storedPassword = md5(phoneNumber + salt);
5. taskdecode题目解析
恶意Service分析
定位到com.example.weather.util.SsService,其中dVar2.o(encrypt)对外发送加密数据。
加密层次
- Java层:魔改的Chacha20
- Native层:魔改的RC4
Native层RC4魔改点
- S数组初始化过程执行两次
- j的计算加上了S[j]
解密脚本关键点:
# 魔改的RC4初始化
def modified_rc4_init(key):
S = list(range(256))
j = 0
# 第一次初始化
for i in range(256):
j = (j + S[i] + S[j] + key[i % len(key)]) % 256 # 魔改点:加上了S[j]
S[i], S[j] = S[j], S[i]
# 第二次初始化
for i in range(256):
j = (j + S[i] + S[j] + key[i % len(key)]) % 256
S[i], S[j] = S[j], S[i]
return S
6. SignalScope题目解析
整体流程
- MainActivity启动HttpServer
- 对POST数据调用Native的
aaa方法加密后对比
Native层加密分析
- 获取APK签名
- 对签名进行两次SHA256和一次SHA1
- 使用结果生成RSA参数(p,q)
- 进行RSA加密
- 对p,q进行MD5得到AES的key和iv
- 使用AES加密数据
解密步骤
- 提取APK签名
- 计算SHA256和SHA1得到p,q
- 计算MD5得到AES密钥和IV
- 逆向RSA和AES加密过程
关键代码示例:
import hashlib
from Crypto.Cipher import AES
from Crypto.PublicKey import RSA
# 1. 获取APK签名
signature = get_apk_signature()
# 2. 计算哈希
sha256_1 = hashlib.sha256(signature).digest()
sha256_2 = hashlib.sha256(sha256_1).digest()
sha1 = hashlib.sha1(signature).digest()
# 3. 生成RSA参数
p = int.from_bytes(sha256_1 + sha256_2, 'big')
q = int.from_bytes(sha1, 'big')
# 4. 生成AES参数
md5_p = hashlib.md5(str(p).encode()).digest()
md5_q = hashlib.md5(str(q).encode()).digest()
aes_key = md5_p[:16]
aes_iv = md5_q[:16]
# 5. AES解密
cipher = AES.new(aes_key, AES.MODE_CBC, aes_iv)
plaintext = cipher.decrypt(ciphertext)
通用解题技巧总结
-
加密算法识别:
- AES:通常有固定块大小(16字节),可能使用CBC/ECB模式
- RC4:流密码,常见S盒初始化过程
- RSA:涉及大素数操作,模幂运算
-
魔改算法分析:
- 对比标准算法实现
- 关注初始化过程、S盒生成、密钥调度等关键点
- 动态调试验证猜测
-
密钥来源分析:
- 硬编码字符串
- 文件哈希(如APK签名、资源文件)
- 设备信息(IMEI、MAC地址等)
-
动态分析技巧:
- 使用Frida hook加密函数
- 使用IDA动态调试so文件
- 监控文件操作(如释放的DEX文件)
-
数据流追踪:
- 从输入点追踪到加密点
- 从加密点回溯密钥生成过程
- 关注跨语言调用(Java-Native)的数据转换