JAR 文件逆向与多阶段爆破
一、环境准备与文件分析
拿到 `.jar` 文件,先用 `unzip` 解压查看结构,发现 `com/company` 包下共 11 个 class 文件,其中 `Main` 是入口类。使用 `jadx` 反编译,得到可读 Java 源码。
二、第一阶段:爆破 4 字符 Key
1、关键代码分析
Main.java 核心逻辑:
String in = sc.nextLine(); // 读 4 字符输入
String t = new String(in.getBytes());
for (byte e : encode.digest(t.getBytes())) { // SHA-1 哈希
password = password + String.format("%02x", Byte.valueOf(e));
}
if (Check.checkPassword(password)) { ... }Check.java 目标哈希:
private static String t = "caf4cbafdf72ce0f2f2eadc4309916e8c96f0de8";2、验证 SHA-1 实现正确性
Nazo.java实现了完整 SHA-1,但存在填充差异。先用标准向量验证:
import hashlib
h = hashlib.sha1(b"abc").hexdigest()确认目标哈希就是标准 SHA-1(Nazo 的自定义填充不影响短字符串结果)。
结果:a9993e364706816aba3e25717850c26c9cd0d89d。
3、暴力破解
import hashlib, string
target = "caf4cbafdf72ce0f2f2eadc4309916e8c96f0de8"
chars = string.printable.strip() # 95 个可打印字符
for c1 in chars:
for c2 in chars:
for c3 in chars:
for c4 in chars:
key = c1 + c2 + c3 + c4
if hashlib.sha1(key.encode()).hexdigest() == target:
print(f"FOUND: {key}") # 输出 mdzz结果:Key = mdzz
三、第二阶段:ClassLoader 动态解密
1、ClassLoader 机制分析
a14b64a0683594003b4efe8a2285acd8.java继承ClassLoader,核心方法:
protected Class<?> findClass(String name) {
String className = name.substring(name.lastIndexOf(".") + 1);
// 文件名 = MD5(类名) + ".class"
String fileName = "/" + name.replace(".", "/").substring(...)
+ md5(className) + ".class";
InputStream in = getClass().getResourceAsStream(fileName);
// 解密:AES/CBC/PKCS5Padding
byte[] key = md5(this.code.getBytes()); // 密钥 = MD5("mdzz")
IvParameterSpec iv = new IvParameterSpec("****************".getBytes());
AES.init(2, new SecretKeySpec(key, "AES"), iv);
byte[] decrypted = AES.doFinal(raw); // 解密 class 字节
return defineClass(name, decrypted, ...);
}2、解密关键类
import hashlib
from Crypto.Cipher import AES
key = hashlib.md5(b'mdzz').digest() # 密钥
iv = b'****************' # IV
for encrypted_file in ['64c6da24...', 'c42681a8...', 'f0cba5c1...', '8164f8f4...']:
with open(f'resources/com/company/{encrypted_file}', 'rb') as f:
encrypted = f.read()
cipher = AES.new(key, AES.MODE_CBC, iv)
decrypted = cipher.decrypt(encrypted)
# 去除 PKCS5 填充
pad_len = decrypted[-1]
if 1 <= pad_len <= 16:
decrypted = decrypted[:-pad_len]
# 验证魔法数
assert decrypted[:4] == b'\xca\xfe\xba\xbe' 文件定位:`MD5(类名) + ".class"`,如 Stage → `64c6da2436465d11573858d46056b95d.class`
四、第三阶段:逆向变换链
1、调用链分析
Stage.Start()
→ 读 flag 输入
→ 调用 Stage2.check(flag)
Stage2.check(flag)
→ 遍历 flag[i], i%3==0 时 flag[i] ^= 6
→ 调用 Stage5.check(flag)
Stage5.check(flag)
→ 遍历 flag[i], (i+2)%3==0 时 flag[i] ^= 51
→ 调用 Stage7.check(flag)
Stage7.check(flag)
→ 返回 flag 不变2、目标值分析
Stage.java 中的 checkflag:
byte[] checkflag = {100, 106, 55, 53, 80, 48, 66, 0, 95, 81, 2, 55, 110, 108, 67, 54, 119, 51};3、逆向变换
XOR 运算的逆运算仍是 XOR,直接逆序应用:
flag = bytearray(checkflag)
# 逆 Stage5:(i+2)%3==0 的索引 ^51
# 索引:1, 4, 7, 10, 13, 16
for i in range(17):
if (i + 2) % 3 == 0:
flag[i] ^= 51
# 逆 Stage2:i%3==0 的索引 ^6
# 索引:0, 3, 6, 9, 12, 15
for i in range(17):
if i % 3 == 0:
flag[i] ^= 64、逐步还原过程得出flag{bY73c0D3_W17h_C0D3}。
解题工具链:`unzip` → `jadx` → `Python hashlib/Crypto` → 逆向推导
注:此题可直接利用AI求解:
如果直接用GLM5.2大模型解此题现在不是难度,但难度是你无法在便携设备上得到这样的算力,所以我选用了Qwen3.6的35B,利用云侠AI配合直接完成此题目。
