vecri 发表于 2007-12-24 19:44:34

aCaFeeL's CrackMe V5(前传版)算法分析 + 注册机(附件)

【破文标题】破解aCaFeeL's CrackMe V5(前传版)
【破文作者】vecri
【作者邮箱】qj_20031@163.com
【作者主页】
【破解工具】OD
【破解平台】Windows XP
【软件名称】aCaFeeL's CrackMe V5(前传版) ->
【软件大小】
【原版下载】https://www.chinapyg.com/viewthread.php?tid=22489&extra=page%3D1
【保护方式】反调试+序列号
【软件简介】
【破解声明】菜鸟一个..偶有所得~
------------------------------------------------------------------------
【破解过程】一:首先是这个CrackMe的反调试分析: 包括窗口查找. 和 CRC
在打开这个CrackMe后, 再开OD, OD会自动关闭, 由此可以知道是WM_TIMER搞的鬼, bpx *看看有什么可疑的函数, 没有看到CreateToolHelpSnap32(),ProcessFirst32()以及ProcessNext32(), 就找到一个
FindWindow, 试试是不是这个.
下断: bp FindWindow
中断下, 返回用户领空, 看代码:
0040EAF2|.50            PUSH EAX                                 ; |Class = "OllyDBG"
0040EAF3|.E8 8C57FFFF   CALL <JMP.&user32.FindWindowA>         ; \FindWindowA
0040EAF8|.8BF0          MOV ESI,EAX
0040EAFA|.85F6          TEST ESI,ESI
0040EAFC      74 2A         JE SHORT keygenme.0040EB28
0040EAFE|>BB E01E0000   /MOV EBX,1EE0
0040EB03|>6A 00         |/PUSH 0                                 ; /lParam = 0
0040EB05|.6A 00         ||PUSH 0                                 ; |wParam = 0
0040EB07|.6A 10         ||PUSH 10                              ; |Message = WM_CLOSE
0040EB09|.56            ||PUSH ESI                               ; |hWnd
0040EB0A|.E8 9558FFFF   ||CALL <JMP.&user32.SendMessageA>      ; \SendMessageA
0040EB0F|.4B            ||DEC EBX
0040EB10|.^ 75 F1         |\JNZ SHORT keygenme.0040EB03

如果是窗口类是OllyDBG, 就发送WM_CLOSE消息, 于是把上面的判断JE SHORT keygenme.0040EB28
改成JNE SHORT keygenme.0040EB28, 另存为其他文件. 一运行发现文件被修改, 基本上判断是CRC校验的问题:


重新载入, 下断: CreateFileA, 断下, 返回用户领空:
0040EA60|.E8 4F3AFFFF   CALL keygenme.004024B4
0040EA65|.837D F8 00    CMP DWORD PTR SS:,0
0040EA69|.74 04         JE SHORT keygenme.0040EA6F   ;跳转就完蛋
0040EA6B|.33DB          XOR EBX,EBX
0040EA6D|.EB 02         JMP SHORT keygenme.0040EA71
0040EA6F|>B3 01         MOV BL,1
0040EA71|>33C0          XOR EAX,EAX

将上面的跳转取反, JE改为JNE, 然后把FindWindow处的跳转也改掉, 另存后运行, 通过~~~

可惜现在Validate按键不能按, 还是灰色的..接下来分析.


二:将Validate改为正常
bp CreateWindowExA, 断下, 看看右下角是哪个窗口, 到Validate的时候看看:
00406D5D   .8D4424 70   LEA EAX,DWORD PTR SS:
00406D61   .50            PUSH EAX                                 ; /pWndClass
00406D62   .E8 1DD6FFFF   CALL <JMP.&user32.RegisterClassA>      ; \RegisterClassA
00406D67   .85C0          TEST EAX,EAX
00406D69   .0F84 81000000 JE keygenme.00406DF0
00406D6F   >891D 14554100 MOV DWORD PTR DS:,EBX            ; |
00406D75   .E8 B2D4FFFF   CALL <JMP.&user32.CreateWindowExA>       ; \CreateWindowExA

此时右下角是:
0012FEE8   00010000|ExtStyle = WS_EX_CONTROLPARENT
0012FEEC   0012FF18|Class = "obj_BUTTON"
0012FEF0   00D91FA8|WindowName = "&Validate"
0012FEF4   4E00400B|Style = WS_CHILD|WS_CLIPSIBLINGS|WS_CLIPCHILDREN|WS_DISABLED|400B
0012FEF8   00000063|X = 63 (99.)
0012FEFC   000000CE|Y = CE (206.)
0012FF00   00000057|Width = 57 (87.)
0012FF04   00000014|Height = 14 (20.)
0012FF08   002A0236|hParent = 002A0236 ('keygenme',class='obj_Form')

将4E00400B改成正常的4600400B, 则按钮可按, 可是还是灰色~~真要命~

bpCallWindowProcA, bp SetColor, 右下角堆栈里注意看对应的消息, 在发给Validate按钮WM_PAINT后, 仔细看后面的SetColor调用,
都是为这个Button绘图的, 可以看到第二个SetColor参数为Gray, 所以我们只要写些补丁代码, 让颜色变为(8, 0, 0)就可以了


下面我把这两个地方的补丁代码给大家看一下, 补丁后的文件会传到附件里
在文件后的空白出添加两段补丁代码:
//第1段补丁代码
00410CB0   > \6A 08         PUSH 8      ;//这里是按钮上文字的颜色, (8, 0, 0)
00410CB2   .8B45 F8       MOV EAX,DWORD PTR SS:    ;//原来的两句代码
00410CB5   .8B40 18       MOV EAX,DWORD PTR DS:
00410CB8   .^ E9 5157FFFF   JMP keygenme.0040640E       //跳回原来的地方执行
00410CBD      90            NOP
00410CBE      00            DB 00
00410CBF      00            DB 00
//第2段补丁代码
00410CC0   >817B 34 0B400>CMP DWORD PTR DS:,4E00400B      //如果按钮风格为4E00400B(其中包含WS_DISABLED)
00410CC7   .75 07         JNZ SHORT keygenme.00410CD0
00410CC9   .C743 34 0B400>MOV DWORD PTR DS:,4600400B      //就改为4600400B(去掉了WS_DISABLED标志)
00410CD0   >FF73 34       PUSH DWORD PTR DS:      //原来的两句代码
00410CD3   .FFB3 89050000 PUSH DWORD PTR DS:
00410CD9   .^ E9 FB5FFFFF   JMP keygenme.00406CD9      //跳回原处执行

原文代码修改如下, 跳到补丁代码出执行:
00406407   . /E9 A4A80000   JMP keygenme.00410CB0       //跳到补丁处
0040640C   |90            NOP
0040640D   |90            NOP
0040640E   > |50            PUSH EAX                                 ; |hDC
0040640F   . |E8 D8DDFFFF   CALL <JMP.&gdi32.SetTextColor>         ; \SetTextColor

00406CCE   > \52            PUSH EDX
00406CCF   .50            PUSH EAX
00406CD0   .E9 EB9F0000   JMP keygenme.00410CC0      //跳到补丁处
00406CD5      90            NOP
00406CD6      90            NOP
00406CD7      90            NOP
00406CD8      90            NOP


三: 注册算法分析, 这里才是主题~
用RUN跟踪可以得到Validate按钮响应代码在40E7C4处(RUN跟踪如果不会,上看雪论坛去.~)

0040E7C4/.55            PUSH EBP
0040E7C5|.8BEC          MOV EBP,ESP
0040E7C7|.B9 07000000   MOV ECX,7
0040E7CC|>6A 00         /PUSH 0
0040E7CE|.6A 00         |PUSH 0
0040E7D0|.49            |DEC ECX
0040E7D1|.^ 75 F9         \JNZ SHORT keygenme.0040E7CC
0040E7D3|.51            PUSH ECX
0040E7D4|.53            PUSH EBX
0040E7D5|.56            PUSH ESI
0040E7D6|.57            PUSH EDI
0040E7D7|.8BD8          MOV EBX,EAX
0040E7D9|.33C0          XOR EAX,EAX
0040E7DB|.55            PUSH EBP
0040E7DC|.68 88E94000   PUSH keygenme.0040E988
0040E7E1|.64:FF30       PUSH DWORD PTR FS:
0040E7E4|.64:8920       MOV DWORD PTR FS:,ESP
0040E7E7|.8B43 3C       MOV EAX,DWORD PTR DS:
0040E7EA|.B2 01         MOV DL,1
0040E7EC|.E8 DBB4FFFF   CALL keygenme.00409CCC
0040E7F1|.8D55 F4       LEA EDX,DWORD PTR SS:
0040E7F4|.8B43 3C       MOV EAX,DWORD PTR DS:
0040E7F7|.E8 E48AFFFF   CALL keygenme.004072E0                   ;获取注册码
0040E7FC|.8B45 F4       MOV EAX,DWORD PTR SS:
0040E7FF|.E8 4848FFFF   CALL keygenme.0040304C                   ;取注册码长度.
0040E804|.83F8 35       CMP EAX,35
0040E807|.0F85 56010000 JNZ keygenme.0040E963                  ;长度必须等于35(10进制53)
0040E80D|.8D45 F8       LEA EAX,DWORD PTR SS:
0040E810|.50            PUSH EAX
0040E811|.8D55 F0       LEA EDX,DWORD PTR SS:
0040E814|.8B43 3C       MOV EAX,DWORD PTR DS:
0040E817|.E8 C48AFFFF   CALL keygenme.004072E0                   ;再次获取注册码
0040E81C|.8B45 F0       MOV EAX,DWORD PTR SS:
0040E81F|.B9 08000000   MOV ECX,8
0040E824|.BA 2E000000   MOV EDX,2E
0040E829|.E8 264AFFFF   CALL keygenme.00403254                   ;获取注册码最后几位
0040E82E|.8D45 EC       LEA EAX,DWORD PTR SS:            ;参数为最后8位注册码的地址
0040E831|.E8 6AFAFFFF   CALL keygenme.0040E2A0                   ;获取ini文件code字段并进行xor
0040E836|.837D EC 00    CMP DWORD PTR SS:,0
0040E83A|.0F84 23010000 JE keygenme.0040E963
0040E840|.8D55 E8       LEA EDX,DWORD PTR SS:
0040E843|.8B43 38       MOV EAX,DWORD PTR DS:
0040E846|.E8 958AFFFF   CALL keygenme.004072E0                   ;获取用户名
0040E84B|.837D E8 00    CMP DWORD PTR SS:,0
0040E84F|.0F84 0E010000 JE keygenme.0040E963                     ;比较用户名是否为空
0040E855|.8D45 E4       LEA EAX,DWORD PTR SS:
0040E858|.50            PUSH EAX
0040E859|.8D55 DC       LEA EDX,DWORD PTR SS:
0040E85C|.8B43 38       MOV EAX,DWORD PTR DS:
0040E85F|.E8 7C8AFFFF   CALL keygenme.004072E0                   ;再次获取用户名
0040E864|.8B45 DC       MOV EAX,DWORD PTR SS:
0040E867|.8D55 E0       LEA EDX,DWORD PTR SS:
0040E86A|.E8 85F3FFFF   CALL keygenme.0040DBF4                   ;对用户名进行处理..跟进
0040E86F|.8B45 E0       MOV EAX,DWORD PTR SS:            ;处理结果
0040E872|.B9 08000000   MOV ECX,8
0040E877|.BA 09000000   MOV EDX,9
0040E87C|.E8 D349FFFF   CALL keygenme.00403254                   ;从第9为开始,取8个字母, 形成一子串1
0040E881|.8D45 E4       LEA EAX,DWORD PTR SS:
0040E884|.50            PUSH EAX                                 ;刚取的子串1
0040E885|.8D45 D8       LEA EAX,DWORD PTR SS:
0040E888|.50            PUSH EAX
0040E889|.8D55 D4       LEA EDX,DWORD PTR SS:
0040E88C|.8B43 3C       MOV EAX,DWORD PTR DS:
0040E88F|.E8 4C8AFFFF   CALL keygenme.004072E0                   ;再取注册码
0040E894|.8B45 D4       MOV EAX,DWORD PTR SS:
0040E897|.B9 01000000   MOV ECX,1
0040E89C|.BA 09000000   MOV EDX,9
0040E8A1|.E8 AE49FFFF   CALL keygenme.00403254                   ;取注册码的第9位
0040E8A6|.8B55 D8       MOV EDX,DWORD PTR SS:            ;EDX放第9位的地址
0040E8A9|.58            POP EAX
0040E8AA|.E8 A547FFFF   CALL keygenme.00403054                   ;刚取的子串1连接上第9位
0040E8AF|.8B45 E4       MOV EAX,DWORD PTR SS:            ;连接后的子串1
0040E8B2|.50            PUSH EAX
0040E8B3|.8D45 D0       LEA EAX,DWORD PTR SS:
0040E8B6|.50            PUSH EAX
0040E8B7|.8D55 CC       LEA EDX,DWORD PTR SS:
0040E8BA|.8B43 3C       MOV EAX,DWORD PTR DS:
0040E8BD|.E8 1E8AFFFF   CALL keygenme.004072E0                   ;取注册码
0040E8C2|.8B45 CC       MOV EAX,DWORD PTR SS:
0040E8C5|.B9 09000000   MOV ECX,9
0040E8CA|.BA 25000000   MOV EDX,25
0040E8CF|.E8 8049FFFF   CALL keygenme.00403254                   ;从第37(10进制)位取9位, 形成子串2
0040E8D4|.8B55 D0       MOV EDX,DWORD PTR SS:
0040E8D7|.58            POP EAX
0040E8D8|.E8 7F48FFFF   CALL keygenme.0040315C                   ;这里是字符串比较函数,子串1
0040E8DD|.0F85 80000000 JNZ keygenme.0040E963                  ;和子串2必须相等,否则完蛋
0040E8E3|.8D45 FC       LEA EAX,DWORD PTR SS:             ;从ini文件取code字段并与0x1a异或,得
0040E8E6|.E8 B5F9FFFF   CALL keygenme.0040E2A0                   ;到子串3
0040E8EB|.8B45 F8       MOV EAX,DWORD PTR SS:             ;注册码最后8位,作为子串4
0040E8EE|.E8 5947FFFF   CALL keygenme.0040304C
0040E8F3|.8BF8          MOV EDI,EAX
0040E8F5|.85FF          TEST EDI,EDI
0040E8F7|.7E 25         JLE SHORT keygenme.0040E91E
0040E8F9|.BE 01000000   MOV ESI,1
0040E8FE|>8D45 F8       /LEA EAX,DWORD PTR SS:
0040E901|.E8 1649FFFF   |CALL <keygenme.字符串拷贝函数>
0040E906|.8B55 F8       |MOV EDX,DWORD PTR SS:            ;依次取子串4的字母
0040E909|.8A5432 FF   |MOV DL,BYTE PTR DS:
0040E90D|.8B4D FC       |MOV ECX,DWORD PTR SS:            ;依次取子串3的字母
0040E910|.8A4C31 FF   |MOV CL,BYTE PTR DS:
0040E914|.0AD1          |OR DL,CL                              ;对应位进行或运算形成子串5
0040E916|.885430 FF   |MOV BYTE PTR DS:,DL
0040E91A|.46            |INC ESI
0040E91B|.4F            |DEC EDI
0040E91C|.^ 75 E0         \JNZ SHORT keygenme.0040E8FE
0040E91E|>8D45 C8       LEA EAX,DWORD PTR SS:
0040E921|.E8 4AF9FFFF   CALL keygenme.0040E270
0040E926|.8B55 C8       MOV EDX,DWORD PTR SS:
0040E929|.8B45 F8       MOV EAX,DWORD PTR SS:
0040E92C|.E8 2B48FFFF   CALL keygenme.0040315C                   ;经过转换的系统盘Serial串
0040E931|.75 30         JNZ SHORT keygenme.0040E963            ;必须和子串5相等
0040E933|.8D55 C4       LEA EDX,DWORD PTR SS:
0040E936|.8B43 38       MOV EAX,DWORD PTR DS:
0040E939|.E8 A289FFFF   CALL keygenme.004072E0
0040E93E|.8D45 C4       LEA EAX,DWORD PTR SS:
0040E941|.BA A0E94000   MOV EDX,keygenme.0040E9A0                ;ASCII ", you are the best cracker!"
0040E946|.E8 0947FFFF   CALL keygenme.00403054
0040E94B|.8B55 C4       MOV EDX,DWORD PTR SS:
0040E94E|.8B43 38       MOV EAX,DWORD PTR DS:
0040E951|.E8 D689FFFF   CALL keygenme.0040732C
0040E956|.8B43 3C       MOV EAX,DWORD PTR DS:
0040E959|.BA C4E94000   MOV EDX,keygenme.0040E9C4                ;ASCII "Registered!"
0040E95E|.E8 C989FFFF   CALL keygenme.0040732C
0040E963|>8B43 48       MOV EAX,DWORD PTR DS:
0040E966|.B2 01         MOV DL,1
0040E968|.8B08          MOV ECX,DWORD PTR DS:
0040E96A|.FF51 08       CALL DWORD PTR DS:
0040E96D|.33C0          XOR EAX,EAX
0040E96F|.5A            POP EDX
0040E970|.59            POP ECX
0040E971|.59            POP ECX
0040E972|.64:8910       MOV DWORD PTR FS:,EDX
0040E975|.68 8FE94000   PUSH keygenme.0040E98F
0040E97A|>8D45 C4       LEA EAX,DWORD PTR SS:
0040E97D|.BA 0F000000   MOV EDX,0F
0040E982|.E8 6D45FFFF   CALL keygenme.00402EF4
0040E987\.C3            RETN
0040E988   .^ E9 1740FFFF   JMP keygenme.004029A4
0040E98D   .^ EB EB         JMP SHORT keygenme.0040E97A
0040E98F   .5F            POP EDI
0040E990   .5E            POP ESI
0040E991   .5B            POP EBX
0040E992   .8BE5          MOV ESP,EBP
0040E994   .5D            POP EBP
0040E995   .C3            RETN

从ini文件读code字段的函数:
0040E2A0/$55            PUSH EBP
0040E2A1|.8BEC          MOV EBP,ESP
0040E2A3|.6A 00         PUSH 0
0040E2A5|.6A 00         PUSH 0
0040E2A7|.53            PUSH EBX
0040E2A8|.8BD8          MOV EBX,EAX
0040E2AA|.33C0          XOR EAX,EAX
0040E2AC|.55            PUSH EBP
0040E2AD|.68 4DE34000   PUSH keygenme.0040E34D
0040E2B2|.64:FF30       PUSH DWORD PTR FS:
0040E2B5|.64:8920       MOV DWORD PTR FS:,ESP
0040E2B8|.8D45 FC       LEA EAX,DWORD PTR SS:
0040E2BB|.E8 6474FFFF   CALL keygenme.00405724                   ;获取当前路径
0040E2C0|.8D45 FC       LEA EAX,DWORD PTR SS:
0040E2C3|.BA 64E34000   MOV EDX,keygenme.0040E364                ;ASCII "acafeel.ini"
0040E2C8|.E8 874DFFFF   CALL keygenme.00403054                   ;连接路径和ini文件名
0040E2CD|.8B45 FC       MOV EAX,DWORD PTR SS:
0040E2D0|.E8 F777FFFF   CALL keygenme.00405ACC
0040E2D5|.A3 7C554100   MOV DWORD PTR DS:,EAX
0040E2DA|.A1 7C554100   MOV EAX,DWORD PTR DS:
0040E2DF|.C640 18 00    MOV BYTE PTR DS:,0
0040E2E3|.A1 7C554100   MOV EAX,DWORD PTR DS:
0040E2E8|.83C0 1D       ADD EAX,1D
0040E2EB|.BA 78E34000   MOV EDX,keygenme.0040E378                ;ASCII "RegInfo"
0040E2F0|.E8 2F4CFFFF   CALL <keygenme.字符串转移函数>
0040E2F5|.8D45 F8       LEA EAX,DWORD PTR SS:
0040E2F8|.50            PUSH EAX                                 ; /Arg1
0040E2F9|.A1 7C554100   MOV EAX,DWORD PTR DS:            ; |
0040E2FE|.33C9          XOR ECX,ECX                              ; |
0040E300|.BA 88E34000   MOV EDX,keygenme.0040E388                ; |ASCII "code"
0040E305|.E8 1E77FFFF   CALL keygenme.00405A28                   ; \keygenme.00405A28
0040E30A|.8B55 F8       MOV EDX,DWORD PTR SS:             ;获取code字段
0040E30D|.B8 80554100   MOV EAX,keygenme.00415580
0040E312|.E8 0D4CFFFF   CALL <keygenme.字符串转移函数>                  ;字符串拷贝,从EDX到EAX
0040E317|.8BCB          MOV ECX,EBX
0040E319|.BA 1A000000   MOV EDX,1A
0040E31E|.A1 80554100   MOV EAX,DWORD PTR DS:            ;code字段
0040E323|.E8 24FEFFFF   CALL keygenme.0040E14C                   ;字符串xor函数
0040E328|.A1 7C554100   MOV EAX,DWORD PTR DS:
0040E32D|.8B10          MOV EDX,DWORD PTR DS:
0040E32F|.FF52 04       CALL DWORD PTR DS:
0040E332|.33C0          XOR EAX,EAX
0040E334|.5A            POP EDX
0040E335|.59            POP ECX
0040E336|.59            POP ECX
0040E337|.64:8910       MOV DWORD PTR FS:,EDX
0040E33A|.68 54E34000   PUSH keygenme.0040E354
0040E33F|>8D45 F8       LEA EAX,DWORD PTR SS:
0040E342|.BA 02000000   MOV EDX,2
0040E347|.E8 A84BFFFF   CALL keygenme.00402EF4

从这里我们可以知道必须在当前路径出必须有acafeel.ini,内容至少有:

code=xxxxxx
这个函数从code字段读入字符串,并做点处理, 处理函数见下面的代码, 是个很简单的函数, 其中的关键代码:
0040E181|.BB 01000000   MOV EBX,1
0040E186|>8D45 FC       /LEA EAX,DWORD PTR SS:
0040E189|.E8 8E50FFFF   |CALL <keygenme.字符串拷贝函数>
0040E18E|.8B55 FC       |MOV EDX,DWORD PTR SS:
0040E191|.0FB6541A FF   |MOVZX EDX,BYTE PTR DS:
0040E196|.33D7          |XOR EDX,EDI                     //运算就只有这一步
0040E198|.885418 FF   |MOV BYTE PTR DS:,DL
0040E19C|.43            |INC EBX
0040E19D|.4E            |DEC ESI
0040E19E|.^ 75 E6         \JNZ SHORT keygenme.0040E186
0040E1A0|>8B45 F8       MOV EAX,DWORD PTR SS:
0040E1A3|.8B55 FC       MOV EDX,DWORD PTR SS:



还有一个主要函数 ,就是对用户名进行处理, 有点复杂~~

0040DBF4/$55            PUSH EBP
0040DBF5|.8BEC          MOV EBP,ESP
0040DBF7|.B9 0C000000   MOV ECX,0C
0040DBFC|>6A 00         /PUSH 0
0040DBFE|.6A 00         |PUSH 0
0040DC00|.49            |DEC ECX
0040DC01|.^ 75 F9         \JNZ SHORT keygenme.0040DBFC
0040DC03|.51            PUSH ECX
0040DC04|.53            PUSH EBX
0040DC05|.56            PUSH ESI
0040DC06|.57            PUSH EDI
0040DC07|.8955 F8       MOV DWORD PTR SS:,EDX
0040DC0A|.8945 FC       MOV DWORD PTR SS:,EAX
0040DC0D|.8B45 FC       MOV EAX,DWORD PTR SS:
0040DC10|.E8 EB55FFFF   CALL <keygenme.申请空间>
0040DC15|.33C0          XOR EAX,EAX
0040DC17|.55            PUSH EBP
0040DC18|.68 25E04000   PUSH keygenme.0040E025
0040DC1D|.64:FF30       PUSH DWORD PTR FS:
0040DC20|.64:8920       MOV DWORD PTR FS:,ESP
0040DC23|.8B45 FC       MOV EAX,DWORD PTR SS:
0040DC26|.E8 2154FFFF   CALL keygenme.0040304C
0040DC2B|.25 01000080   AND EAX,80000001                         ;用户名长度和80000001与
0040DC30|.79 05         JNS SHORT keygenme.0040DC37
0040DC32|.48            DEC EAX
0040DC33|.83C8 FE       OR EAX,FFFFFFFE
0040DC36|.40            INC EAX
0040DC37|>85C0          TEST EAX,EAX
0040DC39|.0F85 DA010000 JNZ keygenme.0040DE19                  ;用户名长度是偶数时
0040DC3F|.8D55 D8       LEA EDX,DWORD PTR SS:
0040DC42|.8B45 FC       MOV EAX,DWORD PTR SS:
0040DC45|.E8 0AFFFFFF   CALL keygenme.0040DB54                   ;用户名反序
0040DC4A|.8B55 D8       MOV EDX,DWORD PTR SS:
0040DC4D|.8D45 FC       LEA EAX,DWORD PTR SS:
0040DC50|.E8 1353FFFF   CALL keygenme.00402F68                   ;反序后的用户名放到
0040DC55|.BE 80000000   MOV ESI,80
0040DC5A|.8D45 E8       LEA EAX,DWORD PTR SS:
0040DC5D|.BA 3CE04000   MOV EDX,keygenme.0040E03C                ;ASCII "WoAiZhangLiangYing!"
0040DC62|.E8 0153FFFF   CALL keygenme.00402F68                   ;"WoAiZhangLiangYing!"放到
0040DC67|.8B45 FC       MOV EAX,DWORD PTR SS:             ;反序后的用户名
0040DC6A|.E8 DD53FFFF   CALL keygenme.0040304C                   ;取长度
0040DC6F|.85C0          TEST EAX,EAX
0040DC71|.0F8E AF000000 JLE keygenme.0040DD26
0040DC77|.8945 DC       MOV DWORD PTR SS:,EAX            ;用户名长度放到
0040DC7A|.BB 01000000   MOV EBX,1
0040DC7F|>8B45 FC       /MOV EAX,DWORD PTR SS:            ;循环开始,eax放反序后的用户名
0040DC82|.33C9          |XOR ECX,ECX
0040DC84|.8A4C18 FF   |MOV CL,BYTE PTR DS:          ;依次取用户名中的字母
0040DC88|.03CE          |ADD ECX,ESI                           ;加上80
0040DC8A|.8BC1          |MOV EAX,ECX
0040DC8C|.B9 FF000000   |MOV ECX,0FF
0040DC91|.99            |CDQ
0040DC92|.F7F9          |IDIV ECX                              ;除以0ff
0040DC94|.8BF2          |MOV ESI,EDX                           ;余数到esi
0040DC96|.8B45 E8       |MOV EAX,DWORD PTR SS:         ;"WoAiZhangLiangYing!"放到EAX
0040DC99|.33C9          |XOR ECX,ECX
0040DC9B|.8A4C18 FF   |MOV CL,BYTE PTR DS:          ;依次取"WoAiZhangLiangYing!"中的字母
0040DC9F|.33F1          |XOR ESI,ECX                           ;取出来的字母和esi xor
0040DCA1|.8BC3          |MOV EAX,EBX
0040DCA3|.25 01000080   |AND EAX,80000001
0040DCA8|.79 05         |JNS SHORT keygenme.0040DCAF             ;ebx非负则跳
0040DCAA|.48            |DEC EAX
0040DCAB|.83C8 FE       |OR EAX,FFFFFFFE
0040DCAE|.40            |INC EAX
0040DCAF|>85C0          |TEST EAX,EAX
0040DCB1|.75 1C         |JNZ SHORT keygenme.0040DCCF             ;ebx如果为偶数, 则跳
0040DCB3|.8D4D D4       |LEA ECX,DWORD PTR SS:
0040DCB6|.BA 02000000   |MOV EDX,2
0040DCBB|.8BC6          |MOV EAX,ESI
0040DCBD|.E8 AE76FFFF   |CALL keygenme.00405370                  ;如果ebx为偶数,则不经过下面的循环,直接转为字符串
0040DCC2|.8B55 D4       |MOV EDX,DWORD PTR SS:
0040DCC5|.8D45 F0       |LEA EAX,DWORD PTR SS:
0040DCC8|.E8 8753FFFF   |CALL keygenme.00403054
0040DCCD|.EB 4D         |JMP SHORT keygenme.0040DD1C
0040DCCF|>8D4D EC       |LEA ECX,DWORD PTR SS:
0040DCD2|.BA 02000000   |MOV EDX,2
0040DCD7|.8BC6          |MOV EAX,ESI
0040DCD9|.E8 9276FFFF   |CALL keygenme.00405370                  ;将刚才得到ESI变为字符串, 16进制的
0040DCDE|.8B45 EC       |MOV EAX,DWORD PTR SS:
0040DCE1|.E8 6653FFFF   |CALL keygenme.0040304C
0040DCE6|.8BF8          |MOV EDI,EAX
0040DCE8|.85FF          |TEST EDI,EDI
0040DCEA|.7E 30         |JLE SHORT keygenme.0040DD1C             ;转换后字符串长度为零则跳
0040DCEC|.C745 F4 01000>|MOV DWORD PTR SS:,1            ;初始化索引
0040DCF3|>8B45 EC       |/MOV EAX,DWORD PTR SS:          ;EAX为刚才ESI转化为的字符串
0040DCF6|.8B55 F4       ||MOV EDX,DWORD PTR SS:         ;索引
0040DCF9|.0FB64410 FF   ||MOVZX EAX,BYTE PTR DS:      ;依次取其中的字母
0040DCFE|.8D4D D0       ||LEA ECX,DWORD PTR SS:
0040DD01|.BA 02000000   ||MOV EDX,2
0040DD06|.E8 6576FFFF   ||CALL keygenme.00405370               ;再将这个字母的16进制转为字符串
0040DD0B|.8B55 D0       ||MOV EDX,DWORD PTR SS:
0040DD0E|.8D45 F0       ||LEA EAX,DWORD PTR SS:
0040DD11|.E8 3E53FFFF   ||CALL keygenme.00403054               ;连接转移最后的字符串
0040DD16|.FF45 F4       ||INC DWORD PTR SS:
0040DD19|.4F            ||DEC EDI
0040DD1A|.^ 75 D7         |\JNZ SHORT keygenme.0040DCF3
0040DD1C|>43            |INC EBX
0040DD1D|.FF4D DC       |DEC DWORD PTR SS:
0040DD20|.^ 0F85 59FFFFFF \JNZ keygenme.0040DC7F
0040DD26|>8D45 F0       LEA EAX,DWORD PTR SS:
0040DD29|.50            PUSH EAX
0040DD2A|.8D45 CC       LEA EAX,DWORD PTR SS:
0040DD2D|.B9 58E04000   MOV ECX,keygenme.0040E058                ;ASCII "6143614665654C21"
0040DD32|.8B55 F0       MOV EDX,DWORD PTR SS:
0040DD35|.E8 5E53FFFF   CALL keygenme.00403098                   ;字符串连接
0040DD3A|.8B45 CC       MOV EAX,DWORD PTR SS:
0040DD3D|.B9 10000000   MOV ECX,10
0040DD42|.BA 01000000   MOV EDX,1
0040DD47|.E8 0855FFFF   CALL keygenme.00403254
0040DD4C|.8B45 F0       MOV EAX,DWORD PTR SS:            ;上面生成的字符串
0040DD4F|.E8 F852FFFF   CALL keygenme.0040304C
0040DD54|.85C0          TEST EAX,EAX
0040DD56|.7E 50         JLE SHORT keygenme.0040DDA8
0040DD58|.8945 DC       MOV DWORD PTR SS:,EAX
0040DD5B|.BB 01000000   MOV EBX,1
0040DD60|>8BC3          /MOV EAX,EBX
0040DD62|.25 01000080   |AND EAX,80000001
0040DD67|.79 05         |JNS SHORT keygenme.0040DD6E
0040DD69|.48            |DEC EAX
0040DD6A|.83C8 FE       |OR EAX,FFFFFFFE
0040DD6D|.40            |INC EAX
0040DD6E|>85C0          |TEST EAX,EAX
0040DD70|.74 30         |JE SHORT keygenme.0040DDA2            ;如果ebx为偶数,则跳
0040DD72|.8D45 C4       |LEA EAX,DWORD PTR SS:
0040DD75|.50            |PUSH EAX
0040DD76|.B9 02000000   |MOV ECX,2
0040DD7B|.8BD3          |MOV EDX,EBX
0040DD7D|.8B45 F0       |MOV EAX,DWORD PTR SS:
0040DD80|.E8 CF54FFFF   |CALL keygenme.00403254                  ;取子串
0040DD85|.8B45 C4       |MOV EAX,DWORD PTR SS:
0040DD88|.E8 1776FFFF   |CALL keygenme.004053A4                  ;字符串转为数字
0040DD8D|.8BD0          |MOV EDX,EAX
0040DD8F|.8D45 C8       |LEA EAX,DWORD PTR SS:
0040DD92|.E8 5152FFFF   |CALL keygenme.00402FE8                  ;数字拷贝到ebp-38
0040DD97|.8B55 C8       |MOV EDX,DWORD PTR SS:
0040DD9A|.8D45 E4       |LEA EAX,DWORD PTR SS:
0040DD9D|.E8 B252FFFF   |CALL keygenme.00403054
0040DDA2|>43            |INC EBX
0040DDA3|.FF4D DC       |DEC DWORD PTR SS:
0040DDA6|.^ 75 B8         \JNZ SHORT keygenme.0040DD60
0040DDA8|>8D55 C0       LEA EDX,DWORD PTR SS:
0040DDAB|.8B45 E4       MOV EAX,DWORD PTR SS:
0040DDAE|.E8 A1FDFFFF   CALL keygenme.0040DB54                   ;拷贝.
0040DDB3|.8B55 C0       MOV EDX,DWORD PTR SS:
0040DDB6|.8D45 E4       LEA EAX,DWORD PTR SS:
0040DDB9|.E8 AA51FFFF   CALL keygenme.00402F68                   ;取反序
0040DDBE|.8B45 E4       MOV EAX,DWORD PTR SS:
0040DDC1|.E8 8652FFFF   CALL keygenme.0040304C
0040DDC6|.85C0          TEST EAX,EAX
0040DDC8|.0F8E 1C020000 JLE keygenme.0040DFEA
0040DDCE|.8945 DC       MOV DWORD PTR SS:,EAX
0040DDD1|.BB 01000000   MOV EBX,1                              ;ebx为索引
0040DDD6|>8B45 E4       /MOV EAX,DWORD PTR SS:
0040DDD9|.33C9          |XOR ECX,ECX
0040DDDB|.8A4C18 FF   |MOV CL,BYTE PTR DS:          ;依次取其中的字节
0040DDDF|.03CE          |ADD ECX,ESI
0040DDE1|.8BC1          |MOV EAX,ECX
0040DDE3|.B9 FF000000   |MOV ECX,0FF
0040DDE8|.99            |CDQ
0040DDE9|.F7F9          |IDIV ECX
0040DDEB|.8BF2          |MOV ESI,EDX
0040DDED|.B9 2B000000   |MOV ECX,2B
0040DDF2|.33F1          |XOR ESI,ECX                           ;与2b xor
0040DDF4|.8D4D BC       |LEA ECX,DWORD PTR SS:
0040DDF7|.BA 12000000   |MOV EDX,12
0040DDFC|.8BC6          |MOV EAX,ESI
0040DDFE|.E8 6D75FFFF   |CALL keygenme.00405370                  ;16进制转为字符串
0040DE03|.8B55 BC       |MOV EDX,DWORD PTR SS:
0040DE06|.8D45 E0       |LEA EAX,DWORD PTR SS:
0040DE09|.E8 4652FFFF   |CALL keygenme.00403054
0040DE0E|.43            |INC EBX
0040DE0F|.FF4D DC       |DEC DWORD PTR SS:
0040DE12|.^ 75 C2         \JNZ SHORT keygenme.0040DDD6
0040DE14|.E9 D1010000   JMP keygenme.0040DFEA

上面是用户名长度为偶数的情况, 如果用户名长度为奇数, 也可以参考这个分析, 因为两种情况绝大部分的处理是相同的,这里的算法如果看不清楚, 可以看我写的注册机代码, 里面将这个函数实现了一下...

还有个函数要看..是对系统硬盘序列号进行处理, 生成一个字符串. 看代码
0040E270/$53            PUSH EBX
0040E271|.8BD8          MOV EBX,EAX
0040E273|.B0 43         MOV AL,43
0040E275|.E8 56FFFFFF   CALL keygenme.0040E1D0                   ;这个函数调用GetVolumeInformation获得
0040E27A|.69C0 27400000 IMUL EAX,EAX,4027                        ;系统盘的Serial, EAX里是返回值
0040E280|.05 2724400B   ADD EAX,0B402427
0040E285|.8BD3          MOV EDX,EBX
0040E287|.E8 8871FFFF   CALL keygenme.00405414                   ;转成字符串
0040E28C|.53            PUSH EBX
0040E28D|.8B03          MOV EAX,DWORD PTR DS:
0040E28F|.B9 08000000   MOV ECX,8
0040E294|.BA 01000000   MOV EDX,1
0040E299|.E8 B64FFFFF   CALL keygenme.00403254                   ;从第1位开始取8个字母,形成子串
0040E29E|.5B            POP EBX
0040E29F\.C3            RETN

附注册机源码:
#include<iostream>
#include<cstring>
#include<sstream>
#include<windows.h>
#include<fstream>

usingnamespacestd;
#defineMAX_DST100

voidstrxor(char* dst, char* src, char ch)   //关于ini文件code 异或的函数
{
        intlen = strlen(src);
        inti;
        for(i=0; i<len; i++)
        {
                dst = src ^ ch;
        }
        dst = 0;
}

void HexToDec(char* shex, char* idec )   //十六进制转为整数..找不到合用的就自己写了一个函数..
{                                       //不过只能这个程序用..
        int i, j, mid=0;
        int len = strlen(shex);
        for(i=0, j=0; i<len; i++)
        {
                if( shex>='0' && shex<='9' )
                        mid = shex - '0';
                else if(shex>='a' && shex<='f')
                  mid = shex - 'a' + 10;
                else if(shex>='A' && shex<='F')
                        mid = shex - 'A' + 10;
               
                if (i%2 == 0)
                {       
                        mid <<= 4;
                        idec = mid;
                }
                else
                {
                        idec |= mid;
                        j++;
                }
        }
        idec = 0;
}

voidDealWithName(char *namedst, char *namesrc)    //对用户名处理的函数,,最复杂的一个函数.
{
        strrev(namesrc);

        charszLove[] = "WoAiZhangLiangYing!";
        charszTemp = {0};
        charszTemp2 = {0};
        int   namelen = strlen(namesrc);
        int   i, j=0;
        unsigned int   temp= 0x80;//记录esi

        if (namelen %2 ==0)
        {
                for (i=0; i<namelen; i++)
                {
                        temp += namesrc;
                        temp %= 0xff;
                        temp ^= szLove;

                        if (i%2 == 1)
                        {
                                sprintf(szTemp, "%X", temp);
                                if (szTemp == ' ')        szTemp2 = '0';
                                strcat(namedst, szTemp);
                        }
                        else
                        {
                                memset(szTemp, 0, sizeof(szTemp));
                                sprintf(szTemp, "%X", temp);
                                for (j=0; j<strlen(szTemp); j++)
                                {
                                        sprintf(szTemp2, "%X", (int)szTemp);
                                        if (szTemp2 == ' ')        szTemp2 = '0';
                                        strcat(namedst, szTemp2);
                                }
                        }
                }

                char*szToCat = "6143614665654C21";
                strcat(namedst, szToCat);
                namedst = 0;    //取前16个字母

                char   szScan = {0};
                strcpy(szScan, namedst);
                HexToDec(szScan, namedst);
                strrev(namedst);
       
                strcpy(szTemp, namedst);
                memset(namedst, 0, MAX_DST);
                namelen = strlen(szTemp);
                for (i=0; i<namelen; i++)
                {
                        temp += szTemp;
                        temp %= 0xff;
                        temp ^= 0x2b;
               
                        sprintf(szTemp2, "%2X", temp);
                        if (szTemp2 == ' ')        szTemp2 = '0';
                        strcat(namedst, szTemp2);
                }
        }
        else
        {
                for (i=0; i<namelen; i++)
                {
                        temp += namesrc;
                        temp %= 0xff;
                        temp ^= szLove;

                        if (i%2 == 0)
                        {
                                sprintf(szTemp, "%X", temp);
                                if (szTemp == ' ')        szTemp2 = '0';
                                strcat(namedst, szTemp);
                        }
                        else
                        {
                                memset(szTemp, 0, sizeof(szTemp));
                                sprintf(szTemp, "%X", temp);
                                for (j=0; j<strlen(szTemp); j++)
                                {
                                        sprintf(szTemp2, "%X", (int)szTemp);
                                        if (szTemp2 == ' ')        szTemp2 = '0';
                                        strcat(namedst, szTemp2);
                                }
                        }
                }

                //cout << namedst << endl;
                char*szToCat = "6143614665654C21";
                strcat(namedst, szToCat);
                namedst = 0;    //取前16个字母

                //cout << namedst << endl;
                char   szScan = {0};
                strcpy(szScan, namedst);
                HexToDec(szScan, namedst);
                strrev(namedst);
       
                //cout << namedst << endl;
                strcpy(szTemp, namedst);
                memset(namedst, 0, MAX_DST);
                namelen = strlen(szTemp);
                for (i=0; i<namelen; i++)
                {
                        temp += szTemp;
                        temp %= 0xff;
                        temp ^= 0x2b;
               
                        sprintf(szTemp2, "%2X", temp);
                        if (szTemp2 == ' ')        szTemp2 = '0';
                        strcat(namedst, szTemp2);
                }
                //cout << namedst << endl;
        }
}

voidGetSystemSerial(char*serialdst)    //获取系统Serial并做处理
{
        char*path = "c:\\";
        charbuffer;
        DWORD   dwSerial;   
    DWORD   dwMaximumComponentLength;   
    DWORD   dwFileSystemFlags;
        ::GetVolumeInformation(path, 0, 0, &dwSerial, &dwMaximumComponentLength, &dwFileSystemFlags, NULL, NULL);

        dwSerial *= 0x4027;
        dwSerial += 0xB402427;
        sprintf(serialdst, "%u", dwSerial);
        serialdst = 0;
}

voidmain()
{
        charcode = {0};      //ini的code
        charxorcode;         //ini的code异或后的结果
        charregcode = {0};
        memset(regcode, 'A', 53);    //注册码中有很多字母没用, 我就用'A'来填充吧..

        charname    = "vecri";   //用户名
        charnamesrc;
        strcpy(namesrc, name);

        charnamedst = {0};
        DealWithName(namedst, namesrc);   //对用户名处理

        charsub1 = {0};
        strncpy(sub1, namedst+8, 8);    //取子串1
       
        strncpy(regcode+36, sub1, 8);    //从子串1获取注册码的一部分, 要看分析~~

        char*sub3 = xorcode;
        char*sub4 = "asdfasdf";   //子串4, 注册码最后8位
        char   sysserial = {0};
        GetSystemSerial(sysserial);   //Serial转换的结果

        strxor(code, sysserial, 0x1a);   //得到ini的code

        ofstreamfout("result.txt");
        fout << code << endl;
        strncpy(regcode+45, sysserial, 8);
        fout << regcode << endl;
        fout.close();      //结果文件, 其中有ini的code , 和注册码

        /*大家自己在crackme的目录下新建个acafeel.ini, 其中内容为
       
        code=我生成的code
        */
        //呵呵...我懒得去写代码..~~
        cout << "name: " << name << endl;
        cout << "code: " << regcode << endl;

        charch;
        cin >> ch;
}

------------------------------------------------------------------------
【破解总结】看到正式版和前传版, 就慌忙拿前传版来破,,呵呵..感觉应该简单点吧....~接下来搞正式版的~
------------------------------------------------------------------------
【版权声明

[ 本帖最后由 vecri 于 2008-1-5 19:40 编辑 ]

magic659117852 发表于 2007-12-24 21:36:52

/:011 向楼主看齐 .........../:014

acafeel 发表于 2007-12-25 13:53:11

相当的彪悍呀/:001

阳小子 发表于 2007-12-25 15:01:06

前传版一只搞不定,今天总算看到了啊。

vecri 发表于 2007-12-26 11:23:16

这里是不是不轻易给精华的啊。.~/:002

感觉还是算法分析版块好拿精华~

CuteSnail 发表于 2007-12-26 13:09:17

收藏下来慢慢看了

小子贼野 发表于 2008-1-5 16:39:41

原帖由 vecri 于 2007-12-26 11:23 发表 https://www.chinapyg.com/images/common/back.gif
这里是不是不轻易给精华的啊。.~/:002

感觉还是算法分析版块好拿精华~

精华不是那么容易骗的/:018

楼主忒彪悍了,膜拜

[ 本帖最后由 小子贼野 于 2008-1-5 16:41 编辑 ]

vecri 发表于 2008-1-5 20:14:45

确实不好骗~~~努力学习中,争取拿到精华。。。

阳小子 发表于 2008-4-1 12:42:25

学了汇编后才知其然啊,原来aCaFeeL大虾在创建窗口的时候使用了WS_DISABLED风格属性,让窗口初始化状态是被禁止的,然后又在设置文本按钮颜色的参数为Gray,LZ那两个补丁打的很漂亮,不过应该可以在代码段直接修改属性达到目的的,可难的就是在茫茫代码量中找到需要修改属性的值啊,就想petnt大虾过后飞笨鸟之CrackMe一样在易语言代码段中修改属性值来达到去掉只读属性。

龙爷 发表于 2008-4-3 23:08:53

好长的代码。。没有图???
页: [1] 2
查看完整版本: aCaFeeL's CrackMe V5(前传版)算法分析 + 注册机(附件)