霍雅
2024网鼎杯青龙组RE2 reverse wp(Write-up)
打开是four无后缀文件,13KB
用查壳工具打开,发现是64位ELF文件GCC编译无壳
打开IDA64位shift+F12打开字符串窗口,发现几个特殊字符和一个wdflag{以及一个correct FLAG!
可以看到main函数,里面包含一个wdflag{和correct Flag!,可以看出来这是程序入口,同时还有个base64_table的字符串,后面会用到。
双击进主函数F2看伪代码,可以看到四种加密方式第一种是数组乘积算法,第二种是亦或,第三种是base64,第四种是AES,对应提示的四大护法。
第一种加密,实际上就是一个乘2算法,所以将下列数组除2可得前八位为0170b39c,加上我们一开始就看到的wdflag{可得flag的前几位为wdflag{0170b39c
memcpy(dest, v51, 0x20uLL);
v49 = 0;
s2 = 96;
v38 = 98;
v39 = 110;
v40 = 96;
v41 = -60;
v42 = 102;
v43 = 114;
v44 = -58;
for ( i = 0; i <= 7; ++i )
s1[i] = 2 * dest[i];
96 => 0x60 | 0x60 / 2 = 0x30 = 48 (ASCII '0')
98 => 0x62 | 0x62 / 2 = 0x31 = 49 (ASCII '1')
110 => 0x6E | 0x6E / 2 = 0x37 = 55 (ASCII '7')
96 => 0x60 | 0x60 / 2 = 0x30 = 48 (ASCII '0')
-60 => 0xC4 | 0xC4 / 2 = 0x62 = 98 (ASCII 'b')
102 => 0x66 | 0x66 / 2 = 0x33 = 51 (ASCII '3')
114 => 0x72 | 0x72 / 2 = 0x39 = 57 (ASCII '9')
-58 => 0xC6 | 0xC6 / 2 = 0x63 = 99 (ASCII 'c')
第二部分如下代码,是一个异或算法
XorrLord的ascii值为:
X = 88, o = 111, r = 114, r = 114, L = 76, o = 111, r = 114, d = 100
和变量v28-v35亦或可得5ed24c63,结合上面的结果可得flag前几位为wdflag{0170b39c5ed24c63
if ( !memcmp(s1, &s2, 8uLL) )
{
v54 = (__int64)"XorrLord";
v28 = 109;
v29 = 10;
v30 = 22;
v31 = 64;
v32 = 120;
v33 = 12;
v34 = 68;
v35 = 87;
109 ^ 88 = 53 => '5'
10 ^ 111 = 101 => 'e'
22 ^ 114 = 100 => 'd'
64 ^ 114 = 50 => '2'
120 ^ 76 = 52 => '4'
12 ^ 111 = 99 => 'c'
68 ^ 114 = 54 => '6'
87 ^ 100 = 51 => '3'
第三个算法是一个base64的魔改表,魔改表也就是我们一开始寻找到的特殊字符,符合base64表的特征,同时名字也有base64,进去查看base64_encode这个函数,内容也和推断一样
但是这个魔改表有个坑,他是63位,所以我们要补一个C,完整表如下DEFGHIJKLMNOPQRSTUVWXYZABabcdefghijklmnopqrstuvwxyz0123456789+/
(其实他就在base64_table后面有个43H,这个就是C,我没注意到)
base64_encode((__int64)&v17, 8uLL, (__int64)v10);
v21 = "BYOzAjWyAVA";
if ( strcmp(v10, "BYOzAjWyAVA") )
return 1;
查看这个函数在main函数里的调用,加密的密文可以看出来就是BYOzAjWyAVA通过编写脚本可得
结果为ec3b52a6,加上我们前面解出来的flag可得flag前几位为:wdflag{0170b39c5ed24c63ec3b52a6
import base64
# 修正版的魔改 Base64 表(补全了缺失的 C)
mod_base64_table = 'CDEFGHIJKLMNOPQRSTUVWXYZABabcdefghijklmnopqrstuvwxyz0123456789+/'
# 标准的 Base64 表
std_base64_table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
# 1. 确保长度一致
if len(mod_base64_table) != 64 or len(std_base64_table) != 64:
raise ValueError(f"Base64 表的长度不一致:魔改表({len(mod_base64_table)}),标准表({len(std_base64_table)})")
# 2. 生成转换映射
decode_map = str.maketrans(mod_base64_table, std_base64_table)
def decode_mod_base64(mod_encoded):
"""将魔改 Base64 转为标准 Base64 并解码"""
# 1. 将魔改的 Base64 字符串转成标准 Base64
std_encoded = mod_encoded.translate(decode_map)
print(f"魔改的 Base64: {mod_encoded} => 标准 Base64: {std_encoded}")
# 2. 补充填充符 '=',确保字符串长度为 4 的倍数
padding_needed = len(std_encoded) % 4
if padding_needed:
std_encoded += '=' * (4 - padding_needed)
# 3. 解码标准 Base64
decoded_bytes = base64.b64decode(std_encoded)
return decoded_bytes.decode('utf-8', errors='ignore') # 忽略解码错误
mod_base64_string = 'BYOzAjWyAVA'
decoded_text = decode_mod_base64(mod_base64_string)
print(f"解码结果: {decoded_text}")
最后一种加密是AES加密,密文为V4数组,秘钥为AesMasterAesMast,详细代码分析让ai来,这里就不继续分析了,有经验的师父应该一眼能看出来
qmemcpy(v9, "AesMasterAesMast", sizeof(v9));
v8[0] = 0LL;
v8[1] = 0LL;
memcpy(v8, v18, 8uLL);
for ( k = 8; k <= 15; ++k )
*((_BYTE *)v8 + k) = 8;
AES_set_encrypt_key(v9, 128LL, v6);
AES_encrypt(v8, v7, v6);
hex_to_string(v7, 16LL, v5);
v4[0] = -10;
v4[1] = -85;
v4[2] = 71;
v4[3] = -66;
v4[4] = 113;
v4[5] = -28;
v4[6] = 1;
v4[7] = -36;
v4[8] = 3;
v4[9] = 48;
v4[10] = -97;
v4[11] = -15;
v4[12] = 67;
v4[13] = -15;
v4[14] = -45;
v4[15] = 102;
if ( memcmp(v7, v4, 0x10uLL) )
return 1;
puts("Correct Flag!");
return 0;
}
先将数组的内容转换成16进制,然后exp如下,结果为724ba7d5
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
# 提供的数据 v4
v4 = bytes([0xF6, 0xAB, 0x47, 0xBE, 0x71, 0xE4, 0x01, 0xDC, 0x03, 0x30, 0x9F, 0xF1, 0x43, 0xF1, 0xD3, 0x66])
# 使用"AesMasterAesMast"作为密钥,编码为字节
key = "AesMasterAesMast".encode()
# 初始化AES解密器,选择ECB模式
cipher = AES.new(key, AES.MODE_ECB)
# 解密数据
decrypted_data = cipher.decrypt(v4)
# 去除填充
try:
unpadded_data = unpad(decrypted_data, AES.block_size)
# 输出解密后的数据,假设是ASCII字符串
print("Decrypted data:", unpadded_data.decode('utf-8', errors='ignore'))
except ValueError as e:
print(f"Padding error or decryption issue: {e}")
最后结果wdflag{0170b39c5ed24c63ec3b52a6724ba7d5}
完整伪代码如下:
int __cdecl main(int argc, const char **argv, const char **envp)
{
int result; // eax@6
char v4; // [sp+0h] [bp-240h]@22
char v5; // [sp+1h] [bp-23Fh]@22
char v6; // [sp+2h] [bp-23Eh]@22
char v7; // [sp+3h] [bp-23Dh]@22
char v8; // [sp+4h] [bp-23Ch]@22
char v9; // [sp+5h] [bp-23Bh]@22
char v10; // [sp+6h] [bp-23Ah]@22
char v11; // [sp+7h] [bp-239h]@22
char v12; // [sp+8h] [bp-238h]@22
char v13; // [sp+9h] [bp-237h]@22
char v14; // [sp+Ah] [bp-236h]@22
char v15; // [sp+Bh] [bp-235h]@22
char v16; // [sp+Ch] [bp-234h]@22
char v17; // [sp+Dh] [bp-233h]@22
char v18; // [sp+Eh] [bp-232h]@22
char v19; // [sp+Fh] [bp-231h]@22
char v20; // [sp+10h] [bp-230h]@22
char v21; // [sp+40h] [bp-200h]@22
char v22; // [sp+140h] [bp-100h]@22
__int64 v23; // [sp+150h] [bp-F0h]@19
__int64 v24; // [sp+158h] [bp-E8h]@19
__int64 v25; // [sp+160h] [bp-E0h]@19
__int64 v26; // [sp+168h] [bp-D8h]@19
char v27; // [sp+170h] [bp-D0h]@17
char v28; // [sp+180h] [bp-C0h]@12
char v29; // [sp+181h] [bp-BFh]@12
char v30; // [sp+182h] [bp-BEh]@12
char v31; // [sp+183h] [bp-BDh]@12
char v32; // [sp+184h] [bp-BCh]@12
char v33; // [sp+185h] [bp-BBh]@12
char v34; // [sp+186h] [bp-BAh]@12
char v35; // [sp+187h] [bp-B9h]@12
char v36[16]; // [sp+190h] [bp-B0h]@13
char s2; // [sp+1A0h] [bp-A0h]@7
char v38; // [sp+1A1h] [bp-9Fh]@7
char v39; // [sp+1A2h] [bp-9Eh]@7
char v40; // [sp+1A3h] [bp-9Dh]@7
char v41; // [sp+1A4h] [bp-9Ch]@7
char v42; // [sp+1A5h] [bp-9Bh]@7
char v43; // [sp+1A6h] [bp-9Ah]@7
char v44; // [sp+1A7h] [bp-99h]@7
char s1[16]; // [sp+1B0h] [bp-90h]@8
char dest[32]; // [sp+1C0h] [bp-80h]@7
char v47[32]; // [sp+1D0h] [bp-70h]@17
char v48[32]; // [sp+1D8h] [bp-68h]@19
char v49; // [sp+1E0h] [bp-60h]@7
char s[39]; // [sp+1F0h] [bp-50h]@1
char v51[39]; // [sp+1F7h] [bp-49h]@7
char v52; // [sp+217h] [bp-29h]@5
char *v53; // [sp+220h] [bp-20h]@17
__int64 v54; // [sp+228h] [bp-18h]@12
int k; // [sp+234h] [bp-Ch]@19
int j; // [sp+238h] [bp-8h]@12
int i; // [sp+23Ch] [bp-4h]@7
printf("Enter the flag:", argv, envp);
if ( fgets(s, 41, stdin) )
s[strcspn(s, "\n")] = 0;
if ( strlen(s) == 40 && !strncmp(s, "wdflag{", 7uLL) && v52 == 125 )
{
memcpy(dest, v51, 0x20uLL);
v49 = 0;
s2 = 96;
v38 = 98;
v39 = 110;
v40 = 96;
v41 = -60;
v42 = 102;
v43 = 114;
v44 = -58;
for ( i = 0; i <= 7; ++i )
s1[i] = 2 * dest[i];
if ( !memcmp(s1, &s2, 8uLL) )
{
v54 = (__int64)"XorrLord";
v28 = 109;
v29 = 10;
v30 = 22;
v31 = 64;
v32 = 120;
v33 = 12;
v34 = 68;
v35 = 87;
for ( j = 8; j <= 15; ++j )
v36[j - 8] = dest[j] ^ *(_BYTE *)(j - 8LL + v54);
if ( !memcmp(v36, &v28, 8uLL) )
{
base64_encode(v47, 8LL, &v27);
v53 = "BYOzAjWyAVA";
if ( !strcmp(&v27, "BYOzAjWyAVA") )
{
v25 = 7310594956877587777LL;
v26 = 8391157515997757810LL;
v23 = 0LL;
v24 = 0LL;
memcpy(&v23, v48, 8uLL);
for ( k = 8; k <= 15; ++k )
*((_BYTE *)&v23 + k) = 8;
AES_set_encrypt_key(&v25, 128LL, &v21);
AES_encrypt(&v23, &v22, &v21);
hex_to_string(&v22, 16LL, &v20);
v4 = -10;
v5 = -85;
v6 = 71;
v7 = -66;
v8 = 113;
v9 = -28;
v10 = 1;
v11 = -36;
v12 = 3;
v13 = 48;
v14 = -97;
v15 = -15;
v16 = 67;
v17 = -15;
v18 = -45;
v19 = 102;
if ( !memcmp(&v22, &v4, 0x10uLL) )
{
puts("Correct Flag!");
result = 0;
}
else
{
result = 1;
}
}
else
{
result = 1;
}
}
else
{
result = 1;
}
}
else
{
result = 1;
}
}
else
{
result = 1;
}
return result;
}
base64伪代码如下
_BYTE *__fastcall base64_encode(__int64 a1, unsigned __int64 a2, __int64 a3)
{
int v3; // eax
int v4; // eax
int v5; // eax
int v6; // eax
int v7; // eax
int v8; // eax
_BYTE *result; // rax
unsigned __int64 v10; // [rsp+8h] [rbp-30h]
unsigned int v11; // [rsp+20h] [rbp-18h]
int v12; // [rsp+28h] [rbp-10h]
int v13; // [rsp+2Ch] [rbp-Ch]
int v14; // [rsp+30h] [rbp-8h]
int v15; // [rsp+34h] [rbp-4h]
v10 = a2;
v15 = 0;
v14 = 0;
while ( v15 < a2 )
{
v3 = v15++;
v13 = *(unsigned __int8 *)(v3 + a1);
if ( v15 >= a2 )
{
v5 = 0;
}
else
{
v4 = v15++;
v5 = *(unsigned __int8 *)(v4 + a1);
}
v12 = v5;
if ( v15 >= a2 )
{
v7 = 0;
}
else
{
v6 = v15++;
v7 = *(unsigned __int8 *)(v6 + a1);
}
v11 = (v12 << 8) + (v13 << 16) + v7;
*(_BYTE *)(a3 + v14) = base64_table[(v11 >> 18) & 0x3F];
*(_BYTE *)(a3 + v14 + 1) = base64_table[(v11 >> 12) & 0x3F];
*(_BYTE *)(a3 + v14 + 2) = base64_table[(v11 >> 6) & 0x3F];
v8 = v14 + 3;
v14 += 4;
*(_BYTE *)(a3 + v8) = base64_table[v11 & 0x3F];
}
while ( v10 % 3 )
{
*(_BYTE *)(--v14 + a3) = 61;
++v10;
}
result = (_BYTE *)(v14 + a3);
*result = 0;
return result;
}