[SCTF2019]creakme
查阅资料:
https://www.anquanke.com/post/id/181019#h3-16
https://blog.csdn.net/orbit/article/details/1497457
https://blog.csdn.net/qq_41071646/article/details/93536419
这道题看了好久,没看懂意思,后面看了师傅们的wp才看懂,原来是aes加密,并且对aes进行了一番学习
先贴下主函数的源码
1 int sub_402540() 2 { 3 HMODULE v0; // eax 4 int v1; // eax 5 _DWORD *v2; // eax 6 unsigned int v3; // edx 7 _DWORD *v4; // ecx 8 unsigned int v5; // ebx 9 char *v6; // edi 10 unsigned int v7; // esi 11 unsigned int v8; // esi 12 bool v9; // cf 13 unsigned __int8 v10; // al 14 unsigned __int8 v11; // al 15 unsigned __int8 v12; // al 16 signed int v13; // esi 17 _BYTE *v14; // ecx 18 _BYTE *v15; // ecx 19 const char *v16; // edx 20 int v17; // eax 21 void *Memory; // [esp+10h] [ebp-70h] 22 int v20; // [esp+20h] [ebp-60h] 23 unsigned int v21; // [esp+24h] [ebp-5Ch] 24 void *Dst; // [esp+28h] [ebp-58h] 25 int v23; // [esp+38h] [ebp-48h] 26 unsigned int v24; // [esp+3Ch] [ebp-44h] 27 char Src; // [esp+40h] [ebp-40h] 28 int v26; // [esp+7Ch] [ebp-4h] 29 30 v0 = GetModuleHandleW(0); 31 sub_402320(v0); 32 sub_4024A0(); 33 v1 = sub_402870(std::cout, "welcome to 2019 sctf"); 34 std::basic_ostream<char,std::char_traits<char>>::operator<<(v1, sub_402AC0); 35 sub_402870(std::cout, "please input your ticket:"); 36 sub_402AF0(std::cin, &Src); 37 v23 = 0; 38 v24 = 15; 39 LOBYTE(Dst) = 0; 40 sub_401D30(&Dst, &Src, strlen(&Src)); 41 v26 = 0; 42 v2 = (_DWORD *)sub_4020D0(&Memory, &Dst); 43 v3 = strlen(aPvfqyc4ttc2uxr); 44 v4 = v2; 45 if ( v2[5] >= 0x10u ) 46 v4 = (_DWORD *)*v2; 47 v5 = v2[4]; 48 v6 = aPvfqyc4ttc2uxr; 49 v7 = v2[4]; 50 if ( v3 < v5 ) 51 v7 = v3; 52 v9 = v7 < 4; 53 v8 = v7 - 4; 54 if ( v9 ) 55 { 56 LABEL_8: 57 if ( v8 == -4 ) 58 goto LABEL_17; 59 } 60 else 61 { 62 while ( *v4 == *(_DWORD *)v6 ) 63 { 64 ++v4; 65 v6 += 4; 66 v9 = v8 < 4; 67 v8 -= 4; 68 if ( v9 ) 69 goto LABEL_8; 70 } 71 } 72 v9 = *(_BYTE *)v4 < (unsigned __int8)*v6; 73 if ( *(_BYTE *)v4 != *v6 74 || v8 != -3 75 && ((v10 = *((_BYTE *)v4 + 1), v9 = v10 < (unsigned __int8)v6[1], v10 != v6[1]) 76 || v8 != -2 77 && ((v11 = *((_BYTE *)v4 + 2), v9 = v11 < (unsigned __int8)v6[2], v11 != v6[2]) 78 || v8 != -1 && (v12 = *((_BYTE *)v4 + 3), v9 = v12 < (unsigned __int8)v6[3], v12 != v6[3]))) ) 79 { 80 v13 = -v9 | 1; 81 goto LABEL_18; 82 } 83 LABEL_17: 84 v13 = 0; 85 LABEL_18: 86 if ( !v13 ) 87 { 88 if ( v3 <= v5 ) 89 v13 = v3 < v5; 90 else 91 v13 = -1; 92 } 93 if ( v21 >= 0x10 ) 94 { 95 v14 = Memory; 96 if ( v21 + 1 >= 0x1000 ) 97 { 98 v14 = (_BYTE *)*((_DWORD *)Memory - 1); 99 if ( (unsigned int)((_BYTE *)Memory - v14 - 4) > 0x1F ) 100 invalid_parameter_noinfo_noreturn(v14, v21 + 36); 101 } 102 sub_402F05(v14); 103 } 104 v26 = -1; 105 v20 = 0; 106 v21 = 15; 107 LOBYTE(Memory) = 0; 108 if ( v24 >= 0x10 ) 109 { 110 v15 = Dst; 111 if ( v24 + 1 >= 0x1000 ) 112 { 113 v15 = (_BYTE *)*((_DWORD *)Dst - 1); 114 if ( (unsigned int)((_BYTE *)Dst - v15 - 4) > 0x1F ) 115 invalid_parameter_noinfo_noreturn(v15, v24 + 36); 116 } 117 sub_402F05(v15); 118 } 119 v16 = "Have fun!"; 120 if ( v13 ) 121 v16 = "A forged ticket!!"; 122 v17 = sub_402870(std::cout, v16); 123 std::basic_ostream<char,std::char_traits<char>>::operator<<(v17, sub_402AC0); 124 system("pause"); 125 return 0; 126 }
看起来很麻烦
进入函数sub_401D30里面看看,发现其是结构体在第20个字节后,便是字符串的长度size,然后其余的便是赋值。
再进入函数sub_4020D0里面看看,发现了这些
可以发现这是一个aes的加密,由于函数sub_401690和函数sub_4013E0都有一个相同的参数,所以猜测这个v31是密钥(其实我点进去分析了,看了一阵子,太长了,不过看到赋值操作和偏移,感觉还是有点感觉的,汇编和C的代码审计还是有点拉胯)
不过既然知道是aes加密,那么从可以分析出,这是与前一个密文进行异或,这里进行加密
所以先异或后加密,每次都会执行便可以判断是CBC加密模式
然后查看v31这个函数发现里面有一个全局变量,给其赋值,
并且该函数还把也赋值进了v31的偏移,所以这两个里面有一个是key有一个是vi,把其化为字符串就可以发现xmmword_407360是sctfsctfsctfsctf看起来更像vi向量点,但在解密的时候,并没有解出来,后面感觉是动态加载的,想进入调试器调试,可是他有检测调试的方法,看了别的师傅的wp也没明白是什么,只知道一个名词SMP技术,然后就去查了一下,可惜没查出什么,不过我想了一下既然他是在放出字符串之前进行的动态加载,那么我是不是等他字符串出来后再去附加进程就可以了呢?果不其然!
然后拿着这串密文去解密
本题感悟:写的题好少,目前写题都需要查许多资料,说明自己在知识储备上的不足,这道题就是一个明显的体现,其次需要加深对加密代码的映象,所以我选择的方法是逆一遍自己写的加密算法并写出其解密算法来进行训练,其次是加深汇编的功底和逆向的效率这两个一直都是我的致命缺点