-
-
CrackMe第四题分析记录
-
发表于: 2016-11-9 22:52 2832
-
--- 以下仅为个人见解
公式:
题目使用了虚拟机,如果不是对虚拟机本身的安全性感兴趣的话可以只寻找虚拟机的关键点,主要包括普通代码段对虚拟机内部的调用边界,还有就是虚拟机的出口(VMEXIT);
这里只表述虚拟机的出口处:
1. 进入虚拟机, 这个比较简单,主程序中GetDlgItemTextA断点就可返回到
40149E为返回结果判断,从00401499进入,直到Jmp:
然后来到虚拟机入口:
取码分发:
有兴趣的可以看一下Handler表,但重点不在此,此时略。
2. 跟踪Handler,定位VM_EIP查看字节码内存,粗略定位:
本程序字节码即VM_EIP由esi指定,上面的红色指令已经给出。同时字节码倒序取出执行(走一下就能看到),见下图:
图略。
在内存中查看VM_EIP执行的数据块:
接着往上看,直到出现一段内存为0为止... ... ...
红色数据断点,运行,会断在取码处,往前走走,就到了虚拟机退出位置。
再跟下去,就返回了壳外代码。
在本题目里,此后就没虚拟机什么事情了
3. 出入虚拟机
每次都从虚拟机出来进行跟踪,此时需要对栈上数据留意下,配合预先用PEID对对程序扫描的结果,会先进行md5的计算,个人分别定位出Md5Update, Md5Final, 但可不必纠结这个,因为只要可以在后续遇到字节流是可以确定那个是由MD5生成即可,但要关注下取了注册码的多少个字节进行的md5,不过这是在栈中可以看到的。
4. 后来
后续就来到了对注册码的主要操作阶段,包括对30个字节码后续23字节的处理,一些异或的过程,由于这些过程是没有被虚拟化的,简单带过,数据为主:
以上两组数据在以下代码中---拷贝,其上方就是公式中表现的一些异或操作(略):
接着后面就是迷宫操作,该判断来自于一下代码片段:
起初是不太清楚是推箱子还是迷宫,只能判断是个16*16的,,,推迷宫了,,,但后来把这上上下下的几片代码摆在一起就清晰了,从这么大的数据栈看来,作者有可能是为了能充分的减少边界而都堆在一个函数里面的,也有可能偷懒,再或者... 毕竟作者才是作者...
5. 谜底
继续看下去就都明了了,如下:
这里面有对两个数组的使用,对数值的比较,紫色为爆破参考点。唯一缺少的就是复原下两个数组的关系了,写段程序,按照上面的处理方式,于是柳暗花明。
如图:
看到了这个图(把部分数据过滤掉了),云雾彻底揭开,可在写出路径的前,需要根据一段不曾提及的代码来确定路径编码规则:
程序中对每个字节分四段来处理判断,所以规则就是...
所以路径就是...
6. 穷举
得到路径后根据公式,MD5穷举,刚开始还残了一下,想要随机碰撞,,,但还是,,,穷举好点
代码片段:
[/CODE]
[/CODE]
[/CODE]
[/CODE]
[/CODE]
[/CODE]
配合脑补,七层代码七层循环... 原本放在几个线程里分段算,,,结果发现没那么慢...
测试成功,如图:
最后配上一张视力表:
土陋了哈...
.End
公式:
(Md5(sn.sub(0, 7)) + Md5(sn.sub(0, 7)).sub(0,7)) ^ ConstArray ^ sn.sub(7, 23) = XArray unsigned char ConstArray[23] = { 0x44, 0xAD, 0x5C, 0xCC, 0x12, 0x90, 0x73, 0x8D, 0x47, 0x81, 0xE3, 0x89, 0x84, 0x9C, 0xDF, 0xF9, 0x47, 0x6A, 0xB6, 0x9E, 0x11, 0x30, 0x27 }; XArray 需要后续分析,为迷宫路线 sn最后由穷举产生,不唯一
题目使用了虚拟机,如果不是对虚拟机本身的安全性感兴趣的话可以只寻找虚拟机的关键点,主要包括普通代码段对虚拟机内部的调用边界,还有就是虚拟机的出口(VMEXIT);
这里只表述虚拟机的出口处:
1. 进入虚拟机, 这个比较简单,主程序中GetDlgItemTextA断点就可返回到
00401491 |. 8BD0 MOV EDX,EAX 00401493 |. 8D8D FCFDFFFF LEA ECX,DWORD PTR SS:[EBP-204] 00401499 |. E8 62FBFFFF CALL CrackMe.00401000 0040149E |. 83F8 01 CMP EAX,1
40149E为返回结果判断,从00401499进入,直到Jmp:
004010B0 . 0FB647 06 MOVZX EAX,BYTE PTR DS:[EDI+6] 004010B4 . 8845 96 MOV BYTE PTR SS:[EBP-6A],AL 004010B7 . E9 7CDF0200 JMP CrackMe.0042F038 004010BC 00 DB 00 004010BD 00 DB 00
然后来到虚拟机入口:
0042F052 8BFC MOV EDI,ESP [COLOR="Red"]0042F054 BE 0E544300 MOV ESI,CrackMe.0043540E[/COLOR] 0042F059 E9 7B0C0000 JMP CrackMe.0042FCD9 0042F05E 0000 ADD BYTE PTR DS:[EAX],AL 0042F060 0000 ADD BYTE PTR DS:[EAX],AL
取码分发:
0042FCDB 4B DEC EBX 0042FCDC 66:F7D3 NOT BX 0042FCDF 66:81EB D165 SUB BX,65D1 0042FCE4 0FB646 FF MOVZX EAX,BYTE PTR DS:[ESI-1] 0042FCE8 4E DEC ESI 0042FCE9 2AC3 SUB AL,BL 0042FCEB F6D0 NOT AL 0042FCED 04 57 ADD AL,57 0042FCEF FEC8 DEC AL 0042FCF1 2C 3E SUB AL,3E 0042FCF3 FF3485 DDF84200 PUSH DWORD PTR DS:[EAX*4+42F8DD] 0042FCFA C3 RETN
有兴趣的可以看一下Handler表,但重点不在此,此时略。
2. 跟踪Handler,定位VM_EIP查看字节码内存,粗略定位:
本程序字节码即VM_EIP由esi指定,上面的红色指令已经给出。同时字节码倒序取出执行(走一下就能看到),见下图:
图略。
在内存中查看VM_EIP执行的数据块:
0043539E B6 ED 08 27 5A 7C A4 95 FE 0F 60 84 C2 1E 1C 77 俄'Z|?`劼w 004353AE 66 AC B8 E5 0A 3F 54 54 AE CD 10 47 72 DC CC 36 f??TTGr芴6 004353BE 16 6F 68 A4 BA FD 04 17 5E 8C C0 06 22 9F 7C F4 ohず?^尷"焲 004353CE C6 2E 18 67 6A BC B4 D5 0E 4F 70 14 06 B9 EF 30 ?gj即?Op癸0 004353DE B4 49 1F 27 56 79 30 E6 B3 14 3E C0 79 ED 6E 24 碔'Vy0娉>纘韓$ 004353EE 01 5F 50 17 44 18 05 50 19 89 23 CA 06 1E 5C EE _PDP??\ 004353FE 20 42 08 A2 0C 7E 28 75 24 04 3C 19 18 77 00 AB B?~(u$<w. 0043540E 00 .
接着往上看,直到出现一段内存为0为止... ... ...
0043025E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0043026E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0043027E 00 [COLOR="red"]86[/COLOR] E4 F2 5E 4C 24 96 8D E8 66 3A 2F 84 C3 DE .嗕騘L$枍鑖:/劽 0043028E 8E 40 A8 53 F4 8C A4 8A D2 9B F3 6F 2C 50 AD 50 嶡⊿魧覜髈,P璓 0043029E 94 0D DC 20 EE 62 25 67 42 FD EA F0 B5 48 79 86 ??頱%gB鸬Hy
红色数据断点,运行,会断在取码处,往前走走,就到了虚拟机退出位置。
0042F76F 8BE5 MOV ESP,EBP 0042F771 5F POP EDI 0042F772 5E POP ESI 0042F773 5D POP EBP 0042F774 5B POP EBX 0042F775 5A POP EDX 0042F776 59 POP ECX 0042F777 58 POP EAX 0042F778 9D POPFD 0042F779 C3 RETN 0042F77A F6D3 NOT BL 0042F77C 8A46 FF MOV AL,BYTE PTR DS:[ESI-1]
再跟下去,就返回了壳外代码。
在本题目里,此后就没虚拟机什么事情了
3. 出入虚拟机
每次都从虚拟机出来进行跟踪,此时需要对栈上数据留意下,配合预先用PEID对对程序扫描的结果,会先进行md5的计算,个人分别定位出Md5Update, Md5Final, 但可不必纠结这个,因为只要可以在后续遇到字节流是可以确定那个是由MD5生成即可,但要关注下取了注册码的多少个字节进行的md5,不过这是在栈中可以看到的。
4. 后来
后续就来到了对注册码的主要操作阶段,包括对30个字节码后续23字节的处理,一些异或的过程,由于这些过程是没有被虚拟化的,简单带过,数据为主:
// unsigned char data1[256] = { 0x6E, 0xD4, 0x1B, 0x69, 0x5F, 0x4E, 0xE8, 0xAA, 0x95, 0xF6, 0xAF, 0xCE, 0x32, 0x1A, 0x62, 0xD9, 0x02, 0x18, 0x74, 0x95, 0x1F, 0xC2, 0x4D, 0x33, 0x3C, 0xF0, 0x3B, 0xEC, 0xE9, 0x81, 0x4B, 0x9C, 0x0F, 0x47, 0x5C, 0xAD, 0xD9, 0x09, 0xB0, 0x87, 0x53, 0x9B, 0xF2, 0xE3, 0x0F, 0x01, 0x92, 0x8D, 0xC2, 0xF5, 0x0C, 0xDD, 0x42, 0xCC, 0xAF, 0xB4, 0xD5, 0xE4, 0x86, 0xD3, 0x9A, 0x0B, 0x62, 0x63, 0xA7, 0xD4, 0x1B, 0x69, 0x5F, 0x4E, 0xE8, 0xAA, 0x95, 0xF6, 0xAF, 0xCE, 0x32, 0x1A, 0x62, 0xD9, 0x02, 0x18, 0x74, 0x95, 0x1F, 0xC2, 0x4D, 0x33, 0x38, 0xF0, 0x3B, 0xEC, 0xED, 0x81, 0x4B, 0x9C, 0x0B, 0x47, 0x5C, 0xAD, 0xDD, 0x09, 0xB0, 0x87, 0x57, 0x9B, 0xF2, 0xE3, 0x0B, 0x01, 0x92, 0x8D, 0xC2, 0xF5, 0x0C, 0xDD, 0x42, 0xCC, 0xAF, 0xB4, 0xD5, 0xE4, 0x86, 0xD3, 0x9A, 0x0B, 0x62, 0x63, 0xA7, 0xD4, 0x1B, 0x69, 0x5F, 0x4E, 0xE8, 0xAA, 0x95, 0xF6, 0xAF, 0xCE, 0x32, 0x1A, 0x62, 0xD9, 0x02, 0x18, 0x74, 0x95, 0x1F, 0xC2, 0x4D, 0x33, 0x38, 0xF0, 0x3B, 0xEC, 0xE9, 0x81, 0x4B, 0x9C, 0x0F, 0x47, 0x5C, 0xAD, 0xD9, 0x09, 0xB0, 0x87, 0x53, 0x9B, 0xF2, 0xE3, 0x0F, 0x01, 0x92, 0x8D, 0xC2, 0xF5, 0x0C, 0xDD, 0x42, 0xCC, 0xAF, 0xB4, 0xD5, 0xE4, 0x86, 0xD3, 0x9A, 0x0B, 0x62, 0x63, 0xA7, 0xD4, 0x1B, 0x69, 0x5B, 0x4E, 0xE8, 0xAA, 0x91, 0xF6, 0xAF, 0xCE, 0x36, 0x1A, 0x62, 0xD9, 0x02, 0x18, 0x74, 0x95, 0x1F, 0xC2, 0x4D, 0x33, 0x38, 0xF0, 0x3B, 0xEC, 0xE9, 0x81, 0x4B, 0x9C, 0x0B, 0x47, 0x5C, 0xAD, 0xDD, 0x09, 0xB0, 0x87, 0x57, 0x9B, 0xF2, 0xE3, 0x0B, 0x01, 0x92, 0x8D, 0xC6, 0xF5, 0x0C, 0xDD, 0x42, 0xCC, 0xAF, 0xB4, 0xD5, 0xE4, 0x86, 0xD3, 0x9A, 0x0B, 0x62, 0x63 }; // unsigned char data2[256] = { 0xD8, 0x05, 0xF6, 0x6A, 0xE7, 0xA2, 0x0B, 0x9B, 0x54, 0x8C, 0xDA, 0x82, 0xBD, 0xB6, 0xA8, 0x46, 0xB1, 0x36, 0x2D, 0x55, 0xF7, 0x81, 0x63, 0xFC, 0x3F, 0x0C, 0xFE, 0x0B, 0x4B, 0x50, 0xE2, 0x17, 0xF2, 0xE1, 0x27, 0x5B, 0x46, 0x73, 0x1C, 0xD0, 0xE5, 0xD7, 0x8D, 0xC9, 0xF2, 0x70, 0x94, 0x53, 0x81, 0x4C, 0x32, 0x46, 0xA0, 0x02, 0xDB, 0x1C, 0x45, 0x09, 0x91, 0xC4, 0x96, 0xF2, 0xA8, 0xE8, 0xD9, 0x05, 0xF6, 0x6B, 0xE7, 0xA2, 0x0A, 0x9B, 0x54, 0x8C, 0xDA, 0x82, 0xBD, 0xB7, 0xA9, 0x46, 0xB0, 0x36, 0x2D, 0x54, 0xF7, 0x81, 0x63, 0xFC, 0x3E, 0x0C, 0xFE, 0x0B, 0x4B, 0x50, 0xE3, 0x17, 0xF2, 0xE0, 0x26, 0x5A, 0x47, 0x73, 0x1C, 0xD1, 0xE5, 0xD6, 0x8C, 0xC8, 0xF2, 0x70, 0x95, 0x53, 0x80, 0x4C, 0x33, 0x47, 0xA0, 0x02, 0xDB, 0x1C, 0x44, 0x08, 0x91, 0xC4, 0x96, 0xF2, 0xA9, 0xE8, 0xD9, 0x04, 0xF6, 0x6A, 0xE7, 0xA2, 0x0A, 0x9B, 0x55, 0x8C, 0xDB, 0x83, 0xBC, 0xB6, 0xA9, 0x46, 0xB0, 0x37, 0x2D, 0x55, 0xF7, 0x81, 0x63, 0xFD, 0x3E, 0x0D, 0xFE, 0x0B, 0x4A, 0x50, 0xE3, 0x17, 0xF3, 0xE0, 0x27, 0x5B, 0x46, 0x73, 0x1D, 0xD0, 0xE4, 0xD7, 0x8C, 0xC8, 0xF3, 0x70, 0x95, 0x53, 0x80, 0x4C, 0x33, 0x47, 0xA0, 0x03, 0xDB, 0x1D, 0x45, 0x08, 0x91, 0xC4, 0x96, 0xF2, 0xA9, 0xE8, 0xD9, 0x04, 0xF6, 0x6A, 0xE6, 0xA3, 0x0A, 0x9A, 0x54, 0x8C, 0xDB, 0x82, 0xBC, 0xB7, 0xA9, 0x46, 0xB0, 0x37, 0x2C, 0x54, 0xF6, 0x81, 0x62, 0xFD, 0x3E, 0x0D, 0xFE, 0x0A, 0x4A, 0x50, 0xE2, 0x17, 0xF2, 0xE1, 0x27, 0x5B, 0x47, 0x72, 0x1C, 0xD0, 0xE5, 0xD7, 0x8C, 0xC9, 0xF2, 0x70, 0x94, 0x53, 0x81, 0x4D, 0x33, 0x47, 0xA0, 0x03, 0xDB, 0x1C, 0x44, 0x08, 0x91, 0xC5, 0x97, 0x9A, 0xA8, 0xE8 };
以上两组数据在以下代码中---拷贝,其上方就是公式中表现的一些异或操作(略):
... XOR ... ... XOR... ... ... ... 004011F1 B9 40000000 MOV ECX,40 004011F6 8DBD 90FCFFFF LEA EDI,DWORD PTR SS:[EBP-370] 004011FC BE 98374100 MOV ESI,CrackMe.00413798 00401201 33C0 XOR EAX,EAX 00401203 F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS> 00401205 B9 40000000 MOV ECX,40 0040120A 8985 30FCFFFF MOV DWORD PTR SS:[EBP-3D0],EAX 00401210 BE 98384100 MOV ESI,CrackMe.00413898 00401215 8DBD 90FEFFFF LEA EDI,DWORD PTR SS:[EBP-170] 0040121B F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS> 0040121D 33C9 XOR ECX,ECX 0040121F 898D 2CFCFFFF MOV DWORD PTR SS:[EBP-3D4],ECX
接着后面就是迷宫操作,该判断来自于一下代码片段:
00401248 8A8D 0CFCFFFF MOV CL,BYTE PTR SS:[EBP-3F4] 0040124E D3EA SHR EDX,CL 00401250 83E2 03 AND EDX,3 00401253 FF2495 0C144000 JMP DWORD PTR DS:[EDX*4+40140C] 0040125A 83E8 10 SUB EAX,10 0040125D EB 09 JMP SHORT CrackMe.00401268 0040125F 40 INC EAX 00401260 EB 06 JMP SHORT CrackMe.00401268 00401262 83C0 10 ADD EAX,10 00401265 EB 01 JMP SHORT CrackMe.00401268 00401267 48 DEC EAX 00401268 8985 30FCFFFF MOV DWORD PTR SS:[EBP-3D0],EAX
起初是不太清楚是推箱子还是迷宫,只能判断是个16*16的,,,推迷宫了,,,但后来把这上上下下的几片代码摆在一起就清晰了,从这么大的数据栈看来,作者有可能是为了能充分的减少边界而都堆在一个函数里面的,也有可能偷懒,再或者... 毕竟作者才是作者...
5. 谜底
继续看下去就都明了了,如下:
004012CE 8995 04FCFFFF MOV DWORD PTR SS:[EBP-3FC],EDX 004012D4 8A8C05 90FCFFFF MOV CL,BYTE PTR SS:[EBP+EAX-370] 004012DB 8AC1 MOV AL,CL 004012DD 888D 37FCFFFF MOV BYTE PTR SS:[EBP-3C9],CL [COLOR="red"]004012E3 C0C8 02 ROR AL,2[/COLOR] 004012E6 0FB6C8 MOVZX ECX,AL 004012E9 0FB602 MOVZX EAX,BYTE PTR DS:[EDX] 004012EC 33C8 XOR ECX,EAX [COLOR="red"]004012EE 83F9 30 CMP ECX,30[/COLOR] 004012F1 0F84 E2000000 JE CrackMe.004013D9 [COLOR="red"]004012F7 83F9 20 CMP ECX,20[/COLOR] 004012FA 0F84 D9000000 JE CrackMe.004013D9 [COLOR="red"]00401300 83F9 58 CMP ECX,58[/COLOR] 00401303 0F84 E5000000 [COLOR="DarkOrchid"] JE CrackMe.004013EE[/COLOR] 00401309 8B8D 10FCFFFF MOV ECX,DWORD PTR SS:[EBP-3F0] 0040130F 8BC1 MOV EAX,ECX 00401311 99 CDQ 00401312 83E2 0F AND EDX,0F 00401315 03C2 ADD EAX,EDX 00401317 C1F8 04 SAR EAX,4 0040131A 8985 08FCFFFF MOV DWORD PTR SS:[EBP-3F8],EAX
这里面有对两个数组的使用,对数值的比较,紫色为爆破参考点。唯一缺少的就是复原下两个数组的关系了,写段程序,按照上面的处理方式,于是柳暗花明。
for (int i = 0; i < 256; i++) { unsigned char tmp = ((data1[i] >> 2) | ((data1[i]) & 0x00000003) << 6); printf("%d[%02x] = %02x - %d\n", i, tmp, tmp ^ data2[i], tmp ^ data2[i]); mig[i] = tmp^data2[i]; }
如图:
4330303030 303030 30303030 303030303030 303030 30303030 30 303030 30 30 3030303030303030 303030 30 30 30 303030 30 3030303030303030 30 30 30 3030303030303030 30 30 303030 30 30303030 30 30 303030 30 30 30303030 30 30 303030 30 30 30303030 30 30 303030 30 30303030 30 30 30303030303030 30303030 30 30 30303030303030 30 30 30 30 30 30303030 30303030303030 30 30 30303030 30303030303030 30 583030
看到了这个图(把部分数据过滤掉了),云雾彻底揭开,可在写出路径的前,需要根据一段不曾提及的代码来确定路径编码规则:
0040122C C785 0CFCFFFF 0>MOV DWORD PTR SS:[EBP-3F4],6
程序中对每个字节分四段来处理判断,所以规则就是...
所以路径就是...
unsigned char path[23] = { 0xa9, 0x5a, 0xbe, 0xaa, 0xa5, 0x55, 0xa5, 0x00, 0x00, 0xfa, 0xbc, 0x00, 0x00, 0x15, 0x55, 0xaf, 0xfe, 0x95, 0x55, 0xaa, 0xaa, 0xfe, 0xa5 };
6. 穷举
得到路径后根据公式,MD5穷举,刚开始还残了一下,想要随机碰撞,,,但还是,,,穷举好点
代码片段:
[CODE] [CODE] [CODE] [CODE] [CODE] [CODE] testt[0] = enumt[x1]; testt[1] = enumt[x2]; testt[2] = enumt[x3]; testt[3] = enumt[x4]; testt[4] = enumt[x5]; testt[5] = enumt[x6]; testt[6] = enumt[x7]; MD5_CTX ctx = { 0 }; MD5Init(&ctx); MD5Update(&ctx, testt, 7); MD5Final(&ctx); memcpy(tmp, ctx.digest, 16); memcpy(tmp + 16, ctx.digest, 7); unsigned char tmp2[28] = { 0 }; for (int i = 0; i < 23; i++) { tmp2[i] = tmp[i] ^ destv[i]; } int ok = 1; for (int i = 0; i < 23; i++) { if (tmp2[i] < '0' || (tmp2[i] > '9'&& tmp2[i] < 'A') || (tmp2[i] > 'Z' &&tmp2[i] < 'a') || (tmp2[i] > 'z')) { ok = 0; break; } } if (ok == 0) { continue; } printf("ok: try use this: %s - %s \n", testt, tmp2); break;
[/CODE]
[/CODE]
[/CODE]
[/CODE]
[/CODE]
[/CODE]
配合脑补,七层代码七层循环... 原本放在几个线程里分段算,,,结果发现没那么慢...
ok: try use this: 007RiQS - vXasVB,)o7g_2;g!"P`!ZIx ok: try use this: 00a4YwD - f'ypKMq+Y^so]eKM2/x"GF%
测试成功,如图:
--------------------------- information --------------------------- 注册成功:) --------------------------- 确定 ---------------------------
最后配上一张视力表:
土陋了哈...
.End
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
赞赏
谁下载
看原图
赞赏
雪币:
留言: