前言
- 这两天参加了 NU1LCTF 和 ByteCTF ,签了到之后发现一题都做不出来 /(ㄒoㄒ)/~~ ,很受伤。所以打算回顾一下错过的 SUCTF2019 ,多积累经验和学习更多的技术。
分析
-
IDA打开,发现程序是 LLVM 编译的,还加了花指令,导致看起来非常绕。
-
坑爹的是还不能动态调试,只能静态分析了。过程难以描述,这里就贴一下正确的执行步骤吧:
int __cdecl main(int argc, const char **argv, const char **envp) { signed int v3; // eax signed int v4; // eax signed int v5; // ecx signed int v6; // eax signed int v7; // eax signed int v8; // eax signed int v9; // eax signed int v10; // eax char v11; // al char v12; // al char v13; // al char v14; // al char v15; // al signed int v16; // ecx signed int v17; // eax signed int v18; // eax unsigned int v19; // eax unsigned int v20; // eax unsigned int v21; // eax signed int v22; // ecx char v24; // al char v25; // al char v26; // al char v27; // al signed int v28; // [rsp+9Ch] [rbp-94h] char v29; // [rsp+A0h] [rbp-90h] char v30; // [rsp+A8h] [rbp-88h] char v31; // [rsp+B0h] [rbp-80h] char v32; // [rsp+B8h] [rbp-78h] char v33; // [rsp+C0h] [rbp-70h] char v34; // [rsp+C8h] [rbp-68h] char v35; // [rsp+CFh] [rbp-61h] int v36; // [rsp+D0h] [rbp-60h] int input_len; // [rsp+D4h] [rbp-5Ch] int v38; // [rsp+D8h] [rbp-58h] int v39; // [rsp+DCh] [rbp-54h] char input[24]; // [rsp+E0h] [rbp-50h] char v41; // [rsp+F8h] [rbp-38h] char v42; // [rsp+100h] [rbp-30h] char v43; // [rsp+108h] [rbp-28h] char v44; // [rsp+110h] [rbp-20h] int v45; // [rsp+114h] [rbp-1Ch] const char **v46; // [rsp+118h] [rbp-18h] int v47; // [rsp+120h] [rbp-10h] int v48; // [rsp+124h] [rbp-Ch] int v49; // [rsp+128h] [rbp-8h] bool v50; // [rsp+12Eh] [rbp-2h] bool v51; // [rsp+12Fh] [rbp-1h] v48 = 0; v47 = argc; v46 = argv; v45 = time(0LL); puts("func(?)=\"01abfc750a0c942167651c40d088531d\"?"); input[0] = getchar(); fgets(&input[1], 21, stdin); v39 = time(0LL); v38 = v39 - v45; v49 = v39 - v45; v28 = 0x703FF685; while ( 1 ) { while ( 1 ) { while ( 1 ) { while ( 1 ) { while ( 1 ) { while ( 1 ) { while ( 1 ) { while ( 1 ) { while ( 1 ) { while ( 1 ) { while ( 1 ) { while ( 1 ) { while ( 1 ) { while ( 1 ) { while ( v28 == 0x8364E2E6 ) { v35 = v38 ^ input[v36];// v35=input[v36] v34 = GetChar((__int64)&v43, v35);// v34=v35 v33 = Get_Char_3((__int64)&v41, input[v38 - 1 + v36]);// v33=input[v36-1] v11 = Mod(&v33, 7); v35 = Add((__int64)&v34, v11); v32 = Get_Char_2((__int64)&v44, v35);// v32=v35 v31 = Get_Char_2((__int64)&v44, input[v38 - 1 + v36]); v12 = Xor(&v31, 18); v30 = Get_Char_4((__int64)&v42, v12); v13 = Mult(&v30, 3); v29 = GetChar((__int64)&v43, v13); v14 = Add((__int64)&v29, 2); v15 = Xor(&v32, v14); v16 = 0x4D79419D; v35 = v15; v51 = enc[v36 - 1] != v15; if ( y < 10 || (((_BYTE)x - 1) * (_BYTE)x & 1) == 0 ) v16 = 0xE6B1C47D; v28 = v16; } if ( v28 != 0x8B56CD07 ) break; v28 = 0x5E980F0E; } if ( v28 != 0x8FAFE559 ) break; v28 = 0xC54B2616; puts("You win"); } if ( v28 != 0x918FF00C ) break; v18 = 0x51FB290B; if ( y < 10 || (((_BYTE)x - 1) * (_BYTE)x & 1) == 0 ) v18 = 1154698238; v28 = v18; } if ( v28 != 0xB743BDDC ) break; v21 = 0x8FAFE559; if ( y < 10 || (((_BYTE)x - 1) * (_BYTE)x & 1) == 0 ) v21 = 0xC54B2616; v28 = v21; } if ( v28 != 0xC54B2616 ) break; puts("You win"); v22 = 0x8FAFE559; if ( y < 10 || (((_BYTE)x - 1) * (_BYTE)x & 1) == 0 ) v22 = 0x1B327C95; v28 = v22; } if ( v28 != 0xCB553B5C ) break; LABEL_70: v19 = 0xEB1FA22E; if ( y < 10 || (((_BYTE)x - 1) * (_BYTE)x & 1) == 0 ) v19 = 0xFCB084AC; v28 = v19; } if ( v28 != 0xD3E10A81 ) break; v4 = 0x7F611913; // (3) if ( y < 10 || (((_BYTE)x - 1) * (_BYTE)x & 1) == 0 ) v4 = 0x2C0D2A04; // (4) v28 = v4; // v28=0x2C0D2A04 } if ( v28 == 0xE4A1C025 ) exit(0); if ( v28 != 0xE6B1C47D ) break; v17 = 0x6EAC82CB; if ( v51 ) v17 = 0x918FF00C; v28 = v17; } if ( v28 != 0xEB1FA22E ) break; v28 = 0xFCB084AC; } if ( v28 != 0xEE73C818 ) break; v6 = 0x66996259; // (8) if ( v50 ) v6 = 0xE4A1C025; v28 = v6; // v28=0x66996259 } if ( v28 != 0xF28568CF ) break; v28 = 0x16FA3CE; } if ( v28 != 0xFCB084AC ) break; v20 = 0xEB1FA22E; if ( y < 10 || (((_BYTE)x - 1) * (_BYTE)x & 1) == 0 ) v20 = 0xF28568CF; v28 = v20; } if ( v28 != 0x16FA3CE ) break; ++v36; v28 = 0x5E980F0E; } if ( v28 == 0x1B327C95 ) return 0; if ( v28 == 0x1E2AAEDE ) { puts("Let the silent second hand take the place of my doubt..."); exit(0); } if ( v28 == 0x25297AE9 ) { v36 = 1; v28 = 0x437E1545; } else if ( v28 == 0x2C0D2A04 ) { input_len = strlen(input); // (5) v50 = input_len != 21; v5 = 0x7F611913; if ( y < 10 || (((_BYTE)x - 1) * (_BYTE)x & 1) == 0 ) v5 = 0xEE73C818; // (6) v28 = v5; // v28=0xEE73C818 } else if ( v28 == 0x3C4B1D57 ) { v10 = 0x4D79419D; if ( y < 10 || (((_BYTE)x - 1) * (_BYTE)x & 1) == 0 ) v10 = 0x8364E2E6; v28 = v10; } else if ( v28 == 0x437E1545 ) { v8 = 0x25297AE9; v36 = 1; if ( y < 10 || (((_BYTE)x - 1) * (_BYTE)x & 1) == 0 ) v8 = 0x8B56CD07; v28 = v8; } else { if ( v28 == 0x44D34BFE ) exit(0); if ( v28 == 0x4D79419D ) { v35 = v38 ^ input[v36]; v34 = GetChar((__int64)&v43, v35); v33 = Get_Char_3((__int64)&v41, input[v38 - 1 + v36]); v24 = Mod(&v33, 7); v35 = Add((__int64)&v34, v24); v32 = Get_Char_2((__int64)&v44, v35); v31 = Get_Char_2((__int64)&v44, input[v38 - 1 + v36]); v25 = Xor(&v31, 18); v30 = Get_Char_4((__int64)&v42, v25); v26 = Mult(&v30, 3); v29 = GetChar((__int64)&v43, v26); v27 = Add((__int64)&v29, 2); v35 = Xor(&v32, v27); v28 = 0x8364E2E6; } else { if ( v28 == 0x51FB290B ) exit(0); switch ( v28 ) { case 0x5E980F0E: // (10) v9 = 0xB743BDDC; if ( v36 < 21 ) // 进行20轮变换 v9 = 0x3C4B1D57; v28 = v9; break; case 0x66996259: // (9) v7 = 0x25297AE9; if ( y < 10 || (((_BYTE)x - 1) * (_BYTE)x & 1) == 0 ) v7 = 0x437E1545; v28 = v7; break; case 0x6EAC82CB: goto LABEL_70; case 0x703FF685: // (1) v3 = 0xD3E10A81; if ( v49 > 0 ) v3 = 0x1E2AAEDE; v28 = v3; // (2)v28=0xD3E10A81 break; case 0x7F611913: // (7) input_len = strlen(input); v28 = 0x2C0D2A04; break; } } } } }
-
标号的地方表示第 i 次执行的位置。到了第 10 次以后,我猜测程序应该是验证输入的数据了。验证的方式在:
-
原先的函数名也是没有意义的,经过分析之后被我重定义了。
-
所以得到递推关系:
v15=(input[v36]+(input[v36-1]%7))^((input[v36-1]^18)*3+2) //验证 v15==enc[v36 - 1]
-
所以反求 input 的关系式是:
input[i]=(enc[i-1]^((input[i-1]^18)*3+2)&0xff)-(input[i-1]%7)
-
但是 input[0] 需要爆破一下
脚本
enc=[0xf3,0x2e,0x18,0x36,0xe1,0x4c,0x22,0xd1,0xf9,0x8c,0x40,0x76,0xf4,0xe,0x0,0x5,0xa3,0x90,0xe,0xa5]
for k in range(128):
out=''
input=[]
input.append(k)
out+=chr(k)
for i in range(1,21):
ch=(enc[i-1]^((input[i-1]^18)*3+2)&0xff)-(input[i-1]%7)
input.append(ch&0xff)
out+=chr(ch&0xff)
if 'flag' in out:
print(out)
break
#flag{mY-CurR1ed_Fns}
总结
- 代码量不多的情况下,可以根据初始条件和输出提示,进行目标导向性的探索。猜测程序应该怎么走才会走向成功,探测路径应围绕着输入的数据进行。