首页
社区
课程
招聘
[原创]nonzenze's keygenme#1破解分析
发表于: 2006-8-16 16:56 5786

[原创]nonzenze's keygenme#1破解分析

2006-8-16 16:56
5786

【破文标题】CRACKME算法分析
【破文作者】逍遥风
【破解工具】OD
【破解平台】WINXP
【软件简介】Difficulty: 1 - Very easy, for newbies
            Platform: Windows
            Language: Assembler

----------------------------------------------------------------------

这个CRACKME在跟踪的时候要注意,再检验完毕注册码的长度后,后面的代码会产生一个异常,使单步跟踪无法继续
所以跟踪的时候要注意这一点。

根据注册的提示信息,很容易找到关键代码处
一下部分就是关键代码:

0040108F  |.  68 FF000000   push    0FF                         ; /Count = FF (255.)
00401094  |.  8D85 01FFFFFF lea     eax, [ebp-FF]               ; |
0040109A  |.  50            push    eax                         ; |Buffer
0040109B  |.  68 ED030000   push    3ED                         ; |ControlID = 3ED (1005.)
004010A0  |.  FF75 08       push    dword ptr [ebp+8]           ; |hWnd
004010A3  |.  E8 82040000   call    <jmp.&user32.GetDlgItemText>; \GetDlgItemTextA
004010A8  |.  68 FF000000   push    0FF                         ; /Count = FF (255.)
004010AD  |.  8D85 02FEFFFF lea     eax, [ebp-1FE]              ; |
004010B3  |.  50            push    eax                         ; |Buffer
004010B4  |.  68 E9030000   push    3E9                         ; |ControlID = 3E9 (1001.)
004010B9  |.  FF75 08       push    dword ptr [ebp+8]           ; |hWnd
004010BC  |.  E8 69040000   call    <jmp.&user32.GetDlgItemText>; \GetDlgItemTextA
004010C1  |.  8D85 02FEFFFF lea     eax, [ebp-1FE]              ;  分别注册名和注册码
004010C7  |.  50            push    eax                         ;  使EAX等于输入的注册码
004010C8  |.  E8 D3030000   call    004014A0                    ;  取输入的注册名
004010CD  |.  8D85 01FFFFFF lea     eax, [ebp-FF]               ;  使EAX等于注册名
004010D3  |.  50            push    eax
004010D4  |.  E8 F7030000   call    004014D0                    ;  取注册名位数
004010D9  |.  8985 ECFDFFFF mov     [ebp-214], eax
004010DF  |.  83F8 05       cmp     eax, 5                      ;  注册名位数与5比较
004010E2  |.  0F82 83010000 jb      0040126B                    ;  注册名小于5位就跳向失败
004010E8  |.  8D85 02FEFFFF lea     eax, [ebp-1FE]              ;  使EAX等于注册码
004010EE  |.  50            push    eax
004010EF  |.  E8 DC030000   call    004014D0                    ;  取注册码的位数
004010F4  |.  8985 E8FDFFFF mov     [ebp-218], eax
004010FA  |.  83F8 08       cmp     eax, 8                      ;  注册码位数与8比较
004010FD  |.  0F85 85010000 jnz     00401288                    ;  不等于8位就跳向失败
从这里得知:
1)注册名必须大于5位
2)注册码必须等于8位

00401103  |.  C705 08304000>mov     dword ptr [403008], 0040112>
0040110D  |.  892D 04304000 mov     [403004], ebp
00401113  |.  68 00104000   push    00401000
00401118  |.  64:FF35 00000>push    dword ptr fs:[0]
0040111F  |.  8925 00304000 mov     [403000], esp
00401125  |.  64:8925 00000>mov     fs:[0], esp
0040112C  |.  64:8F05 00000>pop     dword ptr fs:[0]
00401133  |.  83C4 04       add     esp, 4
00401136  |.  C705 08304000>mov     dword ptr [403008], 0040116>
00401140  |.  892D 04304000 mov     [403004], ebp
00401146  |.  68 00104000   push    00401000
0040114B  |.  64:FF35 00000>push    dword ptr fs:[0]
00401152  |.  8925 00304000 mov     [403000], esp
00401158  |.  64:8925 00000>mov     fs:[0], esp
0040115F  |.  33DB          xor     ebx, ebx                    ;  使EBX等于0
00401161  |.  33D2          xor     edx, edx
00401163  |.  B8 02000000   mov     eax, 2                      ;  使EAX等于2
00401168  |.  F7F3          div     ebx                         ;  2/0,会出现一个异常

单步跟踪到这里,就会发现不能再跟踪下去了。因为
这里先使寄存器EBX等于0,使寄存器EAX等于2
然后用EAX中的值去除EBX中的值。即用2去除以0,这样就会产生一个除0的异常。就会导致跟踪不下去了。
跳过这段代码的方法有很多,我们的主要目的是分析它的算法,所以想办法在跟踪的时候跳过这段代码就可以了。

重新载入CRACKME。单步跟踪到
004010FD  |.  0F85 85010000 jnz     00401288                    ;  不等于8位就跳向失败
这里的时候,将鼠标点在
0040117A  |.  899D F0FDFFFF mov     [ebp-210], ebx
这一行,然后F4运行到所选。就可以跳过那段异常代码了。

0040116A  |.  64:8F05 00000>pop     dword ptr fs:[0]
00401171  |.  83C4 04       add     esp, 4
00401174  |.  33C0          xor     eax, eax
00401176  |.  33DB          xor     ebx, ebx
00401178  |.  33C9          xor     ecx, ecx
现在来到了这里:

0040117A  |.  899D F0FDFFFF mov     [ebp-210], ebx
00401180  |.  C685 E7FDFFFF>mov     byte ptr [ebp-219], 0
00401187  |.  8A8D 01FFFFFF mov     cl, [ebp-FF]                ;  取注册名每一位的ASCII码
0040118D  |>  8AC1          /mov     al, cl                     ;  使AL=CL,计算结果An,其中A1等于注册名第一位的ASCII码
0040118F  |.  0FCB          |bswap   ebx                        ;  交换顺序
00401191  |.  03D8          |add     ebx, eax                   ;  
00401193  |.  FE85 E7FDFFFF |inc     byte ptr [ebp-219]         ;  计算次数加1
00401199  |.  51            |push    ecx
0040119A  |.  8A8D E7FDFFFF |mov     cl, [ebp-219]              ;  使CL等于计算次数
004011A0  |.  3B8D ECFDFFFF |cmp     ecx, [ebp-214]             ;  计算次数与注册名位数相比较
004011A6  |.  59            |pop     ecx
004011A7  |.  41            |inc     ecx                        ;  将An的值加1得到A(n+1)
004011A8  |.^ 72 E3         \jb      short 0040118D             ;  循环计算

这段算法很有意思,用到了BSWAP指令,它的作用是交换32位寄存器里字节的顺序
怎么理解呢,还是用例子来说明问题吧

以注册名lovetc为例。
0040118D  |>  8AC1          /mov     al, cl                     ;  使AL=CL,计算结果An,其中A1等于注册名第一位的ASCII码
如代码中提示:A1=注册名第一位的ASCII码。
即:A1 = 6C  
然后:
004011A7  |.  41            |inc     ecx                        ;  将An的值加1得到A(n+1)
即:A(2)=A1+1 = 6D

此时:EBX中的值就是A1=6C,
      EAX中的值就是A2=6D
下面就是关键的一句

0040118F  |.  0FCB          |bswap   ebx                        ;  交换顺序
现在EBX=0000006C。执行过这一句后EBX的值就变为
EBX=6C000000。

然后再相加:
00401191  |.  03D8          |add     ebx, eax     
              ;  
现在EBX中的值就是:
6C00006D

以此类推:以后的变换过程就是:

1)A(3)=A(2)+1=6E.
2)变换顺序;6C00006D变为6D00006C
3)相加:6D00006C+6E=6D0000DA
。。。
重复计算:
1)A(4)=A(3)+1=6F
2)交换顺序:6D0000DA变为DA00006D
3)相加:DA00006D+6F=DA0000DC
。。。
以此类推。
循环计算的次数就是注册名的长度。

最后:
注册名lovetc对应的注册码就是4A01014D

另外:
关于异常的部分,由于水平有限没有将那一部分分析完整。
所以希望大家补充,以便我等菜鸟学习

----------------------------------------------------------------------
比较有趣的算法计算。
----------------------------------------------------------------------
【版权声明】本文只为交流,转载请保留作者及文章完整性


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 7
支持
分享
最新回复 (7)
雪    币: 461
活跃值: (93)
能力值: ( LV9,RANK:1170 )
在线值:
发帖
回帖
粉丝
2
异常部分,我也不太懂,希望高手给予指导.
2006-8-16 20:50
0
雪    币: 338
活跃值: (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
3
强帖必留言!
2006-8-17 12:40
0
雪    币: 214
活跃值: (10)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
4
是2处异常:

0040115F      33DB          XOR EBX,EBX
00401161  |.  33D2          XOR EDX,EDX
00401163  |.  B8 02000000   MOV EAX,2
00401168  |.  F7F3          DIV EBX

004012E9  |> \33DB          XOR EBX,EBX
004012EB  |.  33D2          XOR EDX,EDX
004012ED  |.  B8 02000000   MOV EAX,2
004012F2  |.  F7F3          DIV EBX

把2处 F7F3 nop掉就成了
2006-8-17 13:11
0
雪    币: 615
活跃值: (1217)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
5
既然调试会出现异常,那么程序执行的时候为什么就不会异常呢?
这个问题我始终不明白,希望高手在此讲解!
2006-8-17 17:56
0
雪    币: 291
活跃值: (213)
能力值: ( LV12,RANK:210 )
在线值:
发帖
回帖
粉丝
6
SEH把异常吞了

40100这里是个异常回调函数,会把Eip修正为地址403008的内容

sub_401000      proc near               ; DATA XREF: DialogFunc+B4o
.text:00401000                                         ; DialogFunc+E7o ...
.text:00401000
.text:00401000 arg_8           = dword ptr  10h
.text:00401000
.text:00401000                 push    ebp
.text:00401001                 mov     ebp, esp
.text:00401003                 mov     eax, [ebp+arg_8]
.text:00401006                 push    dword_403008
.text:0040100C                 pop     [eax+CONTEXT.Eip]
.text:00401012                 push    dword_403000
.text:00401018                 pop     [eax+CONTEXT.Esp]
.text:0040101E                 push    dword_403004
.text:00401024                 pop     [eax+CONTEXT.Ebp]
.text:0040102A                 mov     eax, 0
.text:0040102F                 leave
.text:00401030                 retn
.text:00401030 sub_401000      endp

第1个SEH节点
.text:00401103                 mov     dword_403008, offset loc_40112C
.text:0040110D                 mov     dword_403004, ebp
.text:00401113                 push    offset sub_401000
.text:00401118                 push    large dword ptr fs:0
.text:0040111F                 mov     dword_403000, esp
.text:00401125                 mov     large fs:0, esp
.text:0040112C

如果异常发生将跳转到40112C处

不过这里没有异常发生,随后程序又建立了一个全新的节点
text:0040112C loc_40112C:                             ; DATA XREF: DialogFunc+A4o
.text:0040112C                 pop     large dword ptr fs:0
.text:00401133                 add     esp, 4
.text:00401136                 mov     dword_403008, offset loc_40116A
.text:00401140                 mov     dword_403004, ebp
.text:00401146                 push    offset sub_401000
.text:0040114B                 push    large dword ptr fs:0
.text:00401152                 mov     dword_403000, esp
.text:00401158                 mov     large fs:0, esp

异常---------------
text:0040115F                 xor     ebx, ebx
.text:00401161                 xor     edx, edx
.text:00401163                 mov     eax, 2
.text:00401168                 div     ebx

异常发生后将跳转到粗体字所示的40116A处

40116a处内容略,见逍遥风大虾的算法分析

这两次异常仅仅相当于跳转而已

后面还有一次异常,道理类似,各位自己看看吧
2006-8-17 20:34
0
雪    币: 433
活跃值: (176)
能力值: ( LV13,RANK:1250 )
在线值:
发帖
回帖
粉丝
7
您还在为汇编写的害虫而烦恼吗?IDA杀虫剂是您最佳的选择,安全、高效,无副作用!
2006-9-1 22:12
0
雪    币: 721
活跃值: (350)
能力值: ( LV9,RANK:1250 )
在线值:
发帖
回帖
粉丝
8
最初由 冲天剑 发布
您还在为汇编写的害虫而烦恼吗?IDA杀虫剂是您最佳的选择,安全、高效,无副作用!


Data Rescue应该给你颁发一个最佳广告创意奖。
2006-9-3 16:26
0
游客
登录 | 注册 方可回帖
返回
//