0%

【GHCTF2025】re-腐蚀

2025-03-15 16:45By
a3520249934
REVERSERC4流密码动态调试自定义逻辑XORCPython语言逆向逆向技术算法分析Rust

Problem: [GHCTF 2025]腐蚀

@TOC

main函数

NSSIMAGE
ida打开,是rust,进入真正的main函数main_0。
看到明显读入了一个Input.png,但是不知道是在哪里读入的。

动调

随便放个Input.png直接开始动调,每个函数前后都停一下,直到找到读入的图片信息
NSSIMAGE
图片存储地址在rax中,点进去下个硬件断点。
NSSIMAGE
然后开始跑,第一个出发断点的位置:
NSSIMAGE

加密

RC4

看伪代码,发现是RC4,但是最后异或了0x1F,我处理过的代码如下:

v45 = -2i64; memset(sbox, 0, sizeof(sbox)); v32[0] = sub_7FF7DDAF3D10(0i64, 256i64); v32[1] = v3; while ( 1 ) { v33 = sub_7FF7DDAF22C0(v32); v34 = v4; if ( !v33 ) break; if ( v34 >= 0x100 ) sub_7FF7DDB0FDE4(v34, 256i64, &off_7FF7DDB12240); *((_BYTE *)sbox + v34) = v34; // sbox生成0-255字节流 } j = 0i64; v36[0] = sub_7FF7DDAF3D10(0i64, 256i64); v36[1] = v5; while ( 1 ) { v37 = sub_7FF7DDAF22C0(v36); i_ = v6; if ( !v37 ) break; i__ = i_; if ( i_ >= 0x100 ) sub_7FF7DDB0FDE4(i_, 256i64, &off_7FF7DDB121B0); sbox_i = *((unsigned __int8 *)sbox + i_); // sbox_i = *((unsigned __int8 *)sbox + i_); t_j = sbox_i + j; if ( __CFADD__(sbox_i, j) ) sub_7FF7DDB100D0(&off_7FF7DDB121C8); key_len = _except_get_jumpbuf_sp(key); if ( !key_len ) sub_7FF7DDB10190(&off_7FF7DDB121E0); key_i = *(unsigned __int8 *)sub_7FF7DDAF5210(key, i__ % key_len, &off_7FF7DDB121F8);// key_i = key[i % key_len] next_j = key_i + t_j; // next_j = key_i + t_j; if ( __CFADD__(key_i, t_j) ) sub_7FF7DDB100D0(&off_7FF7DDB12210); j = next_j; swap((unsigned int)sbox, 256, i__, next_j, (__int64)&off_7FF7DDB12228); } jumpbuf_sp = _except_get_jumpbuf_sp(a3); sub_7FF7DDAF4DA0((__int64 *)&v39, jumpbuf_sp, (__int64)&off_7FF7DDB120D8); i = 0i64; j__ = 0i64; v7 = sub_7FF7DDAF50B0(a3); v9 = sub_7FF7DDAF4AC0(v7, v8); v43[0] = sub_7FF7DDAF5090(v9, v10); v43[1] = v11; while ( 1 ) { png_address = (char *)sub_7FF7DDAF5270(v43); if ( !png_address ) break; png_byte = *png_address; // png_byte = *png_address; i_plus_1 = i + 1; if ( i == -1i64 ) sub_7FF7DDB100D0(&off_7FF7DDB120F0); i = i_plus_1; // i = i + 1 sbox_i_1 = *((unsigned __int8 *)sbox + i_plus_1);// sbox_i_1 = *((unsigned __int8 *)sbox + i_plus_1); new_j = sbox_i_1 + j__; // new_j = sbox_i_1 + j__; if ( __CFADD__(sbox_i_1, j__) ) sub_7FF7DDB100D0(&off_7FF7DDB12120); j__ = new_j; swap((unsigned int)sbox, 256, i, new_j, (__int64)&off_7FF7DDB12138); if ( i >= 0x100 ) sub_7FF7DDB0FDE4(i, 256i64, &off_7FF7DDB12150); sbox_i_n = *((unsigned __int8 *)sbox + i); // sbox_i_n = *((unsigned __int8 *)sbox + i); if ( j__ >= 0x100 ) sub_7FF7DDB0FDE4(j__, 256i64, &off_7FF7DDB12168); sbox_j_n = *((unsigned __int8 *)sbox + j__);// sbox_j_n = *((unsigned __int8 *)sbox + j__); if ( __CFADD__(sbox_j_n, sbox_i_n) ) sub_7FF7DDB100D0(&off_7FF7DDB12180); LOBYTE(v14) = *((_BYTE *)sbox + (unsigned __int8)(sbox_j_n + sbox_i_n)) ^ png_byte ^ 0x1F;// LOBYTE(v14) = *((_BYTE *)sbox + (unsigned __int8)(v15 + v21)) ^ png_byte ^ 0x1F; sub_7FF7DDAF4F40(&v39, v14, &off_7FF7DDB12198); } *(_QWORD *)(a1 + 16) = v40; *(_OWORD *)a1 = v39; sub_7FF7DDAF2160(a3); sub_7FF7DDAF2160(key); return a1;

理论上把所有异或字节dump出来即可,但是图片太大了,我们就把key找出来
NSSIMAGE

断点段在这,点进去key,地址在8字节处
NSSIMAGE
跳转过去,dump下来:

6082AE424E4449451A0A0D0A4E478950

NSSIMAGE
可以猜到RC4加密结果存储在v39中,断在如图所示处,进入rax,找到地址,打下断点,与刚刚操作类似。

换序

继续跑,断点被触发,查看逻辑
NSSIMAGE
交换了ia5-1-i的字节,疑似换序,发现a5还刚好是图片字节数的一半,稳辣

脚本

def reverse_file_bytes(input_filename, output_filename): # 读取输入文件的二进制内容 with open(input_filename, 'rb') as file: file_data = file.read() # 将字节数据倒序 reversed_data = bytearray(reversed(file_data)) # 将倒序后的数据写入到输出文件 with open(output_filename, 'wb') as file: file.write(reversed_data) input_filename = "C:\\Users\\35202\\Downloads\\fs\\fs\\enc" # 输入文件路径 output_filename = 'C:\\Users\\35202\\Downloads\\fs\\fs\\out' # 输出文件路径 reverse_file_bytes(input_filename, output_filename) def rc4_decrypt(ciphertext, key): S = list(range(256)) j = 0 out = [] # KSA - Key Scheduling Algorithm for i in range(256): j = (j + S[i] + (key[i % len(key)])) % 256 S[i], S[j] = S[j], S[i] i = j = 0 for char in ciphertext: i = (i + 1) % 256 j = (j + S[i]) % 256 S[i], S[j] = S[j], S[i] out.append(chr(ord(char) ^ S[(S[i] + S[j]) % 256] ^ 0x1f)) return ''.join(out) def decrypt_file(input_filename, output_filename, key): # 读取输入文件的二进制内容 with open(input_filename, 'rb') as file: file_data = file.read() # 将字节数据转换为可处理的格式并解密 decrypted_data = rc4_decrypt(file_data.decode('latin1'), key).encode('latin1') # 将解密后的数据写入到输出文件 with open(output_filename, 'wb') as file: file.write(decrypted_data) input_filename = 'C:\\Users\\35202\\Downloads\\fs\\fs\\out' # 加密文件路径 output_filename = 'C:\\Users\\35202\\Downloads\\fs\\fs\\flag.png' # 解密后文件保存路径 key = bytes.fromhex("6082AE424E4449451A0A0D0A4E478950") # RC4解密所需的密钥 decrypt_file(input_filename, output_filename, key)

美了美了
NSSIMAGE

flag:NSSCTF{Y0u_ar3_ru5t_m@st3r}

还没有人赞赏,快来当第一个赞赏的人吧!
  
© 著作权归作者所有
加载失败
广告
×
评论区
添加新评论