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{}
原顺序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的一个表 感觉以后遇到复杂的运算但又是按位加密的都可以这样做?