返回
48
0

CTF Binary-[Re挑战题]-JvavMaster[Score=5]

Aristore,2025-07-07 21:23

参考文章:GUI—— 从的可执行exe文件中提取jar包并反编译成Java - 知乎

下载JD-GUI

Win+R输入%temp%,按时间降序,运行程序后刷新打开刚刚冒出来的文件夹

把文件夹里的jvav.jar拖到jd-gui进行反编译

exp如下:

Python
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()}")

运行结果:

Plaintext
生成的 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!!}
暂无回复。你的想法是什么?


bottom-logo1
bottom-logo2captionbottom-logo3
GeeSec
商务合作
bottom-logo4