-
-
[原创] 看雪.TSRC 2017CTF秋季赛第三题crackMe破解过程
-
2017-10-28 23:55 3098
-
本题反调试比较多,算法有BUG,分析得可能不算到位,请见谅。
下载地址:https://ctf.pediy.com/attach-download-80.htm
一、侦查:
无壳,粗略分析有Base64等算法,有成功提示信息,定位"ok"找到注册算法流程:
三、算法:
⑵: 对64位SM3进行2次 Base64解码 ,要求解码后的前3字节与穷举的3字节吻合,并且解码结果包含“0x2f”即可将64位作为正确答案。
但本题算法包含BUG,首先Base64对64位SM3结果进行2次解码后,很有可能输出空白结果,前3字节容易构造“0x00”或“0x2f”;
其次“0x20”标志不一定可靠,即算法第 ⑵ 步解码结果未包含0x2f,未设置0x20标志位,最后第 ⑸ 步也有很大概率验证通过(具体BUG原因未继续细查,估计是检测地址范围过大,内存状态每次运行都会有所变化,也有其他原因可能导致该BUG)。
② :综上所述,我们可以随意选择一种方法进行破解
⑴ :比如构造 Base64的2次解码输出3字节“0x00,0x00,0x00”,得到SM3:“183920f00e15a0433ee3a8fc90dd9ac164c4142ccf63ca189a8f645ec96ff8de”,输入该64位字符有很大可能通过验证,因2次Base64解码未包含“0x2f”没有设置“0x20”标志位,所以通过验证靠运气,有时不行,但按比赛规则有一次通过就算题目被破解。
⑵: 再比如,我们还可以构造2次Base64解码输出“0x2f”结果的 -->1次Base64加密 “Lw==” --> 2次Base64加密“THc9PQo”,把 “THc9PQo”输入Crackme观察SM3加密结果为“2f725aaf8d9fa538554e9f3589ddc785364d52ab1a6760c12caa2ec01ae4ba9e”,也就是“0x2f,0x00,0x00”这3个字节的SM3加密结果(可以自己写代码或者利用算法工具验证), “2f725aaf8d9fa538554e9f3589ddc785364d52ab1a6760c12caa2ec01ae4ba9e” 在本题中的2次Base64解码为空,因此在其前面连接 “THc9PQo” 即可:
THc9PQo2f725aaf8d9fa538554e9f3589ddc785364d52ab1a6760c12caa2ec01ae4ba9e
类似的构造方法太多了,答案数不胜数。
五、总结:
本题利用大量反调试手段抵抗破解,采用密码学算法增加强度,但结果也是戏剧化的。
下载地址:https://ctf.pediy.com/attach-download-80.htm
一、侦查:
无壳,粗略分析有Base64等算法,有成功提示信息,定位"ok"找到注册算法流程:
00435061 . 68 01040000 PUSH 0x401 ; /Count = 401 (1025.) 00435066 . 8D85 D8F7FFFF LEA EAX,DWORD PTR SS:[EBP-0x828] ; | 0043506C . 50 PUSH EAX ; |Buffer 0043506D . 68 E9030000 PUSH 0x3E9 ; |ControlID = 3E9 (1001.) 00435072 . 8B4D 08 MOV ECX,DWORD PTR SS:[EBP+0x8] ; | 00435075 . 51 PUSH ECX ; |hWnd 00435076 . FF15 70F54900 CALL DWORD PTR DS:[<&USER32.GetDlgItemTe>; \GetDlgItemTextA 0043507C . 3BF4 CMP ESI,ESP 0043507E . E8 CE8DFFFF CALL crackMe3.0042DE51 00435083 . 8985 E0FBFFFF MOV DWORD PTR SS:[EBP-0x420],EAX 00435089 . C685 C8EFFFFF>MOV BYTE PTR SS:[EBP-0x1038],0x0 00435090 . 68 FF030000 PUSH 0x3FF 00435095 . 6A 00 PUSH 0x0 00435097 . 8D85 C9EFFFFF LEA EAX,DWORD PTR SS:[EBP-0x1037] 0043509D . 50 PUSH EAX 0043509E . E8 4385FFFF CALL crackMe3.0042D5E6 004350A3 . 83C4 0C ADD ESP,0xC 004350A6 . 8D85 D0F3FFFF LEA EAX,DWORD PTR SS:[EBP-0xC30] 004350AC . 50 PUSH EAX 004350AD . 68 00040000 PUSH 0x400 004350B2 . 8D8D D8F7FFFF LEA ECX,DWORD PTR SS:[EBP-0x828] 004350B8 . 51 PUSH ECX 004350B9 . E8 A981FFFF CALL crackMe3.0042D267 ; Base64解码 004350BE . 83C4 0C ADD ESP,0xC 004350C1 . C685 C0EBFFFF>MOV BYTE PTR SS:[EBP-0x1440],0x0 004350C8 . 68 FF030000 PUSH 0x3FF 004350CD . 6A 00 PUSH 0x0 004350CF . 8D85 C1EBFFFF LEA EAX,DWORD PTR SS:[EBP-0x143F] 004350D5 . 50 PUSH EAX 004350D6 . E8 0B85FFFF CALL crackMe3.0042D5E6 004350DB . 83C4 0C ADD ESP,0xC 004350DE . 8D85 C8EFFFFF LEA EAX,DWORD PTR SS:[EBP-0x1038] 004350E4 . 50 PUSH EAX 004350E5 . 68 00040000 PUSH 0x400 004350EA . 8D8D D0F3FFFF LEA ECX,DWORD PTR SS:[EBP-0xC30] 004350F0 . 51 PUSH ECX 004350F1 . E8 7181FFFF CALL crackMe3.0042D267 ; Base64解码 004350F6 . 83C4 0C ADD ESP,0xC 004350F9 . 68 00040000 PUSH 0x400 004350FE . 8D85 C0EBFFFF LEA EAX,DWORD PTR SS:[EBP-0x1440] 00435104 . 50 PUSH EAX 00435105 . 8D8D C8EFFFFF LEA ECX,DWORD PTR SS:[EBP-0x1038] 0043510B . 51 PUSH ECX 0043510C . E8 5988FFFF CALL crackMe3.0042D96A ; 0x20 set 00435111 . 83C4 0C ADD ESP,0xC 00435114 . C785 B4EBFFFF>MOV DWORD PTR SS:[EBP-0x144C],0x3 0043511E . 8D85 8CEBFFFF LEA EAX,DWORD PTR SS:[EBP-0x1474] 00435124 . 50 PUSH EAX 00435125 . 8B8D B4EBFFFF MOV ECX,DWORD PTR SS:[EBP-0x144C] 0043512B . 51 PUSH ECX 0043512C . 8D95 C8EFFFFF LEA EDX,DWORD PTR SS:[EBP-0x1038] 00435132 . 52 PUSH EDX 00435133 . E8 4089FFFF CALL crackMe3.0042DA78 ; 国密SM3(前3字节) 00435138 . 83C4 0C ADD ESP,0xC 0043513B . C785 78E7FFFF>MOV DWORD PTR SS:[EBP-0x1888],0x0 00435145 . EB 0F JMP XcrackMe3.00435156 00435147 > 8B85 78E7FFFF MOV EAX,DWORD PTR SS:[EBP-0x1888] 0043514D . 83C0 01 ADD EAX,0x1 00435150 . 8985 78E7FFFF MOV DWORD PTR SS:[EBP-0x1888],EAX 00435156 > 83BD 78E7FFFF>CMP DWORD PTR SS:[EBP-0x1888],0x20 0043515D . 7D 2C JGE XcrackMe3.0043518B 0043515F . 8B85 78E7FFFF MOV EAX,DWORD PTR SS:[EBP-0x1888] 00435165 . 0FB68C05 8CEB>MOVZX ECX,BYTE PTR SS:[EBP+EAX-0x1474] 0043516D . 51 PUSH ECX 0043516E . 68 A4B14800 PUSH crackMe3.0048B1A4 ; ASCII "%02x" 00435173 . 8B95 78E7FFFF MOV EDX,DWORD PTR SS:[EBP-0x1888] 00435179 . 8D8455 84E7FF>LEA EAX,DWORD PTR SS:[EBP+EDX*2-0x187C] 00435180 . 50 PUSH EAX 00435181 . E8 7F8DFFFF CALL crackMe3.0042DF05 ; 十六进制转ASCII 00435186 . 83C4 0C ADD ESP,0xC 00435189 .^ EB BC JMP XcrackMe3.00435147 0043518B > 8D85 84E7FFFF LEA EAX,DWORD PTR SS:[EBP-0x187C] 00435191 . 50 PUSH EAX 00435192 . E8 FD85FFFF CALL crackMe3.0042D794 ; len 00435197 . 83C4 04 ADD ESP,0x4 0043519A . 50 PUSH EAX 0043519B . 8D8D D8F7FFFF LEA ECX,DWORD PTR SS:[EBP-0x828] 004351A1 . 51 PUSH ECX 004351A2 . E8 ED85FFFF CALL crackMe3.0042D794 ; len 004351A7 . 83C4 04 ADD ESP,0x4 004351AA . 8DB405 D8F7FF>LEA ESI,DWORD PTR SS:[EBP+EAX-0x828] 004351B1 . 8D95 84E7FFFF LEA EDX,DWORD PTR SS:[EBP-0x187C] 004351B7 . 52 PUSH EDX 004351B8 . E8 D785FFFF CALL crackMe3.0042D794 ; len 004351BD . 83C4 04 ADD ESP,0x4 004351C0 . 2BF0 SUB ESI,EAX 004351C2 . 56 PUSH ESI 004351C3 . 8D85 84E7FFFF LEA EAX,DWORD PTR SS:[EBP-0x187C] 004351C9 . 50 PUSH EAX 004351CA . E8 5889FFFF CALL crackMe3.0042DB27 ; cmp Hash 64字节对比和输入的右侧64字节(不足留0x0) 004351CF . 83C4 0C ADD ESP,0xC 004351D2 . 85C0 TEST EAX,EAX 004351D4 . 75 3E JNZ XcrackMe3.00435214 ; 关键跳1 004351D6 . E8 D97EFFFF CALL crackMe3.0042D0B4 004351DB . 8D85 C0EBFFFF LEA EAX,DWORD PTR SS:[EBP-0x1440] 004351E1 . 50 PUSH EAX 004351E2 . 68 00B04900 PUSH crackMe3.0049B000 004351E7 . E8 BF87FFFF CALL crackMe3.0042D9AB ; 0x20 check 004351EC . 83C4 08 ADD ESP,0x8 004351EF . 0FB6C8 MOVZX ECX,AL 004351F2 . 83F9 01 CMP ECX,0x1 004351F5 . 75 1D JNZ XcrackMe3.00435214 ; 关键跳2 004351F7 . 8BF4 MOV ESI,ESP 004351F9 . 6A 00 PUSH 0x0 ; /Style = MB_OK|MB_APPLMODAL 004351FB . 68 98B14800 PUSH crackMe3.0048B198 ; |Title = "CrackMe" 00435200 . 68 94B14800 PUSH crackMe3.0048B194 ; |Text = "ok" 00435205 . 6A 00 PUSH 0x0 ; |hOwner = NULL 00435207 . FF15 88F54900 CALL DWORD PTR DS:[<&USER32.MessageBoxA>>; \MessageBoxA
v20 = GetDlgItemTextA(hDlg, 1001, &String, 1025); v14 = 0; j__memset(&v15, 0, 0x3FFu); sub_42D267((int)&String, 1024, (int)&v16); // BASE64解码,里头有反调试 v13[0] = 0; j__memset(&v13[1], 0, 0x3FFu); sub_42D267((int)&v16, 1024, (int)&v14); // BASE64解码,里头有反调试 sub_42D96A(&v14, (int)v13, 1024); // 0x20 set,里头有反调试 v12 = 3; sub_42DA78(&v14, 3u, (int)v11); // 国密SM3,仅加密前3字节,里头有反调试 for ( i = 0; i < 32; ++i ) j__sprintf(&hash[2 * i], "%02x", v11[i]); v4 = j__strlen(hash); v5 = &String + j__strlen(&String); v6 = j__strlen(hash); if ( !j__memcmp(hash, &v5[-v6], v4) ) // hash64字节对比和输入的右侧64字节(不足留0x0) { sub_42D0B4(); if ( sub_42D9AB((int)&unk_49B000, (int)v13) == 1 )// 0x20 check,里头有反调试 MessageBoxA(0, "ok", "CrackMe", 0); }
二、反调试:
该作品反调试种类繁多,常见的都有了,估计很多人会罗列出来详细阐述,太占篇幅我就不必要复制粘贴了,只要把CALL反调试子程序修改RET返回即可绕过。
这里仅罗列我实际为了调试所patch掉的地址和代码:(不保证齐全)⑴: 对输入的注册码(≥64位)进行2次Base64解码,解码错误可能使输出结果为空;
⑵: 根据
Base64 解码结果设置标志0x20(2次Base64解码后包含0x2f);
⑶: 使用国密SM3对2次Base64解码后的前3字节进行加密,并转为64位字符串;
⑷: SM3加密结果64位字符与输入的注册码右边64位字符比较(关键跳1);
⑸: 对标志0x20
(2次Base64解码后包含0x2f)比较,含BUG(关键跳2)。
①:如果不是算法包含BUG,正常的解题思路是:
⑵: 对64位SM3进行2次 Base64解码 ,要求解码后的前3字节与穷举的3字节吻合,并且解码结果包含“0x2f”即可将64位作为正确答案。
但本题算法包含BUG,首先Base64对64位SM3结果进行2次解码后,很有可能输出空白结果,前3字节容易构造“0x00”或“0x2f”;
其次“0x20”标志不一定可靠,即算法第 ⑵ 步解码结果未包含0x2f,未设置0x20标志位,最后第 ⑸ 步也有很大概率验证通过(具体BUG原因未继续细查,估计是检测地址范围过大,内存状态每次运行都会有所变化,也有其他原因可能导致该BUG)。
② :综上所述,我们可以随意选择一种方法进行破解
⑴ :比如构造 Base64的2次解码输出3字节“0x00,0x00,0x00”,得到SM3:“183920f00e15a0433ee3a8fc90dd9ac164c4142ccf63ca189a8f645ec96ff8de”,输入该64位字符有很大可能通过验证,因2次Base64解码未包含“0x2f”没有设置“0x20”标志位,所以通过验证靠运气,有时不行,但按比赛规则有一次通过就算题目被破解。
⑵: 再比如,我们还可以构造2次Base64解码输出“0x2f”结果的 -->1次Base64加密 “Lw==” --> 2次Base64加密“THc9PQo”,把 “THc9PQo”输入Crackme观察SM3加密结果为“2f725aaf8d9fa538554e9f3589ddc785364d52ab1a6760c12caa2ec01ae4ba9e”,也就是“0x2f,0x00,0x00”这3个字节的SM3加密结果(可以自己写代码或者利用算法工具验证), “2f725aaf8d9fa538554e9f3589ddc785364d52ab1a6760c12caa2ec01ae4ba9e” 在本题中的2次Base64解码为空,因此在其前面连接 “THc9PQo” 即可:
THc9PQo2f725aaf8d9fa538554e9f3589ddc785364d52ab1a6760c12caa2ec01ae4ba9e
类似的构造方法太多了,答案数不胜数。
五、总结:
本题利用大量反调试手段抵抗破解,采用密码学算法增加强度,但结果也是戏剧化的。
[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法
赞赏
他的文章
看原图