最近在分析一个名为MedicalApp的Android应用时,遇到了一个典型的native层加密案例。这个应用的所有核心逻辑都封装在so动态链接库中,使用了多种加密算法进行保护,包括RC4和XXTEA。这种设计在安全要求较高的医疗类应用中很常见,目的是防止关键业务逻辑被轻易逆向分析。
逆向过程中发现,应用提供了多个架构的so文件(arm64-v8a、armeabi-v7a等),但只有arm32位版本的代码可读性相对较好。即便如此,代码仍然经过了混淆处理,增加了分析难度。这种情况在实际工作中经常遇到——开发者会针对不同架构进行不同程度的混淆,有时候选择"不太流行"的架构版本反而能获得更好的逆向效果。
通过逆向分析so文件,我们定位到了三个关键函数:
z2: RC4算法的KSA(Key-Scheduling Algorithm)部分z3: RC4算法的PRGA(Pseudo-Random Generation Algorithm)部分z4: XXTEA加密算法实现这里有个有趣的发现:XXTEA的实现被刻意混淆了,乍看之下不像标准实现。但通过仔细分析数据流和控制流,确认它确实是常规的XXTEA算法。这种"伪装"是开发者常用的反逆向手段之一。
从内存dump或静态分析中,我们获取了以下关键数据:
XXTEA密钥:
code复制0x1, 0x10, 0x100, 0x1000
加密数据:
code复制0x68e5973e, 0xc20c7367, 0x98afd41b, 0xfe4b9de2,
0x1a5b60b, 0x3d36d646, 0xdbcc7baf, 0xa0414f00,
0x762ce71a
值得注意的是,这些数据都是以32位无符号整数的形式存储的,这在处理加密数据时需要特别注意字节序问题。
XXTEA(Corrected Block TEA)是TEA加密算法家族的一员,由David Wheeler和Roger Needham设计。它的特点是:
算法核心是那个看似复杂但实则精妙的混合函数:
c复制z = v[p] += (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)));
以下是完整的XXTEA解密C代码实现:
c复制#include <stdio.h>
#include <stdint.h>
#define DELTA 0x9F5776B6
void btea(uint32_t *v, int n, uint32_t const key[4]) {
uint32_t y, z, sum;
unsigned p, rounds, e;
if (n > 1) { /* 编码 */
rounds = 6 + 52/n;
sum = 0;
z = v[n-1];
do {
sum += DELTA;
e = (sum >> 2) & 3;
for (p=0; p<n-1; p++) {
y = v[p+1];
z = v[p] += (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)));
}
y = v[0];
z = v[n-1] += (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)));
} while (--rounds);
}
else if (n < -1) { /* 解码 */
n = -n;
rounds = 6 + 52/n;
sum = rounds*DELTA;
y = v[0];
do {
e = (sum >> 2) & 3;
for (p=n-1; p>0; p--) {
z = v[p-1];
y = v[p] -= (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)));
}
z = v[n-1];
y = v[0] -= (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)));
sum -= DELTA;
} while (--rounds);
}
}
int main() {
uint32_t v[9]= {0x68e5973e, 0xc20c7367, 0x98afd41b, 0xfe4b9de2,
0x1a5b60b, 0x3d36d646, 0xdbcc7baf, 0xa0414f00,
0x762ce71a};
uint32_t const k[4]= {0x1, 0x10, 0x100, 0x1000};
int n= 9;
btea(v, -n, k);
for (int i = 0; i < n; i++) {
for (int j = 0; j < 4; j++) {
printf("%02x ", (v[i] >> (j * 8)) & 0xFF);
}
}
return 0;
}
关键点说明:
n参数的正负表示加密/解密,绝对值表示数据块数sum值为rounds*DELTA,每轮递减执行后输出:
code复制56 04 b0 d4 9c 63 4d 30 96 ce c0 05 93 be 3b 82 52 4b 16 b2 8a 33 b7 4d 6d 7b 99 50 c2 b1 0c 12 e1 84 0a 93
RC4是一种流加密算法,广泛应用于SSL/TLS等协议中。它包含两个主要部分:
以下是RC4解密的Python实现:
python复制data = [0x56, 0x04, 0xb0, 0xd4, 0x9c, 0x63, 0x4d, 0x30,
0x96, 0xce, 0xc0, 0x05, 0x93, 0xbe, 0x3b, 0x82,
0x52, 0x4b, 0x16, 0xb2, 0x8a, 0x33, 0xb7, 0x4d,
0x6d, 0x7b, 0x99, 0x50, 0xc2, 0xb1, 0x0c, 0x12,
0xe1, 0x84, 0x0a, 0x93]
key = [0x1, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0,
0x0, 0x1, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0]
# KSA阶段
S = list(range(256))
j = 0
for i in range(256):
j = (j + S[i] + key[i % len(key)]) % 256
S[i], S[j] = S[j], S[i]
# PRGA阶段
i = j = 0
result = []
for char in data:
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
k = S[(S[i] + S[j]) % 256]
result.append(char ^ k)
print(''.join([chr(c) for c in result]))
关键注意事项:
执行后输出flag:
code复制flag{194836950ae9df840e8a94348b901a}
当遇到多个架构的so文件时,建议:
flag{194836950ae9df840e8a94348b901a}这个案例展示了典型的Android应用native层保护方案:多层加密+代码混淆+多架构差异化实现。破解的关键在于耐心分析、正确识别算法,以及选择合适的逆向工具链。