2019 安洵杯 Re 部分WP
0x01.EasyEncryption
测试文件:https://www.lanzous.com/i7soysb
int sub_416560() { int v0; // eax int v1; // edx int v2; // edx int v3; // ecx int v4; // ST08_4 char v6[4]; // [esp+310h] [ebp-7E0h] char Str; // [esp+700h] [ebp-3F0h] int v8; // [esp+AECh] [ebp-4h] int savedregs; // [esp+AF0h] [ebp+0h] sub_41132A((int)&unk_424091); sub_411294(std::cout, "输入flag: "); sub_41113B(std::cin, &Str); sub_4111F4(&Str, (int)v6); // v6="artqkoehqpkbihv" if ( (unsigned __int8)sub_4112B7(v6) ) { sub_41105F("you are right\n"); system("pause"); sub_411339(v3, v2); } else { v0 = sub_411294(std::cout, "wrong"); sub_41114A(v0, 10); } v4 = v1; sub_41137A(&savedregs, &dword_416660, 0); return sub_411339((unsigned int)&savedregs ^ v8, v4); }
int __cdecl sub_413980(char *Str) { int v1; // edx int v2; // ecx int v3; // edx int v4; // ecx int v5; // edx int v6; // ecx char *Str1; // [esp+D0h] [ebp-8h] sub_41132A((int)&unk_42405B); Str1 = (char *)sub_4112D5(Str); // Base64 if ( !j_strcmp(Str1, "YXJ0cWtvZWhxcGtiaWh2") ) { free(Str1); sub_411339(v6, v5); } else { free(Str1); sub_411339(v2, v1); } return sub_411339(v4, v3); }
for ( i = 0; byte_41EC80[i]; ++i ) { v16 = (unsigned __int8)byte_41EC80[i] - 97; v2 = j_abs(v16); v15[i] = v2; }
Serial = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" Li = [] for i in Serial: Li.append(abs(ord(i) - 97)
v10 = j_strlen(Str); if ( v10 % i <= 0 ) { v3 = v10 % i; // 余数 v9 = v10 / i; // 商 } else { v3 = v10 % i; v9 = v10 / i + 1; }
for ( j = 0; j < v9; ++j ) { for ( k = 0; k < i; ++k ) { if ( Str[v14] ) // 输入的字符值不能为0 { if ( Str[v14] < 97 || Str[v14] > 122 ) // 输入只能是小写字母 exit(1); if ( (Str[v14] + v15[k] - 97) % 26 + 97 > 122 ) v4 = (Str[v14] + v15[k] - 97) % 26 + 71; else v4 = (Str[v14] + v15[k] - 97) % 26 + 97; v8 = v4; v3 = v14 + a2; *(_BYTE *)(v14++ + a2) = v8; } } }
Serial = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" Li = [] for i in Serial: Li.append(abs(ord(i) - 97)) print(Li) t1 = len(Li) - 1 enc = "artqkoehqpkbihv" v10 = len(enc) v14 = 0 Str = '' for j in range(1): for k in range(v10): for n in range(10): tmp1 = ord(enc[v14]) - 71 + 26 * n + 97 - Li[k] tmp2 = ord(enc[v14]) - 97 + 26 * n + 97 - Li[k] if tmp1 >= 97 and tmp1 <= 122: print ("SUCCESS!") Str += chr(tmp1) break elif tmp2 >= 97 and tmp2 <= 122: print ("SUCCESS!") Str += chr(tmp2) break else: print("ERROR!") v14 = v14 + 1 print (Str)
0x02 crackme
测试文件:https://www.lanzous.com/i7sucre
1.函数定位
首先定位到起始的函数sub_412AB0
1 int __stdcall sub_412AB0(int a1, int a2, int a3, int a4) 2 { 3 size_t i; // [esp+D8h] [ebp-8h] 4 5 for ( i = 0; i < j_strlen(BASE64_table_41A080); ++i ) 6 { 7 if ( BASE64_table_41A080[i] <= 122 && BASE64_table_41A080[i] >= 97 ) 8 { 9 BASE64_table_41A080[i] -= 32; 10 } 11 else if ( BASE64_table_41A080[i] <= 90 && BASE64_table_41A080[i] >= 65 ) 12 { 13 BASE64_table_41A080[i] += 32; 14 } 15 } 16 MessageBoxA(0, "hooked", "successed", 0); 17 AddVectoredExceptionHandler(0, Handler); 18 return 0; 19 }
2.程序分析
2.1 Base64变表1
根据起始函数的第一个for循环,这里首先对Base64的表进行的变换,将大小写进行对换。
#include <iostream> #include <string> using namespace std; string Str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; int main() { char v2; size_t i; // [esp+D8h] [ebp-8h] for (i = 0; i < Str.length(); ++i) { if (Str[i] <= 122 && Str[i] >= 97) { Str[i] -= 32; } else if (Str[i] <= 90 && Str[i] >= 65) { Str[i] += 32; } } cout << Str << endl; system("PAUSE"); return 0; }
得到新base64表"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/"
2.2 向量化异常处理
SetUnhandledExceptionFilter()函数:https://baike.baidu.com/item/SetUnhandledExceptionFilter/2334228?fr=aladdin
AddVectoredExceptionHandler()函数:https://www.cnblogs.com/suanguade/p/6674232.html
接着使用向量化异常处理,进入 Handler
1 int __stdcall Handler_0(_DWORD **a1) 2 { 3 char v2; // [esp+D0h] [ebp-18h] 4 char v3; // [esp+D1h] [ebp-17h] 5 char v4; // [esp+D2h] [ebp-16h] 6 char v5; // [esp+D3h] [ebp-15h] 7 char v6; // [esp+D4h] [ebp-14h] 8 char v7; // [esp+D5h] [ebp-13h] 9 char v8; // [esp+D6h] [ebp-12h] 10 char v9; // [esp+D7h] [ebp-11h] 11 char v10; // [esp+D8h] [ebp-10h] 12 char v11; // [esp+D9h] [ebp-Fh] 13 char v12; // [esp+DAh] [ebp-Eh] 14 char v13; // [esp+DBh] [ebp-Dh] 15 char v14; // [esp+DCh] [ebp-Ch] 16 char v15; // [esp+DDh] [ebp-Bh] 17 char v16; // [esp+DEh] [ebp-Ah] 18 char v17; // [esp+DFh] [ebp-9h] 19 20 if ( **a1 == -1073741819 ) 21 { 22 v2 = 'w'; 23 v3 = 'h'; 24 v4 = 'e'; 25 v5 = 'r'; 26 v6 = 'e'; 27 v7 = '_'; 28 v8 = 'a'; 29 v9 = 'r'; 30 v10 = 'e'; 31 v11 = '_'; 32 v12 = 'u'; 33 v13 = '_'; 34 v14 = 'n'; 35 v15 = 'o'; 36 v16 = 'w'; 37 v17 = '?'; 38 sm4_func((int)&unk_41A218, (int)&v2); 39 SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)TopLevelExceptionFilter); 40 } 41 return 0; 42 }
2.2.1 sm4加密
pysm4包下载安装教程:https://www.cnblogs.com/Mayfly-nymph/p/11939336.html
进入sm4_func函数(这个我改过名了)
int __cdecl sub_411F50(int a1, unsigned int *a2) { unsigned int v2; // eax int v3; // ecx int result; // eax unsigned int v5; // [esp+D0h] [ebp-B8h] unsigned int v6; // [esp+DCh] [ebp-ACh] unsigned int v7; // [esp+E0h] [ebp-A8h] unsigned int v8; // [esp+E4h] [ebp-A4h] int v9; // [esp+E8h] [ebp-A0h] int v10[34]; // [esp+ECh] [ebp-9Ch] unsigned int v11; // [esp+174h] [ebp-14h] unsigned int v12; // [esp+178h] [ebp-10h] unsigned int v13; // [esp+17Ch] [ebp-Ch] unsigned int v14; // [esp+180h] [ebp-8h] v5 = 0; v11 = _byteswap_ulong(*a2); v12 = _byteswap_ulong(a2[1]); v13 = _byteswap_ulong(a2[2]); v2 = _byteswap_ulong(a2[3]); v14 = v2; v6 = v11 ^ 0xA3B1BAC6; v7 = dword_417A68[1] ^ v12; v8 = dword_417A68[2] ^ v13; v3 = dword_417A68[3] ^ v2; result = 12; v9 = v3; while ( v5 < 0x20 ) { v10[v5] = *(&v6 + v5) ^ sub_4114E0(dword_417A78[v5] ^ *(&v9 + v5) ^ *(&v8 + v5) ^ *(&v7 + v5)); *(_DWORD *)(a1 + 4 * v5) = v10[v5]; result = v5++ + 1; } return result; }
Google搜了下0xA3B1BAC6
发现了这个函数应该是sm4加密
2.2.2 异常处理
接着,使用SetUnhandledExceptionFilter捕获异常,进入TopLevelExceptionFilter
1 _DWORD *__cdecl sub_412C30(_DWORD *a1) 2 { 3 _DWORD *result; // eax 4 char v2; // STD7_1 5 size_t i; // [esp+DCh] [ebp-8h] 6 7 result = a1; 8 if ( *(_DWORD *)*a1 == -1073741819 ) 9 { 10 for ( i = 0; i < j_strlen(Str2); i += 2 ) 11 { 12 v2 = Str2[i]; 13 Str2[i] = Str2[i + 1]; 14 Str2[i + 1] = v2; 15 } 16 Str1 = sub_41126C(byte_41A180); 17 *(_DWORD *)(a1[1] + 176) = *(_DWORD *)(*a1 + 20); 18 *(_DWORD *)(a1[1] + 164) = *(_DWORD *)(*a1 + 24); 19 *(_DWORD *)(a1[1] + 172) = *(_DWORD *)(*a1 + 28); 20 *(_DWORD *)(a1[1] + 168) = *(_DWORD *)(*a1 + 32); 21 *(_DWORD *)(a1[1] + 156) = *(_DWORD *)(*a1 + 36); 22 *(_DWORD *)(a1[1] + 160) = *(_DWORD *)(*a1 + 40); 23 *(_DWORD *)(a1[1] + 184) = sub_411136; 24 result = (_DWORD *)-1; 25 } 26 return result; 27 }
第一个for循环就是在将Str2相邻两位互换
#include <iostream> #include <string> using namespace std; string Str2 = "1UTAOIkpyOSWGv/mOYFY4R!!"; int main() { char v2; for (int i = 0; i < Str2.length(); i += 2) { v2 = Str2[i]; Str2[i] = Str2[i + 1]; Str2[i + 1] = v2; } cout << Str2 << endl; system("PAUSE"); return 0; }
接着通过sub_41126C函数传入byte_41A180,返回值为Str2,最后将Str1与Str2比较是否相同,输出success或者error,这就很明显了,肯定要输出‘success’,那Str2就要等于'U1ATIOpkOyWSvGm/YOYFR4!!'
2.2.3 Base64变表2
打开sub_41126C函数
1 _BYTE *__cdecl sub_413090(char *Str) 2 { 3 int k; // [esp+E4h] [ebp-5Ch] 4 int v3; // [esp+F0h] [ebp-50h] 5 signed int j; // [esp+FCh] [ebp-44h] 6 int v5; // [esp+108h] [ebp-38h] 7 signed int i; // [esp+114h] [ebp-2Ch] 8 _BYTE *v7; // [esp+120h] [ebp-20h] 9 signed int v8; // [esp+12Ch] [ebp-14h] 10 int v9; // [esp+138h] [ebp-8h] 11 12 v5 = 0; 13 v8 = j_strlen(Str); // Str长度 14 if ( v8 % 3 ) // 设置字节长度 15 v9 = 4 * (v8 / 3) + 4; 16 else 17 v9 = 4 * (v8 / 3); 18 v7 = malloc((v9 + 1) | -__CFADD__(v9, 1)); // 申请空间 19 v7[v9] = 0; 20 for ( i = 0; i < v8; i += 3 ) // 三位三位的处理,base64? 21 { 22 v3 = 0; 23 for ( j = 0; j < 3; ++j ) 24 v3 |= (unsigned __int8)Str[j + i] << 8 * (2 - j); 25 for ( k = 0; k < 4; ++k ) 26 { 27 if ( k >= 4 - (i + 3 - v8) && i + 3 > v8 )// 长度大于等于4的部分使用'!'补齐 28 v7[v5] = '!'; 29 else 30 v7[v5] = ::Str[sub_4110FF((v3 >> 6 * (3 - k)) & 0x3F)]; 31 ++v5; 32 } 33 } 34 return v7; 35 }
在函数sub_4110FF有一步不同的操作
int __cdecl sub_412760(int a1) { return (a1 + 24) % 64; }
这里+24,相当于变表的值为原表取值右移24位
Str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/" Str1 = '' for i in Str: Str1 += Str[(Str.find(i)+24) % len(Str)] print (Str1)
得到新的Base64表"yzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/abcdefghijklmnopqrstuvwx"
到这我们整个过程就分析完毕了,接下来只需要逆向操作就行了。
3.逆向解密
# encoding: utf-8 from pysm4 import decrypt,encrypt from base64 import b64decode Str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/" Str_ = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" Str1 = '' # 变换之后的Base64表 for i in Str: Str1 += Str[(Str.find(i)+24) % len(Str)] print (Str1) # 之前是用变换之后的表进行Base64加密 # 现在转换为正常的Base64加密, # 再解密得到sm4加密之后的字符串 enc = "U1ATIOpkOyWSvGm/YOYFR4!!" dec1 = '' for i in range(len(enc)): if enc[i] == '!': dec1 += '=' else: dec1 += Str_[Str1.find(enc[i])] print (dec1) dec2 = b64decode(dec1) print (dec2) import codecs # 先进行hex编码,再转换为十进制整型 encode_hex = codecs.getencoder("hex_codec") dec3 = int(encode_hex(dec2)[0],16) print (dec3) # 将key转换为十进制 key = "where_are_u_now?" key = int(encode_hex(key)[0],16) print (key) # 将解密的字符串转换会hex decode_hex = codecs.getdecoder("hex_codec") dec4 = decrypt(dec3, key) dec4 = str(hex(dec4)[2:-1]) print (decode_hex(dec4)[0])
4. get flag!
flag{SM4foRExcepioN?!}
官方公布源码:https://github.com/D0g3-Lab/i-SOON_CTF_2019
其他WP:https://blog.csdn.net/Zarcs_233/article/details/103338006
这次进入线下,希望能够好好发挥,加油!