PEID查壳,无壳,KANAL检测算法找不到任何线索(估计是作者自己写的算法)。查找输入表函数,找到GetDlgItemTextA,我们来试一下作者是不是利用这个函数来获得用户输入的字符串。在函数的第一个参数(PUSH ***)处下断,输入:ID:xxfire PW:12345678来到这里。
0040117E |. 68 C9000000 PUSH 0C9 ; /Count = C9 (201.)
00401183 |. 50 PUSH EAX ; |Buffer
00401184 |. 68 E8030000 PUSH 3E8 ; |ControlID = 3E8 (1000.)
00401189 |. 57 PUSH EDI ; |hWnd
0040118A |. FFD5 CALL EBP ; \GetDlgItemTextA
0040118C |. 8BF0 MOV ESI,EAX
0040118E |. 83FE 04 CMP ESI,4 ; 用户名小于4位则完蛋
00401191 |. 0F8C CA000000 JL CrackMe_.00401261
00401197 |. 8BCE MOV ECX,ESI
00401199 |. 81E1 01000080 AND ECX,80000001
0040119F |. 79 05 JNS SHORT CrackMe_.004011A6 ; 比较用户名位数的奇偶性
004011A1 |. 49 DEC ECX
004011A2 |. 83C9 FE OR ECX,FFFFFFFE
004011A5 |. 41 INC ECX
004011A6 |> 0F85 B5000000 JNZ CrackMe_.00401261
004011AC |. 8D9424 D80000>LEA EDX,DWORD PTR SS:[ESP+D8]
004011B3 |. 56 PUSH ESI
004011B4 |. 52 PUSH EDX
004011B5 |. E8 B6000000 CALL CrackMe_.00401270 ; 小写转大写
004011BA |. 83C4 08 ADD ESP,8 ; 堆栈平衡
004011BD |. 85C0 TEST EAX,EAX ; EAX=0则完蛋
004011BF |. 0F84 9C000000 JE CrackMe_.00401261
经核实缓冲区的内容是我们刚输入的xxfire(数据窗口跟随buffer),
我们跟进第一个关键CALL:CALL CrackMe_.00401270:
00401270 /$ 53 PUSH EBX
00401271 |. 8B5C24 0C MOV EBX,DWORD PTR SS:[ESP+C]
00401275 |. 56 PUSH ESI
00401276 |. 33F6 XOR ESI,ESI
00401278 |. 85DB TEST EBX,EBX
0040127A |. 57 PUSH EDI
0040127B |. 7E 4D JLE SHORT CrackMe_.004012CA
0040127D |. 8B7C24 10 MOV EDI,DWORD PTR SS:[ESP+10]
00401281 |> 833D E0624000>/CMP DWORD PTR DS:[4062E0],1
00401288 |. 7E 14 |JLE SHORT CrackMe_.0040129E
0040128A |. 0FBE043E |MOVSX EAX,BYTE PTR DS:[ESI+EDI]
0040128E |. 68 03010000 |PUSH 103
00401293 |. 50 |PUSH EAX
00401294 |. E8 13010000 |CALL CrackMe_.004013AC
00401299 |. 83C4 08 |ADD ESP,8
0040129C |. EB 13 |JMP SHORT CrackMe_.004012B1
0040129E |> 0FBE0C3E |MOVSX ECX,BYTE PTR DS:[ESI+EDI]
004012A2 |. 8B15 D4604000 |MOV EDX,DWORD PTR DS:[4060D4] ; CrackMe_.004060DE
004012A8 |. 66:8B044A |MOV AX,WORD PTR DS:[EDX+ECX*2]
004012AC |. 25 03010000 |AND EAX,103
004012B1 |> 85C0 |TEST EAX,EAX ; 这里重要:EAX=0则完蛋(经分析知道我们输入的用户名所有字符只能由大小写字母组成)
004012B3 |. 74 1E |JE SHORT CrackMe_.004012D3
004012B5 |. 0FBE043E |MOVSX EAX,BYTE PTR DS:[ESI+EDI]
004012B9 |. 50 |PUSH EAX
004012BA |. E8 21000000 |CALL CrackMe_.004012E0
004012BF |. 83C4 04 |ADD ESP,4
004012C2 |. 88043E |MOV BYTE PTR DS:[ESI+EDI],AL
004012C5 |. 46 |INC ESI
004012C6 |. 3BF3 |CMP ESI,EBX
004012C8 |.^ 7C B7 \JL SHORT CrackMe_.00401281
004012CA |> 5F POP EDI
004012CB |. 5E POP ESI
004012CC |. B8 01000000 MOV EAX,1
004012D1 |. 5B POP EBX
004012D2 |. C3 RETN
004012D3 |> 5F POP EDI
004012D4 |. 5E POP ESI
004012D5 |. 33C0 XOR EAX,EAX
004012D7 |. 5B POP EBX
004012D8 \. C3 RETN
现在我们回到CALL CrackMe_.00401270后面继续分析:
004011C5 |. 8D4424 10 LEA EAX,DWORD PTR SS:[ESP+10]
004011C9 |. 68 C9000000 PUSH 0C9
004011CE |. 50 PUSH EAX ; 序列号会储存到[ESP+10]地址里
004011CF |. 68 E9030000 PUSH 3E9
004011D4 |. 57 PUSH EDI
004011D5 |. FFD5 CALL EBP ; CALL GetDlgItemTextA(获得序列号)
004011D7 |. 3BC6 CMP EAX,ESI ; 比较用户名和序列号的位数
004011D9 |. 0F85 82000000 JNZ CrackMe_.00401261 ; 不相等则完蛋
由于我们先前输入的用户名和序列号位数不等,所以会直接GAME OVER,此时我们可以修改一下跳转指令继续分析,但担心会影响到后面的算法,于是我们重新跟踪程序。这次我们输入ID:xxfire PW:123456,来到JNZ指令的下面:
004011E3 |. 50 PUSH EAX ; 序列号的位数入栈
004011E4 |. 51 PUSH ECX ; 序列号入栈
004011E5 |. E8 86000000 CALL CrackMe_.00401270
跟到这里我想自杀!为什么?因为我发现这个CALL就是前面我们跟的那个CALL(小写转大写),也就是说我们的序列号也必须是由大小写字母组成,否则GAME OVER。也就是说我这次输入的序列号又不行,继续重来!!!:(
这次我们输入ID:xxfire PW:qwerty,来到004011E5 |. E8 86000000 CALL CrackMe_.00401270的下面,此时用户名和序列号都已经转换成了大写字母(ID:XXFIRE PW:QWERTY)
004011EA |. 83C4 08 ADD ESP,8
004011ED |. 85C0 TEST EAX,EAX
004011EF |. 74 70 JE SHORT CrackMe_.00401261
004011F1 |. 8BC6 MOV EAX,ESI
004011F3 |. 33FF XOR EDI,EDI
004011F5 |. 99 CDQ ; 把EAX的最高位扩展到EDX
004011F6 |. 2BC2 SUB EAX,EDX ; EDX在这里只可能=0,所以结果还是用户名(或序列号的位数)
004011F8 |. 8BE8 MOV EBP,EAX
004011FA |. D1FD SAR EBP,1 ; 用户名(或序列号)的位数除以2
004011FC |. 3BEB CMP EBP,EBX ; EBX始终为0,所以EBP不可能=EBX
004011FE |. 7E 51 JLE SHORT CrackMe_.00401251 ; 根本就不可能直接跳向成功!!!
00401200 |> 8A4C7C 11 /MOV CL,BYTE PTR SS:[ESP+EDI*2+11] ; 序列号(大写)的第2个字符放在CL
00401204 |. 8A447C 10 |MOV AL,BYTE PTR SS:[ESP+EDI*2+10] ; 序列号(大写)的第1个字符放在CL
00401208 |. 80E9 41 |SUB CL,41 ; 减41(A)
0040120B |. 2C 41 |SUB AL,41 ; 同上
0040120D |. 0FBEF1 |MOVSX ESI,CL ; CL传到ESI,并且符号位扩展
00401210 |. 0FBEC8 |MOVSX ECX,AL ; 同上
00401213 |. BB 1A000000 |MOV EBX,1A ; EBX=1A
00401218 |. 8D14C9 |LEA EDX,DWORD PTR DS:[ECX+ECX*8]
0040121B |. 8D0472 |LEA EAX,DWORD PTR DS:[EDX+ESI*2] ; [(序列号的第2位-41)*2+序列号的第1位*9]的值放在EAX里(不知道是什么含义)
0040121E |. 99 |CDQ
0040121F |. F7FB |IDIV EBX ; EAX除以1A,余数放在EDX里
00401221 |. 0FBE847C D800>|MOVSX EAX,BYTE PTR SS:[ESP+EDI*2+D8] ; 用户名的第一位符号扩展传到EAX
00401229 |. 83E8 41 |SUB EAX,41 ; 用户名的第一位-41
0040122C |. 3BD0 |CMP EDX,EAX
0040122E |. 75 31 |JNZ SHORT CrackMe_.00401261 ; 不等则完蛋
为了能继续分析下去,我们将此处的JNZ临时改成JE,
0040122E /74 31 JE SHORT CrackMe_.00401261 ; 不等则完蛋(临时将JNZ修改成JE)
00401230 |. |8D0476 |LEA EAX,DWORD PTR DS:[ESI+ESI*2]
00401233 |. |8D0C81 |LEA ECX,DWORD PTR DS:[ECX+EAX*4]
00401236 |. |03C1 |ADD EAX,ECX
00401238 |. |8BCB |MOV ECX,EBX
0040123A |. |99 |CDQ
0040123B |. |F7F9 |IDIV ECX
0040123D |. |0FBE847C D900>|MOVSX EAX,BYTE PTR SS:[ESP+EDI*2+D9]
00401245 |. |83E8 41 |SUB EAX,41
00401248 |. |3BD0 |CMP EDX,EAX
0040124A |. |75 15 |JNZ SHORT CrackMe_.00401261
0040124C |. |47 |INC EDI
0040124D |. |3BFD |CMP EDI,EBP
0040124F |.^|7C AF \JL SHORT CrackMe_.00401200
这一段的算法同上一段一样!依次进行运算。接下来就快结束本次分析了,请大家再坚持最后一会儿。
00401251 |> \5F POP EDI
00401252 |. 5E POP ESI
00401253 |. 5D POP EBP
00401254 |. B8 01000000 MOV EAX,1
00401259 |. 5B POP EBX
0040125A |. 81C4 90010000 ADD ESP,190
00401260 |. C3 RETN
00401261 |> 5F POP EDI
00401262 |. 5E POP ESI
00401263 |. 5D POP EBP
00401264 |. 33C0 XOR EAX,EAX
00401266 |. 5B POP EBX
00401267 |. 81C4 90010000 ADD ESP,190
0040126D \. C3 RETN
EAX=1返回的时候就会弹出注册成功的消息框,否则没任何反应!
总结:注册机可以根据后面这两小段的反汇编指令写出相应的汇编指令即可!谢谢!!
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课