测试文件:https://lanzous.com/ic9ox7a
SMC自修改代码
代码分析
首先,我们使用插件Findcript可以发现,这段程序中存在的加密方式:
去混淆
1 void __fastcall __noreturn main(__int64 a1, char **a2, char **a3) 2 { 3 signed int i; // [rsp+8h] [rbp-48h] 4 char s; // [rsp+20h] [rbp-30h] 5 unsigned __int64 v5; // [rsp+48h] [rbp-8h] 6 7 v5 = __readfsqword(0x28u); 8 __isoc99_scanf("%39s", &s, a3); 9 if ( (unsigned int)strlen(&s) != 32 ) 10 { 11 puts("Wrong!"); 12 exit(0); 13 } 14 mprotect(&dword_400000, 0xF000uLL, 7); 15 for ( i = 0; i <= 223; ++i ) 16 *((_BYTE *)sub_402219 + i) ^= 0x99u; 17 sub_40207B(&unk_603170, 61440LL); 18 sub_402219(&s); 19 }
主函数中,第15~16行代码对函数sub_402219进行了异或0x99的操作,打开sub_402219函数,可以看到(选中0x402219区域,按D转换为Data形式)
因此,我们首先需要将数据还原,使用IDC脚本
#includestatic main() { auto addr = 0x402219; auto i; for(i = 0; i <= 223; ++i){ PatchByte(addr+i,Byte(addr+i)^0x99); } }
选中数据,右键分析选中区域,选择force强制执行,最后选中我们编译后的代码,按P键形成函数。得到
__int64 __fastcall sub_402219(__int64 a1) { unsigned int v2; // [rsp+18h] [rbp-D8h] signed int i; // [rsp+1Ch] [rbp-D4h] char v4; // [rsp+20h] [rbp-D0h] unsigned __int64 v5; // [rsp+E8h] [rbp-8h] v5 = __readfsqword(0x28u); sub_400A71(&v4, &unk_603170); sub_40196E(&v4, a1); sub_40196E(&v4, a1 + 16); v2 = 1; for ( i = 0; i <= 31; ++i ) { if ( *(_BYTE *)(i + a1) != byte_6030A0[i] ) v2 = 0; } return v2; }
主函数
void __fastcall __noreturn main(__int64 a1, char **a2, char **a3) { signed int i; // [rsp+8h] [rbp-48h] char s; // [rsp+20h] [rbp-30h] unsigned __int64 v5; // [rsp+48h] [rbp-8h] v5 = __readfsqword(0x28u); __isoc99_scanf("%39s", &s, a3); if ( (unsigned int)strlen(&s) != 32 ) { puts("Wrong!"); exit(0); } mprotect(&dword_400000, 0xF000uLL, 7); for ( i = 0; i <= 223; ++i ) *((_BYTE *)sub_402219 + i) ^= 0x99u; sub_40207B((__int64)&Val0); sub_402219((__int64)&s); JUMPOUT(loc_4021F5); }
可以看到,主要的函数就是sub_40207B和sub_402219,我们倒着分析。(将)
sub_402219函数
__int64 __fastcall sub_402219(__int64 a1) { unsigned int v2; // [rsp+18h] [rbp-D8h] signed int i; // [rsp+1Ch] [rbp-D4h] char v4; // [rsp+20h] [rbp-D0h] unsigned __int64 v5; // [rsp+E8h] [rbp-8h] v5 = __readfsqword(0x28u); sub_400A71((__int64)&v4, (__int64)&Val0); // 使用Val0作为初始秘钥,轮秘钥生成 sub_40196E((__int64)&v4, a1); // 前16位AES加密 sub_40196E((__int64)&v4, a1 + 16); // 后16位AES加密 v2 = 1; for ( i = 0; i <= 31; ++i ) { if ( *(_BYTE *)(i + a1) != byte_6030A0[i] ) v2 = 0; } return v2; }
很明显的看得出,就是将Val0作为初始秘钥来加密我们输入的flag,最后与byte_6030A0比较。byte_6030A0已知为
BC0AADC0147C5ECCE0B140BC9C51D52B46B2B9434DE5324BAD7FB4B39CDB4B5B
因此,我们只需要知道Val0就能反解出flag。
sub_40207B函数
1 unsigned __int64 __fastcall sub_40207B(__int64 a1) 2 { 3 char v2; // [rsp+10h] [rbp-50h] 4 __int64 v3; // [rsp+20h] [rbp-40h] 5 __int64 v4; // [rsp+30h] [rbp-30h] 6 __int64 v5; // [rsp+40h] [rbp-20h] 7 unsigned __int64 v6; // [rsp+58h] [rbp-8h] 8 9 v6 = __readfsqword(0x28u); 10 Encrypt_Func(&BASE64_table_603120, 0x40uLL, (__int64)&v2);// 将BASE64表传入Encrypt_Func加密后存储到v2 11 Encrypt_Func(&CRC32_table_603100, 0x14uLL, (__int64)&v3); 12 Encrypt_Func(&Prime_Constants_char_6030C0, 0x35uLL, (__int64)&v4); 13 Encrypt_Func(MD5_Constants_4025C0, 0x100uLL, (__int64)&v5); 14 Encrypt_Func(&v2, 0x40uLL, a1); // 再将v2进行Encrypt_Func加密,存储到a1 15 return __readfsqword(0x28u) ^ v6; 16 }
实际这段函数,与我们a1(即Val0)有关的第14行代码,将v2进行某种加密后赋值给a1,因此这里只需要第10行代码,其余的加密都无关。
第10行代码将Base64表传入加密,得到v2。
我们能够通过调试得到Val0的值为
.bss:0000000000603170 Val0 db 0CBh ; DATA XREF: main+B9↑o .bss:0000000000603170 ; sub_402219+28↑o .bss:0000000000603171 db 8Dh .bss:0000000000603172 db 49h ; I .bss:0000000000603173 db 35h ; 5 .bss:0000000000603174 db 21h ; ! .bss:0000000000603175 db 0B4h .bss:0000000000603176 db 7Ah ; z .bss:0000000000603177 db 4Ch ; L .bss:0000000000603178 db 0C1h .bss:0000000000603179 db 0AEh .bss:000000000060317A db 7Eh ; ~ .bss:000000000060317B db 62h ; b .bss:000000000060317C db 22h ; " .bss:000000000060317D db 92h .bss:000000000060317E db 66h ; f .bss:000000000060317F db 0CEh
CB8D493521B47A4CC1AE7E62229266CE
总结
因此总的过程就是
- 使用Base64表经过Encrypt_Func函数两次加密,传入Val0
- 使用Val0作为Key,进行AES加密
- 结果与byte_6030A0比较
脚本
from Crypto.Cipher import AES import codecs aes = AES.new(decode_hex('CB8D493521B47A4CC1AE7E62229266CE')[0], AES.MODE_ECB) print(aes.decrypt(decode_hex('BC0AADC0147C5ECCE0B140BC9C51D52B46B2B9434DE5324BAD7FB4B39CDB4B5B')[0]))
得到
get flag!
flag{924a9ab2163d390410d0a1f670}