# hitcon2023 逆向 The Blade WP

运行所给的程序 socket 通信相关


由题目描述 A Rust tool for executing shellcode in a seccomp environment.
字符串查找定位 发现其中 verify 方法可疑

发现隐藏了一个命令 flag 是以添加命令行参数的方式输入 flag 调试得知输入 flag 长度为 64 位

F7 进入 verify 发现加密逻辑 简单来讲 是一个大的 256 次 while 循环 里面有好几个通过固定的表对输入进行打乱,然后一个有点复杂的加密逻辑,有取余有除有异或,于是就有个骚操作的想法,既然逆向加密算法比较复杂,就找出 00-ff 的映射就行了 因为是按位加密的伐然后前面的几次打乱顺序由于是固定的表所以可以看成一次打乱顺序 找出索引交换的顺序即可
do | |
  { | |
++v8;  | |
memcpy(dest, "/", 0x200uLL);  | |
v9 = 64LL;  | |
v10 = &dest[1];  | |
    do | |
    { | |
v11 = *(v10 - 1);  | |
if ( v11 >= 64  | |
|| (v12 = flagg[v9 - 1], flagg[v9 - 1] = flagg[v11], flagg[v11] = v12, v13 = *v10, (unsigned __int64)*v10 > 0x3F) )  | |
      { | |
LABEL_53: | |
core::panicking::panic_bounds_check::h7d0e683548e4cb10();  | |
      } | |
v14 = flagg[v9 - 2];  | |
flagg[v9 - 2] = flagg[v13];  | |
flagg[v13] = v14;  | |
v10 += 2;  | |
v9 -= 2LL;  | |
    } | |
while ( v9 );  | |
memcpy(dest, &unk_55C3745E9D20, 0x200uLL);  | |
v15 = 64LL;  | |
v16 = &dest[1];  | |
    do | |
    { | |
v17 = *(v16 - 1);  | |
if ( v17 > 63 )  | |
goto LABEL_53;  | |
v18 = flagg[v15 - 1];  | |
flagg[v15 - 1] = flagg[v17];  | |
flagg[v17] = v18;  | |
v19 = *v16;  | |
if ( (unsigned __int64)*v16 > 63 )  | |
goto LABEL_53;  | |
v20 = flagg[v15 - 2];  | |
flagg[v15 - 2] = flagg[v19];  | |
flagg[v19] = v20;  | |
v16 += 2;  | |
v15 -= 2LL;  | |
    } | |
while ( v15 );  | |
memcpy(dest, &unk_55C3745E9F20, 0x200uLL);  | |
v21 = 64LL;  | |
v22 = &dest[1];  | |
    do | |
    { | |
v23 = *(v22 - 1);  | |
if ( v23 > 0x3F )  | |
goto LABEL_53;  | |
v24 = flagg[v21 - 1];  | |
flagg[v21 - 1] = flagg[v23];  | |
flagg[v23] = v24;  | |
v25 = *v22;  | |
if ( (unsigned __int64)*v22 > 0x3F )  | |
goto LABEL_53;  | |
v26 = flagg[v21 - 2];  | |
flagg[v21 - 2] = flagg[v25];  | |
flagg[v25] = v26;  | |
v22 += 2;  | |
v21 -= 2LL;  | |
    } | |
while ( v21 );  | |
memcpy(dest, &unk_55C3745EA120, 0x200uLL);  | |
v27 = 64LL;  | |
v28 = &dest[1];  | |
    do | |
    { | |
v29 = *(v28 - 1);  | |
if ( v29 > 0x3F )  | |
goto LABEL_53;  | |
v30 = flagg[v27 - 1];  | |
flagg[v27 - 1] = flagg[v29];  | |
flagg[v29] = v30;  | |
v31 = *v28;  | |
if ( (unsigned __int64)*v28 > 0x3F )  | |
goto LABEL_53;  | |
v32 = flagg[v27 - 2];  | |
flagg[v27 - 2] = flagg[v31];  | |
flagg[v31] = v32;  | |
v28 += 2;  | |
v27 -= 2LL;  | |
    } | |
while ( v27 );  | |
memcpy(dest, &unk_55C3745EA320, 0x200uLL);  | |
v33 = 64LL;  | |
v34 = &dest[1];  | |
    do | |
    { | |
v35 = *(v34 - 1);  | |
if ( v35 > 0x3F )  | |
goto LABEL_53;  | |
v36 = flagg[v33 - 1];  | |
flagg[v33 - 1] = flagg[v35];  | |
flagg[v35] = v36;  | |
v37 = *v34;  | |
if ( (unsigned __int64)*v34 > 0x3F )  | |
goto LABEL_53;  | |
v38 = flagg[v33 - 2];  | |
flagg[v33 - 2] = flagg[v37];  | |
flagg[v37] = v38;  | |
v34 += 2;  | |
v33 -= 2LL;  | |
    } | |
while ( v33 );  | |
memcpy(dest, &unk_55C3745EA520, 0x200uLL);  | |
v39 = 64LL;  | |
v40 = &dest[1];  | |
    do | |
    { | |
v41 = *(v40 - 1);  | |
if ( v41 > 0x3F )  | |
goto LABEL_53;  | |
v42 = flagg[v39 - 1];  | |
flagg[v39 - 1] = flagg[v41];  | |
flagg[v41] = v42;  | |
v43 = *v40;  | |
if ( (unsigned __int64)*v40 > 0x3F )  | |
goto LABEL_53;  | |
v44 = flagg[v39 - 2];  | |
flagg[v39 - 2] = flagg[v43];  | |
flagg[v43] = v44;  | |
v40 += 2;  | |
v39 -= 2LL;  | |
    } | |
while ( v39 );  | |
memcpy(dest, &unk_55C3745EA720, 0x200uLL);  | |
v45 = 64LL;  | |
v46 = &dest[1];  | |
    do | |
    { | |
v47 = *(v46 - 1);  | |
if ( v47 > 0x3F )  | |
goto LABEL_53;  | |
v48 = flagg[v45 - 1];  | |
flagg[v45 - 1] = flagg[v47];  | |
flagg[v47] = v48;  | |
v49 = *v46;  | |
if ( (unsigned __int64)*v46 > 0x3F )  | |
goto LABEL_53;  | |
v50 = flagg[v45 - 2];  | |
flagg[v45 - 2] = flagg[v49];  | |
flagg[v49] = v50;  | |
v46 += 2;  | |
v45 -= 2LL;  | |
    } | |
while ( v45 );  | |
memcpy(dest, &unk_55C3745EA920, 0x200uLL);  | |
v52 = 64LL;  | |
v53 = &dest[1];  | |
    do | |
    { | |
v54 = *(v53 - 1);  | |
if ( v54 > 0x3F )  | |
goto LABEL_53;  | |
v55 = flagg[v52 - 1];  | |
flagg[v52 - 1] = flagg[v54];  | |
flagg[v54] = v55;  | |
v56 = *v53;  | |
if ( (unsigned __int64)*v53 > 0x3F )  | |
goto LABEL_53;  | |
v57 = flagg[v52 - 2];  | |
flagg[v52 - 2] = flagg[v56];  | |
flagg[v56] = v57;  | |
v53 += 2;  | |
v52 -= 2LL;  | |
    } | |
while ( v52 );  | |
v58 = 0LL;  | |
    do | |
    { | |
v59 = (unsigned __int8)flagg[v58] + 1;  | |
LOWORD(v51) = 1;  | |
LOWORD(v52) = 257;  | |
v60 = 0;  | |
      do | |
      { | |
v62 = v52;  | |
LOWORD(v52) = (unsigned __int16)v52 / (unsigned __int16)v59;  | |
v61 = v62 % (unsigned __int16)v59;  | |
v63 = v51;  | |
v51 = v60 - v51 * v52;  | |
LODWORD(v52) = v59;  | |
v59 = (unsigned __int16)(v62 % (unsigned __int16)v59);  | |
v60 = v63;  | |
      } | |
while ( v61 );  | |
v64 = 0;  | |
if ( (__int16)v63 > 0 )  | |
v64 = v63;  | |
flagg[v58] = ((unsigned __int16)(v64 + ((__int16)v63 >> 15) - v63) / 0x101u  | |
                  + v63 | |
+ ((unsigned __int16)v63 >> 15)  | |
+ 113) ^ 0x89;  | |
v52 = v58 + 1;  | |
v58 = v52;  | |
    } | |
while ( v52 != 64 );  | |
  } | |
while ( v8 != 256 );// 提取出的总的加密  | 

不出意外的话 64 位比较数据是 cmp=[0xA7, 0x51, 0x68, 0x52, 0x85, 0x27, 0xFF, 0x31, 0x88, 0x87, 0xD2, 0xC7, 0xD3, 0x23, 0x3F, 0x52, 0x55, 0x10, 0x1F, 0xAF, 0x27, 0xF0, 0x94, 0x5C, 0xCD, 0x3F, 0x7A, 0x79, 0x9F, 0x2F, 0xF0, 0xE7, 0x45, 0xF0, 0x86, 0x3C, 0xF9, 0xB0, 0xEA, 0x6D, 0x90, 0x42, 0xF7, 0x91, 0xED, 0x3A, 0x9A, 0x7C, 0x01, 0x6B, 0x84, 0xDC, 0x6C, 0xC8, 0x43, 0x07, 0x5C, 0x08, 0xF7, 0xDF, 0xEB, 0xE3, 0xAE, 0xA4] (也就是这 64 位的 4 个 xmmword)
原顺序 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ {}
打乱后的顺序 HfVl {qPcCYNMoRi6D7Jr} espOL3FhwdWAtTGZba4Ugjvnx1QkKE2IS9yuz5BX08m
字符的加密逻辑:
do
    {
      v59 = (unsigned __int8)flagg[v58] + 1;
      LOWORD(v51) = 1;
      LOWORD(v52) = 257;
      v60 = 0;
      do
      {
        v62 = v52;
        LOWORD(v52) = (unsigned __int16)v52 / (unsigned __int16)v59;
        v61 = v62 % (unsigned __int16)v59;
        v63 = v51;
        v51 = v60 - v51 * v52;
        LODWORD(v52) = v59;
        v59 = (unsigned __int16)(v62 % (unsigned __int16)v59);
        v60 = v63;
      }
      while ( v61 );
      v64 = 0;
      if ( (__int16)v63 > 0 )
        v64 = v63;
      flagg[v58] = ((unsigned __int16)(v64 + ((__int16)v63 >> 15) - v63) / 0x101u
                  + v63
                  + ((unsigned __int16)v63 >> 15)
                  + 113) ^ 0x89;
      v52 = v58 + 1;
      v58 = v52;
    }
    while ( v52 != 64 );
一阶段脚本
def decrypt(data: list, table: dict):  | |
tmp=[]  | |
for i in data:  | |
tmp.append(table[i])  | |
    return tmp | |
def reverse_order(data:list, table: list):  | |
tmp = []  | |
for i in range(64):  | |
tmp.append(data[table[i]])  | |
    return tmp | |
#get crypto table | |
s0_255 = [0xFB, 0x7B, 0x4E, 0xBB, 0x51, 0x15, 0x8D, 0xDB, 0xB0, 0xAC, 0xA5, 0x8E, 0xAA, 0xB2, 0x60, 0xEB, 0x63, 0x5C, 0xDE, 0x42, 0x2B, 0xC6, 0xA6, 0x35, 0x30, 0x43, 0xD6, 0x5F, 0xBD, 0x24, 0xB1, 0xE3, 0x8C, 0xA7, 0xD5, 0x2A, 0x7C, 0x6D, 0x8B, 0x17, 0x9D, 0x83, 0xFE, 0x69, 0x10, 0x59, 0xA9, 0x9E, 0x0F, 0x1C, 0x66, 0x97, 0x5B, 0x61, 0xED, 0xAD, 0xE0, 0xDA, 0x27, 0x06, 0x25, 0xDC, 0x5E, 0xE7,  | |
0x41, 0x32, 0xD2, 0xD9, 0x8F, 0xEE, 0xAF, 0x03, 0x93, 0x3A, 0x00, 0xA2, 0xE1, 0xB3, 0xEC, 0x81, 0x9F, 0xCA, 0x58, 0xB7, 0x79, 0xFD, 0x3B, 0xA0, 0x02, 0x0C, 0xCB, 0xA8, 0x80, 0xC0, 0x16, 0x4D, 0x2F, 0x75, 0x71, 0x0A, 0x04, 0x39, 0xFF, 0xC1, 0x9C, 0xAB, 0xEF, 0xA4, 0xD8, 0xE2, 0x14, 0xC2, 0x6C, 0x64, 0x1E, 0x6B, 0x7E, 0x99, 0x2E, 0x09, 0x0B, 0x86, 0x74, 0x6A, 0xC4, 0x2D, 0x4F, 0xF9,  | |
0xFA, 0x94, 0xB6, 0x1F, 0x89, 0x6F, 0x5D, 0xE8, 0xEA, 0xB5, 0x5A, 0x65, 0x88, 0xC5, 0x7F, 0x77, 0x11, 0xCF, 0xF1, 0x1B, 0x3F, 0xF4, 0x48, 0x47, 0x12, 0xE4, 0xBA, 0xDF, 0xE9, 0x62, 0x6E, 0xB4, 0x96, 0xCD, 0x13, 0x53, 0x4B, 0x28, 0xD7, 0xD1, 0x33, 0xB8, 0xE6, 0x7A, 0x2C, 0x9B, 0x29, 0x44, 0x52, 0xF7, 0x20, 0xF2, 0x31, 0xD3, 0xB9, 0x40, 0xD0, 0x34, 0xF5, 0x54, 0x1A, 0x01, 0xA1, 0x92,  | |
0xFC, 0x85, 0x07, 0xBE, 0xDD, 0xBC, 0x19, 0xF3, 0x36, 0xF6, 0x72, 0x98, 0x4C, 0x7D, 0xC7, 0xD4, 0x45, 0x4A, 0x9A, 0xC3, 0x8A, 0xE5, 0x50, 0x46, 0xCC, 0x68, 0x76, 0x67, 0xC9, 0x0E, 0x3C, 0x57, 0xF0, 0x22, 0xBF, 0x26, 0x84, 0x0D, 0x90, 0xA3, 0xAE, 0x3D, 0x1D, 0xC8, 0x91, 0x05, 0x87, 0x70, 0x08, 0x73, 0x21, 0x49, 0x55, 0x3E, 0x37, 0x23, 0x18, 0x56, 0xCE, 0x82, 0x38, 0x95, 0x78, 0xF8]  | |
load_data = [0xA7, 0x51, 0x68, 0x52, 0x85, 0x27, 0xFF, 0x31, 0x88, 0x87, 0xD2, 0xC7, 0xD3, 0x23, 0x3F, 0x52, 0x55, 0x10, 0x1F, 0xAF, 0x27, 0xF0, 0x94, 0x5C, 0xCD, 0x3F, 0x7A, 0x79, 0x9F, 0x2F, 0xF0, 0xE7, 0x45, 0xF0, 0x86, 0x3C, 0xF9, 0xB0, 0xEA, 0x6D, 0x90, 0x42, 0xF7, 0x91, 0xED, 0x3A, 0x9A, 0x7C, 0x01, 0x6B, 0x84, 0xDC, 0x6C, 0xC8, 0x43, 0x07, 0x5C, 0x08, 0xF7, 0xDF, 0xEB, 0xE3, 0xAE, 0xA4]  | |
crypto_table = dict(zip(s0_255,range(0x100)))  | |
#get order table | |
source = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ{}'  | |
replaced = 'HfVl{qPcCYNMoRi6D7Jr}espOL3FhwdWAtTGZba4Ugjvnx1QkKE2IS9yuz5BX08m'  | |
revsere_table = [] #index 是 source 在 replace 中的下标  | |
for i in source:  | |
revsere_table.append(replaced.find(i))  | |
tmp = [0x52, 0xCB, 0x15, 0x10, 0x7E, 0xD3, 0x78, 0x26, 0xC2, 0x14, 0x09, 0x50, 0x55, 0xFA, 0xEE, 0xC3, 0x0A, 0x97, 0xB9, 0x38, 0x12, 0x3D, 0x0E, 0xE9, 0xBE, 0xF6, 0x2B, 0x66, 0x67, 0xA8, 0x87, 0xAE, 0x1D, 0x53, 0x62, 0xEC, 0xFC, 0x5C, 0x88, 0x68, 0x23, 0x5B, 0x36, 0x13, 0xFB, 0xD7, 0xCA, 0x7A, 0xBD, 0xD9, 0x69, 0x6A, 0xE4, 0x2A, 0x6C, 0x9D, 0x86, 0xE0, 0xA4, 0x01, 0xBA, 0x3B, 0x20, 0x92]  | |
for i in range(256):  | |
tmp = decrypt(tmp, crypto_table)  | |
tmp = reverse_order(tmp, revsere_table)  | |
print(''.join(chr(i) for i in tmp))  | |
# 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ{} | 
以上脚本用于还原 排序 + 加密,tmp 的值就是经历过完整的打乱顺序和加密后 dump 出的,并不是最终的 cmp_data
说明要么是比较数据还有操作 要么是 input 还有操作
继续往后面看 比较逻辑

like_i = 4LL;  | |
  do | |
  { | |
v77 = v84; // 0xff  | |
if ( v84 < 205 )  | |
goto LABEL_74;  | |
*(_DWORD *)v78 = *(_DWORD *)((char *)dest + like_i);  | |
v79 = v82;  | |
v82[204] = input[like_i];  | |
if ( v77 < 224 )  | |
goto LABEL_74;  | |
v79[223] = v78[0];  | |
v79[205] = input[like_i + 1];  | |
if ( v77 == 224 )  | |
goto LABEL_74;  | |
v79[224] = v78[1];  | |
v79[206] = input[like_i + 2];  | |
if ( v77 < 226 )  | |
goto LABEL_74;  | |
v79[225] = v78[2];  | |
v79[207] = input[like_i + 3];  | |
if ( v77 == 226 )  | |
goto LABEL_74;  | |
v79[226] = v78[3];  | |
_$LT$$RF$std..net..tcp..TcpStream$u20$as$u20$std..io..Write$GT$::write::h0bbfc2d1fa700c7a();  | |
if ( v81[0] )  | |
goto LABEL_50;  | |
v81[0] = 0LL;  | |
v75 = std::io::default_read_exact::h61fb53e2a02eb302(&v85, v81, 8LL);  | |
if ( v75 )  | |
goto LABEL_55;  | |
if ( !v81[0] )  | |
goto LABEL_70;  | |
v80 = (unsigned __int64)(like_i + 1) <= 60;  | |
like_i += 4LL;  | |
  } | |
while ( v80 );  | 
每次是赋值了 input 的 4 个字节 和比较数据的四个字节 但是不清楚跑哪里去了
而 v79 [204] v79 [205] v79 [206] v79 [207] 是栈中固定的位置,为什么下标怎么奇怪呢?
通过查找交叉引用可以发现

v79 是一开始 255 字节长的 shellcode

IDA 有些识别不太准确 在汇编中查看
.rodata:000055E808DA1B2B sub_55E808DA1B2B proc near              ; DATA XREF: seccomp_shell::shell::verify::h898bf5fa26dafbab+44D↑o
.rodata:000055E808DA1B2B push    rsp
.rodata:000055E808DA1B2C pop     rbp
.rodata:000055E808DA1B2D xor     esi, esi                        ; flags
.rodata:000055E808DA1B2F mov     rcx, 379F3A62B80657A1h
.rodata:000055E808DA1B39 mov     rdx, 37F7494DD66F358Eh
.rodata:000055E808DA1B43 xor     rcx, rdx
.rodata:000055E808DA1B46 push    rcx
.rodata:000055E808DA1B47 push    rsp
.rodata:000055E808DA1B48 pop     rdi                             ; filename
.rodata:000055E808DA1B49 push    2
.rodata:000055E808DA1B4B pop     rax
.rodata:000055E808DA1B4C cdq                                     ; mode
.rodata:000055E808DA1B4D syscall                                 ; LINUX - sys_open
.rodata:000055E808DA1B4F xchg    rax, rdi                        ; fd
.rodata:000055E808DA1B51 xor     eax, eax
.rodata:000055E808DA1B53 push    rax
.rodata:000055E808DA1B54 push    rsp
.rodata:000055E808DA1B55 pop     rsi                             ; buf
.rodata:000055E808DA1B56 push    4
.rodata:000055E808DA1B58 pop     rdx                             ; count
.rodata:000055E808DA1B59 syscall                                 ; LINUX - sys_read
.rodata:000055E808DA1B5B pop     r12
.rodata:000055E808DA1B5D push    3
.rodata:000055E808DA1B5F pop     rax
.rodata:000055E808DA1B60 syscall                                 ; LINUX - sys_close
.rodata:000055E808DA1B62 xor     esi, esi                        ; flags
.rodata:000055E808DA1B64 mov     rcx, 0AAC06463C36F3B3Bh
.rodata:000055E808DA1B6E mov     rdx, 0AAC06463C30B4C48h
.rodata:000055E808DA1B78 xor     rcx, rdx
.rodata:000055E808DA1B7B push    rcx
.rodata:000055E808DA1B7C mov     rcx, 7DA9F8D67582578Ch
.rodata:000055E808DA1B86 mov     rdx, 0EC888F916F632A3h
.rodata:000055E808DA1B90 xor     rcx, rdx
.rodata:000055E808DA1B93 push    rcx
.rodata:000055E808DA1B94 push    rsp
.rodata:000055E808DA1B95 pop     rdi                             ; filename
.rodata:000055E808DA1B96 push    2
.rodata:000055E808DA1B98 pop     rax
.rodata:000055E808DA1B99 cdq                                     ; mode
.rodata:000055E808DA1B9A syscall                                 ; LINUX - sys_open
.rodata:000055E808DA1B9C xchg    rax, rdi                        ; fd
.rodata:000055E808DA1B9E xor     eax, eax
.rodata:000055E808DA1BA0 push    rax
.rodata:000055E808DA1BA1 push    rsp
.rodata:000055E808DA1BA2 pop     rsi                             ; buf
.rodata:000055E808DA1BA3 push    4
.rodata:000055E808DA1BA5 pop     rdx                             ; count
.rodata:000055E808DA1BA6 syscall                                 ; LINUX - sys_read
.rodata:000055E808DA1BA8 pop     r13
.rodata:000055E808DA1BAA push    3
.rodata:000055E808DA1BAC pop     rax
.rodata:000055E808DA1BAD syscall                                 ; LINUX - sys_close
.rodata:000055E808DA1BAF xor     esi, esi                        ; flags
.rodata:000055E808DA1BB1 push    6Fh ; 'o'
.rodata:000055E808DA1BB3 mov     rcx, 77D9F62D0C06E559h
.rodata:000055E808DA1BBD mov     rdx, 5BC8C027A638176h
.rodata:000055E808DA1BC7 xor     rcx, rdx
.rodata:000055E808DA1BCA push    rcx
.rodata:000055E808DA1BCB push    rsp
.rodata:000055E808DA1BCC pop     rdi                             ; filename
.rodata:000055E808DA1BCD push    2
.rodata:000055E808DA1BCF pop     rax
.rodata:000055E808DA1BD0 cdq                                     ; mode
.rodata:000055E808DA1BD1 syscall                                 ; LINUX - sys_open
.rodata:000055E808DA1BD3 xchg    rax, rdi                        ; fd
.rodata:000055E808DA1BD5 xor     eax, eax
.rodata:000055E808DA1BD7 push    rax
.rodata:000055E808DA1BD8 push    rsp
.rodata:000055E808DA1BD9 pop     rsi                             ; buf
.rodata:000055E808DA1BDA push    4
.rodata:000055E808DA1BDC pop     rdx                             ; count
.rodata:000055E808DA1BDD syscall                                 ; LINUX - sys_read
.rodata:000055E808DA1BDF pop     rax
.rodata:000055E808DA1BE0 not     rax
.rodata:000055E808DA1BE3 shr     rax, 1Dh
.rodata:000055E808DA1BE7 cqo
.rodata:000055E808DA1BE9 push    29h ; ')'
.rodata:000055E808DA1BEB pop     rcx
.rodata:000055E808DA1BEC div     rcx
.rodata:000055E808DA1BEF xchg    rax, r14
.rodata:000055E808DA1BF1 push    3
.rodata:000055E808DA1BF3 pop     rax
.rodata:000055E808DA1BF4 syscall                                 ; LINUX - sys_close
.rodata:000055E808DA1BF6 mov     eax, 267814C2h
.rodata:000055E808DA1BFB add     eax, r12d
.rodata:000055E808DA1BFE xor     eax, r13d
.rodata:000055E808DA1C01 ror     eax, 0Bh
.rodata:000055E808DA1C04 not     eax
.rodata:000055E808DA1C06 xor     eax, r14d
.rodata:000055E808DA1C09 cmp     eax, 31FF2788h
.rodata:000055E808DA1C0E jnz     short loc_55E808DA1C15
.rodata:000055E808DA1C0E
.rodata:000055E808DA1C10 push    1
.rodata:000055E808DA1C12 pop     rax
.rodata:000055E808DA1C13 jmp     short loc_55E808DA1C18
.rodata:000055E808DA1C13
.rodata:000055E808DA1C15 ; ---------------------------------------------------------------------------
.rodata:000055E808DA1C15
.rodata:000055E808DA1C15 loc_55E808DA1C15:                       ; CODE XREF: sub_55E808DA1B2B+E3↑j
.rodata:000055E808DA1C15 xor     rax, rax
.rodata:000055E808DA1C15
.rodata:000055E808DA1C18
.rodata:000055E808DA1C18 loc_55E808DA1C18:                       ; CODE XREF: sub_55E808DA1B2B+E8↑j
.rodata:000055E808DA1C18 push    rax
.rodata:000055E808DA1C19 push    rbx
.rodata:000055E808DA1C1A pop     rdi                             ; fd
.rodata:000055E808DA1C1B push    rsp
.rodata:000055E808DA1C1C pop     rsi                             ; buf
.rodata:000055E808DA1C1D push    8
.rodata:000055E808DA1C1F pop     rdx                             ; count
.rodata:000055E808DA1C20 push    1
.rodata:000055E808DA1C22 pop     rax
.rodata:000055E808DA1C23 syscall                                 ; LINUX - sys_write
.rodata:000055E808DA1C25 push    rbp
.rodata:000055E808DA1C26 pop     rsp
.rodata:000055E808DA1C27 jmp     r15
.rodata:000055E808DA1C27
.rodata:000055E808DA1C27 sub_55E808DA1B2B endp
.rodata:000055E808DA1C27
发现之前赋值的 input 和比较数据都跑这里来了

add     eax, r12d #首先将 eax 与 r12d 相加
 xor     eax, r13d #然后将 eax 与 r13d 进行异或运算
 ror     eax, 0Bh #接着将 eax 向右旋转 11 位
 not     eax# 然后对 eax 求反
 xor     eax, r14d# 再将 eax 与 r14d 进行异或运算
关键就是上面几条汇编指令了 对 input 还进行了操作
关键就是找到 r12 r13 r14 的值
但这个 shellcode 在程序中好像没有拿出来执行 (也可能是因为我不会调)
而且这个程序好像就单纯的验证了服务器端和客服端的输入是否相同 有点闹麻

(有一个 std::io::default_read_exact 是从客服端接受,从 IDA 动态调试会卡住也能发现这一点)
分析 shellcode 可以得出 r12 r13 r14 是定值
分析方法:随便找一个简单的程序 用 IDApatch 成 shellcode 执行一下就行了
直接用 lazyIDA paste data


可以发现 r12 r13 r14 的定值是多少 然后就直接写 exp 脚本解得 flag 就 OK 了
import numpy as np  | |
def decrypt(data: list, table: dict):  | |
tmp=[]  | |
for i in data:  | |
tmp.append(table[i])  | |
    return tmp | |
def reverse_order(data:list, table: list):  | |
tmp = []  | |
for i in range(64):  | |
tmp.append(data[table[i]])  | |
    return tmp | |
# 定义一个函数,接受一个参数,返回解密后的值 | |
def de_cmp(x):  | |
    # 定义 r12, r13, r14 的值 | |
r12 = 0x0000000464C457F  | |
r13 = 0x0000000746F6F72  | |
r14 = 0x000000031F3831F  | |
    # 将 x 转换为无符号 32 位整数 | |
x = np.uint32(x)  | |
    # 将 x 与 r14 异或 | |
x = np.uint32(x ^ r14)  | |
    # 将 x 取反 | |
x = np.uint32(~x)  | |
    # 将 x 左旋 11 位 | |
x = np.uint32((x << 11) | (x >> (32 - 11)))  | |
    # 将 x 与 r13 异或 | |
x = np.uint32(x ^ r13)  | |
    # 将 x 减去 r12 | |
x = np.uint32(x - r12)  | |
    # 打印 x 的十六进制表示 | |
print(hex(x))  | |
    # 将 x 转换为有符号 32 位整数 | |
x = np.int32(x)  | |
    # 返回 x 的四个字节 | |
return [x & 0xff, (x & 0xff00) >> 8, (x & 0xff0000) >> 16, (x & 0xff000000) >> 24]  | |
#get crypto table | |
s0_255 = [0xFB, 0x7B, 0x4E, 0xBB, 0x51, 0x15, 0x8D, 0xDB, 0xB0, 0xAC, 0xA5, 0x8E, 0xAA, 0xB2, 0x60, 0xEB, 0x63, 0x5C, 0xDE, 0x42, 0x2B, 0xC6, 0xA6, 0x35, 0x30, 0x43, 0xD6, 0x5F, 0xBD, 0x24, 0xB1, 0xE3, 0x8C, 0xA7, 0xD5, 0x2A, 0x7C, 0x6D, 0x8B, 0x17, 0x9D, 0x83, 0xFE, 0x69, 0x10, 0x59, 0xA9, 0x9E, 0x0F, 0x1C, 0x66, 0x97, 0x5B, 0x61, 0xED, 0xAD, 0xE0, 0xDA, 0x27, 0x06, 0x25, 0xDC, 0x5E, 0xE7,  | |
0x41, 0x32, 0xD2, 0xD9, 0x8F, 0xEE, 0xAF, 0x03, 0x93, 0x3A, 0x00, 0xA2, 0xE1, 0xB3, 0xEC, 0x81, 0x9F, 0xCA, 0x58, 0xB7, 0x79, 0xFD, 0x3B, 0xA0, 0x02, 0x0C, 0xCB, 0xA8, 0x80, 0xC0, 0x16, 0x4D, 0x2F, 0x75, 0x71, 0x0A, 0x04, 0x39, 0xFF, 0xC1, 0x9C, 0xAB, 0xEF, 0xA4, 0xD8, 0xE2, 0x14, 0xC2, 0x6C, 0x64, 0x1E, 0x6B, 0x7E, 0x99, 0x2E, 0x09, 0x0B, 0x86, 0x74, 0x6A, 0xC4, 0x2D, 0x4F, 0xF9,  | |
0xFA, 0x94, 0xB6, 0x1F, 0x89, 0x6F, 0x5D, 0xE8, 0xEA, 0xB5, 0x5A, 0x65, 0x88, 0xC5, 0x7F, 0x77, 0x11, 0xCF, 0xF1, 0x1B, 0x3F, 0xF4, 0x48, 0x47, 0x12, 0xE4, 0xBA, 0xDF, 0xE9, 0x62, 0x6E, 0xB4, 0x96, 0xCD, 0x13, 0x53, 0x4B, 0x28, 0xD7, 0xD1, 0x33, 0xB8, 0xE6, 0x7A, 0x2C, 0x9B, 0x29, 0x44, 0x52, 0xF7, 0x20, 0xF2, 0x31, 0xD3, 0xB9, 0x40, 0xD0, 0x34, 0xF5, 0x54, 0x1A, 0x01, 0xA1, 0x92,  | |
0xFC, 0x85, 0x07, 0xBE, 0xDD, 0xBC, 0x19, 0xF3, 0x36, 0xF6, 0x72, 0x98, 0x4C, 0x7D, 0xC7, 0xD4, 0x45, 0x4A, 0x9A, 0xC3, 0x8A, 0xE5, 0x50, 0x46, 0xCC, 0x68, 0x76, 0x67, 0xC9, 0x0E, 0x3C, 0x57, 0xF0, 0x22, 0xBF, 0x26, 0x84, 0x0D, 0x90, 0xA3, 0xAE, 0x3D, 0x1D, 0xC8, 0x91, 0x05, 0x87, 0x70, 0x08, 0x73, 0x21, 0x49, 0x55, 0x3E, 0x37, 0x23, 0x18, 0x56, 0xCE, 0x82, 0x38, 0x95, 0x78, 0xF8]  | |
#load_data = [0xA7, 0x51, 0x68, 0x52, 0x85, 0x27, 0xFF, 0x31, 0x88, 0x87, 0xD2, 0xC7, 0xD3, 0x23, 0x3F, 0x52, 0x55, 0x10, 0x1F, 0xAF, 0x27, 0xF0, 0x94, 0x5C, 0xCD, 0x3F, 0x7A, 0x79, 0x9F, 0x2F, 0xF0, 0xE7, 0x45, 0xF0, 0x86, 0x3C, 0xF9, 0xB0, 0xEA, 0x6D, 0x90, 0x42, 0xF7, 0x91, 0xED, 0x3A, 0x9A, 0x7C, 0x01, 0x6B, 0x84, 0xDC, 0x6C, 0xC8, 0x43, 0x07, 0x5C, 0x08, 0xF7, 0xDF, 0xEB, 0xE3, 0xAE, 0xA4] | |
crypto_table = dict(zip(s0_255,range(0x100)))  | |
#get order table | |
source = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ{}'  | |
replaced = 'HfVl{qPcCYNMoRi6D7Jr}espOL3FhwdWAtTGZba4Ugjvnx1QkKE2IS9yuz5BX08m'  | |
revsere_table = [] #index 是 source 在 replace 中的下标  | |
for i in source:  | |
revsere_table.append(replaced.find(i))  | |
cmp_data = [0x526851A7, 0x31FF2785, 0xC7D28788, 0x523F23D3, 0xAF1F1055, 0x5C94F027, 0x797A3FCD, 0xE7F02F9F, 0x3C86F045, 0x6DEAB0F9, 0x91F74290, 0x7C9A3AED, 0xDC846B01, 0x0743C86C, 0xDFF7085C, 0xA4AEE3EB]  | |
tmp = []  | |
for i in cmp_data:  | |
tmp+=de_cmp(i)  | |
print(tmp)  | |
for i in range(256):  | |
tmp = decrypt(tmp, crypto_table)  | |
tmp = reverse_order(tmp, revsere_table)  | |
print(''.join(chr(i) for i in tmp))  | 
其中 python 和 C 语言的位运算有所不同 (对于符号位的处理) 所以需要使用 np 库
运行即可得到 flag
flag 是一个音乐网址 也算是一个小彩蛋吧
# 总结
有关加密算法由于太菜了不会逆 采用的是暴力的做法 相当于是 00-ff 的一个表 感觉以后遇到复杂的运算但又是按位加密的都可以这样做?