参考文章:GUI—— 从的可执行exe文件中提取jar包并反编译成Java - 知乎
下载JD-GUI
Win+R输入%temp%,按时间降序,运行程序后刷新打开刚刚冒出来的文件夹
把文件夹里的jvav.jar拖到jd-gui进行反编译
exp如下:
import numpy as np
# 1. 复现 Java 中的 random 函数
def random(seed):
x = seed
x ^= (x << 11) & 0xFFFFFFFF
x ^= (x >> 4) & 0xFFFFFFFF
x ^= (x << 5) & 0xFFFFFFFF
x ^= (x >> 14) & 0xFFFFFFFF
return x & 0xFF
# 2. 生成 MATRIX
MATRIX = np.zeros((11, 11), dtype=int)
for i in range(11):
for j in range(11):
MATRIX[i, j] = random(i * 11 + j)
# 3. 定义 TARGET 向量
TARGET = np.array([
140286, 171210, 157332, 135722, 144003, 174006, 144135,
152772, 144501, 155988, 156148
])
# 4. 求解线性方程组
# key_float = np.linalg.inv(MATRIX).dot(TARGET) # 另一种方法
key_float = np.linalg.solve(MATRIX, TARGET)
# 5. 将解四舍五入为整数,并转换为字节
key_bytes = [int(round(x)) for x in key_float]
key_str = "".join(chr(b) for b in key_bytes)
print(f"生成的 MATRIX:\n{MATRIX}")
print(f"\n求解出的 Key (bytes): {key_bytes}")
print(f"求解出的 Key (string): {key_str}")
# 辅助函数,复现 Java 的 rol 和 ror
def rol(b, shift):
shift &= 7
return ((b << shift) | (b >> (8 - shift))) & 0xFF
def ror(b, shift):
shift &= 7
return ((b >> shift) | (b << (8 - shift))) & 0xFF
# 1. 提取所有指令
instructions = []
i = 0
# Java的switch没有default,所以我们需要一个映射
# opcode_map[random(i)] -> [op, idx, param]
# 这里我们直接模拟Java的 getInstruction
def getInstruction(index):
# 此处省略了Java中庞大的switch-case,直接用一个字典代替
# key是index, value是[op, idx, param]
inst_map = {0:[3,24,-43], 1:[-52,41,29], 3:[5,9,4], 12:[2,15,2], 13:[-52,25,-119], 14:[-52,30,18], 21:[4,7,3], 22:[2,23,-49], 23:[-52,46,79], 24:[-52,26,-113], 26:[1,11,-31], 27:[-52,33,121], 37:[-52,34,-35], 38:[-52,28,77], 39:[1,47,-64], 40:[2,4,30], 42:[-52,6,-126], 43:[2,1,-39], 48:[-52,2,-45], 49:[4,35,4], 50:[-1,0,0], 51:[-52,19,59], 60:[-52,29,-105], 61:[4,36,6], 62:[5,13,1], 68:[-52,5,73], 70:[5,22,1], 71:[-52,44,108], 73:[1,21,-106], 74:[1,27,51], 75:[-52,3,76], 80:[1,12,40], 81:[-52,39,35], 82:[-52,38,-78], 92:[4,14,5], 93:[-52,43,-43], 95:[2,20,111], 96:[-52,40,61], 97:[5,18,2], 98:[5,10,2], 108:[-52,16,-77], 109:[3,31,-1], 111:[-52,37,44], 116:[2,17,-23], 118:[-52,45,4], 119:[1,8,84], 121:[-52,0,114], 122:[-52,42,-21], 123:[2,32,11], 128:[4,34,6], 130:[-52,47,4], 131:[1,28,125], 141:[-52,4,46], 142:[-52,1,-44], 143:[1,6,-84], 148:[-52,35,94], 149:[3,2,-93], 150:[4,19,4], 152:[-52,36,27], 153:[1,29,116], 155:[-52,13,-37], 164:[4,41,7], 165:[-52,24,119], 166:[-52,9,-98], 168:[3,25,-37], 169:[-52,15,12], 171:[1,30,14], 176:[-52,7,6], 178:[3,46,41], 179:[-52,23,-72], 189:[2,26,61], 190:[3,33,-37], 191:[-52,11,-113], 196:[-52,18,24], 197:[5,40,4], 199:[-52,10,-95], 200:[-52,31,-57], 201:[1,16,-7], 202:[1,37,-1], 209:[-52,17,-46], 210:[-52,8,-94], 211:[5,45,3], 220:[4,0,4], 222:[-52,32,-56], 223:[5,42,3], 225:[3,5,11], 226:[4,44,1], 227:[-52,22,32], 236:[-52,21,72], 238:[5,3,4], 239:[-52,27,-9], 244:[3,39,120], 245:[-52,12,-119], 247:[5,38,2], 248:[2,43,83], 249:[-52,14,-25], 250:[-52,20,105]}
return inst_map.get(index)
while True:
rand_val = random(i)
opcode = getInstruction(rand_val)
if opcode is None: # Java的switch会跳过没有case的值
i += 1
continue
if opcode[0] == -1: # 终止指令
break
# Java的byte是-128到127, Python中用 & 0xFF 模拟无符号字节
instructions.append([(opcode[0] & 0xFF), (opcode[1] & 0xFF), (opcode[2] & 0xFF)])
i += 1
# 2. 从检查指令确定最终数据状态
final_data = [0] * 48
modification_instructions = []
for op, idx, param in instructions:
if op == 204: # 检查指令
final_data[idx] = param
else:
modification_instructions.append((op, idx, param))
# 3. 逆向执行修改指令
# 从后往前遍历指令列表
for op, idx, param in reversed(modification_instructions):
if op == 1: # ADD -> SUB
final_data[idx] = (final_data[idx] - param) & 0xFF
elif op == 2: # SUB -> ADD
final_data[idx] = (final_data[idx] + param) & 0xFF
elif op == 3: # XOR -> XOR
final_data[idx] = final_data[idx] ^ param
elif op == 4: # ROL -> ROR
final_data[idx] = ror(final_data[idx], param)
elif op == 5: # ROR -> ROL
final_data[idx] = rol(final_data[idx], param)
encrypted_data = bytes(final_data)
print(f"\n求解出的加密后数据 (encrypted_data):\n{encrypted_data.hex()}")
def decrypt(ciphertext, key_bytes):
# KSA (魔改版)
box = list(range(256))
for i in range(256):
box[i] = (255 - i) ^ 0x83
x = 0
key_len = len(key_bytes)
for j in range(256):
x = (x + box[j] + key_bytes[(j + 72) % key_len]) % 256
box[j], box[x] = box[x], box[j]
# PRGA (魔改版) & Decryption
x = 0
y = 0
plaintext = bytearray(len(ciphertext))
for k in range(len(ciphertext)):
x = (x + 3) % 256
y = (y - box[x]) & 0xFF
box[x], box[y] = box[y], box[x]
index = (box[x] ^ box[y]) % 256
keystream_byte = box[index]
# 解密操作: P = (E ^ 0x77) - K
encrypted_byte = ciphertext[k]
temp = (encrypted_byte ^ 0x77) & 0xFF
decrypted_byte = (temp - keystream_byte) & 0xFF
plaintext[k] = decrypted_byte
return plaintext
# 传入第一步的key和第二步的encrypted_data
flag = decrypt(encrypted_data, [ord(c) for c in key_str])
print(f"\n最终解密得到的 Flag: {flag.decode()}")运行结果:
生成的 MATRIX:
[[ 0 165 74 239 149 48 223 122 43 142 97]
[196 190 27 244 81 119 210 61 152 226 71]
[168 13 92 249 22 179 201 108 131 38 238]
[ 75 164 1 123 222 49 148 197 96 143 42]
[ 80 245 26 191 153 60 211 118 12 169 70]
[227 178 23 248 93 39 130 109 200 220 121]
[150 51 73 236 3 166 247 82 189 24 98]
[199 40 141 171 14 225 68 62 155 116 209]
[128 37 202 111 21 176 95 250 50 151 120]
[221 167 2 237 72 25 188 83 246 140 41]
[198 99 69 224 15 170 208 117 154 63 110]]
求解出的 Key (bytes): [106, 118, 97, 118, 95, 109, 97, 115, 116, 101, 114]
求解出的 Key (string): jvav_master
求解出的加密后数据 (encrypted_data):
27ad70c44c42d6c04ee986ae61b73f0ebabb60b3d8b24087a252ccc4d0230438d3a277e56c2dca5bd33a5f2836206644
最终解密得到的 Flag: flag{W0w_y0u_4r3_4_r34L_jv4V_4nD_3X34j_m4573r!!}