首页
论坛
课程
招聘
[原创]专业扫雷注册算法分析
2006-5-3 04:48 7187

[原创]专业扫雷注册算法分析

2006-5-3 04:48
7187
【破文标题】:专业扫雷注册算法分析

【破文作者】:alphabet

【作者邮箱】:nkshk@eyou.com

【软件名称】:专业扫雷1.2版

【软件大小】:616KB

【下载主页】:http://alphabet.ys168.com

【保护方式】:用户名+注册码

【加密保护】:无

【编译语言】:Borland C++

【调试环境】:WinXP SP2

【破解工具】:ODbyDYK v1.10[06.02.12]

【破解日期】:2006-05-03

【作者声明】:本人的第一篇破文,水平不高,在此和我水平一样菜的朋友们共享研究,也请高手们不吝教正,由于本人不太会设置字体的颜

             色,可能看起来比较乱,如果需要,请斑竹帮忙修改一下。谢谢!

一、先运行程序注册了一下看了看,有错误提示“无效的注册号码”,不错!用PEID检查了一下,没有加壳,Borland C++编的,呵呵,又省  

    去脱壳过程了,心里偷乐!
    用OD载入,打开程序,查找==>>所有参考文本串,竟然没有发现“无效的注册号码”,不会吧?Ultra字符串参考==>>查找UNICODE,点完

    之后,弹出一个错误对话框,点确定后,OD自动关闭了,郁闷,看来还是下API函数断点吧。
    OD重新打开程序,右键 查找==>>当前模块中的名称(标签),找到了GetDlgItemTextA,点击右键,选择在每个参考上设置断点,界面左下

    方提示4个断点已设,然后F9运行,程序运行之后,点注册,我输入的用户名是fuzhuhl,注册码是78787878,然后点确定,OD会会中断到

    00404FEB处,

二、注册算法分析
============================================================================================================================
00404FE1  |> \6A 50         push    50                               ; /Count = 50 (80.); Case 1 of switch 00404FD6
00404FE3  |.  68 C8ED4100   push    offset 专业扫雷.reg_ime              ; |Buffer = offset 专业扫雷.reg_ime
00404FE8  |.  6A 65         push    65                               ; |ControlID = 65 (101.)
00404FEA  |.  53            push    ebx                              ; |hWnd
00404FEB  |.  E8 07600100   call    <jmp.&USER32.GetDlgItemTextA>    ; \GetDlgItemTextA           //最先断在这里
按F8运行,会断到另一个地方,按ALT+F9返回程序领空,继续F8运行
00404FF0  |.  6A 0A         push    0A                               ; /Count = A (10.)
00404FF2  |.  68 18EE4100   push    offset 专业扫雷.reg_broj             ; |Buffer = offset 专业扫雷.reg_broj
00404FF7  |.  6A 66         push    66                               ; |ControlID = 66 (102.)
00404FF9  |.  53            push    ebx                              ; |hWnd
00404FFA  |.  E8 F85F0100   call    <jmp.&USER32.GetDlgItemTextA>    ; \GetDlgItemTextA           //这也有一个断点
按F8运行,也会断到另一个地方,按ALT+F9返回程序领空,继续F8运行
00404FFF  |.  68 18EE4100   push    offset 专业扫雷.reg_broj             ; /Arg2 = 0041EE18 ASCII "78787878"
00405004  |.  68 C8ED4100   push    offset 专业扫雷.reg_ime              ; |Arg1 = 0041EDC8 ASCII "fuzhuhl"
00405009  |.  E8 49060000   call    专业扫雷.provjeri_registraciju       ; \provjeri_registraciju  
----------------------------关键call,F7跟进。
0040500E  |.  83C4 08       add     esp, 8
00405011  |.  A2 22EE4100   mov     [registriran], al
00405016  |.  84C0          test    al, al                           //检测al每位进行“与”操作
00405018  |.  74 11         je      short 专业扫雷.0040502B          //等于0就跳到错误              //爆破点
0040501A  |.  C605 74C04100>mov     byte ptr [nag_aktivan], 0
00405021  |.  6A 00         push    0                                ; /Result = 0
00405023  |.  53            push    ebx                              ; |hWnd
00405024  |.  E8 EC5F0100   call    <jmp.&USER32.EndDialog>          ; \EndDialog
00405029  |.  EB 13         jmp     short 专业扫雷.0040503E
0040502B  |>  6A 30         push    30                               ; /Style = MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL
0040502D  |.  FF35 78C04100 push    dword ptr [naslov]               ; |Title = "Professional Minesweeper"
00405033  |.  68 13EF4100   push    offset 专业扫雷.tekst3               ; |Text = "无效的",D7,"",A2,"",B2,"岷怕耄",A1,""
-----------------------------------------------------------------------------------看到错误提示了吧?
00405038  |.  53            push    ebx                              ; |hOwner
00405039  |.  E8 6D600100   call    <jmp.&USER32.MessageBoxA>        ; \MessageBoxA
0040503E  |>  B0 01         mov     al, 1
00405040  |.  EB 28         jmp     short 专业扫雷.0040506A
00405042  |>  C605 74C04100>mov     byte ptr [nag_aktivan], 0        ;  Case 2 of switch 00404FD6
00405049  |.  6A 00         push    0                                ; /Result = 0
0040504B  |.  53            push    ebx                              ; |hWnd
0040504C  |.  E8 C45F0100   call    <jmp.&USER32.EndDialog>          ; \EndDialog
00405051  |.  B0 01         mov     al, 1
00405053  |.  EB 15         jmp     short 专业扫雷.0040506A
00405055  |>  6A 00         push    0                                ; /Result = 0; Case 10 (WM_CLOSE) of switch 00404F93
00405057  |.  53            push    ebx                              ; |hWnd
00405058  |.  E8 B85F0100   call    <jmp.&USER32.EndDialog>          ; \EndDialog
0040505D  |.  C605 74C04100>mov     byte ptr [nag_aktivan], 0
00405064  |.  B0 01         mov     al, 1
00405066  |.  EB 02         jmp     short 专业扫雷.0040506A
============================================================================================================================
F7跟入停在这
00405657 >/$  55            push    ebp
00405658  |.  8BEC          mov     ebp, esp
0040565A  |.  83C4 E4       add     esp, -1C
0040565D  |.  53            push    ebx
0040565E  |.  56            push    esi
0040565F  |.  57            push    edi
00405660  |.  8B5D 0C       mov     ebx, [arg.reg_broj]                    //假注册码送ebx
00405663  |.  8B4D 08       mov     ecx, [arg.reg_ime]                     //用户名送ecx
00405666  |.  33C0          xor     eax, eax                               //eax清零,下面用作计数器
---------------------------------------------------------------------------------------------------------------------------
下面为一个循环,取每一位注册码进行判断
---------------------------------------------------------------------------------------------------------------------------
00405668  |>  0FBE1403      /movsx   edx, byte ptr [ebx+eax]               //假注册码的每一位(ASCII码的十六进制)以符号扩展送

                                                                             edx
0040566C  |.  83C2 D0       |add     edx, -30                              //此处还是举例说明吧。如此位假注册码是7,在这步中

也就是“7”的ASCII码的十六进制“37”加上“-30”,得到“7”,也就是此位的假注册码,每次循环到这都是这样得到原位假注册码
0040566F  |.  895485 E4     |mov     [ebp+eax*4-1C], edx                   //把每一位假注册码存入一地址
00405673  |.  837C85 E4 00  |cmp     dword ptr [ebp+eax*4-1C], 0           
00405678  |.  7C 07         |jl      short 专业扫雷.00405681                                                            
0040567A  |.  837C85 E4 09  |cmp     dword ptr [ebp+eax*4-1C], 9                                                        
0040567F  |.  7E 23         |jle     short 专业扫雷.004056A4                                                            
上面几句用来判断输入的每一位是不是数字,不是数字就跳到错误,所以必须为数字注册码,如果为数字就跳到004056A4处
00405681  |>  68 2DC44100   |push    专业扫雷.0041C42D                   ; /src = "-------"                             
00405686  |.  51            |push    ecx                             ; |dest
00405687  |.  E8 F4F00000   |call    专业扫雷.strcpy                     ; \strcpy
0040568C  |.  83C4 08       |add     esp, 8
0040568F  |.  68 35C44100   |push    专业扫雷.0041C435                   ; /src = "-------"
00405694  |.  53            |push    ebx                             ; |dest
00405695  |.  E8 E6F00000   |call    专业扫雷.strcpy                     ; \strcpy
0040569A  |.  83C4 08       |add     esp, 8
0040569D  |.  33C0          |xor     eax, eax
0040569F  |.  E9 A5000000   |jmp     专业扫雷.00405749
跳到这
004056A4  |>  40            |inc     eax                                    //计数器加1
004056A5  |.  83F8 07       |cmp     eax, 7                                 //循环7次,只取前7位注册码,因此注册码必须够7位
004056A8  |.^ 7C BE         \jl      short 专业扫雷.00405668                  多于7位无关紧要,但不能少于7位
----------------------------------------------------------------------------------------------------------------------------
上述循环取注册码的前7位进行判断,看它们是不是全是数字
----------------------------------------------------------------------------------------------------------------------------
004056AA  |.  6945 F4 E8030>imul    eax, [local.p_reg_broj[4]], 3E8         //注册码的第5位有符号乘以1000(3E8的十进制是1000)
004056B1  |.  6B55 EC 64    imul    edx, [local.p_reg_broj[2]], 64          //注册码的第3位有符号乘以100(64的十进制是100)
004056B5  |.  03C2          add     eax, edx                                //结果相加送eax
004056B7  |.  8B55 FC       mov     edx, [local.p_reg_broj[6]]              //注册码的第7位送edx
004056BA  |.  03D2          add     edx, edx                                //edx*2送edx
004056BC  |.  8D1492        lea     edx, [edx+edx*4]                        //edx*4送edx,和上步一起相当于乘了10倍,即注册码

                                                                             的第7位乘以10
004056BF  |.  03C2          add     eax, edx                                //结果相加送eax                             
004056C1  |.  0345 E4       add     eax, [local.p_reg_broj]                 //注册码的第1位加上eax的值送eax
----------------------------------------------------------------------------------------------------------------------------
上面的过程就是对注册码的奇数位进行加权运算,运算结果记做A,A=[5]*1000+[3]*100+[7]*10+[1],([5]表示注册码的第5位,以下类似)
----------------------------------------------------------------------------------------------------------------------------
004056C4  |.  6BF0 0D       imul    esi, eax, 0D                           //A*13送esi,,记做B,注意是有符号乘法,以下不再  

                                                                            特别说明
004056C7  |.  8BC6          mov     eax, esi                               //上步乘的结果B送eax                  
004056C9  |.  BE C5000000   mov     esi, 0C5                               //十进制197送esi
004056CE  |.  99            cdq                                            //此命令本人也不太懂,好象是什么协处理器指令,只

看到运行这条命令之后edx清零了,其他通用寄存器的值都没有变,有谁清楚给详细介绍以下吧
004056CF  |.  F7FE          idiv    esi                                    //B有符号除以197,商送eax,余数送edx
004056D1  |.  8BF2          mov     esi, edx                               //余数送esi,记做C
004056D3  |.  33FF          xor     edi, edi                               //edi清0
004056D5  |.  33C0          xor     eax, eax                               //eax清0,下面用做计数器
----------------------------------------------------------------------------------------------------------------------------
下面的循环将对输入的用户名进行运算
----------------------------------------------------------------------------------------------------------------------------
004056D7  |>  803C01 00     /cmp     byte ptr [ecx+eax], 0                 //检测用户名是不是输完        
004056DB  |.  74 0C         |je      short 专业扫雷.004056E9               //输完跳出循环
004056DD  |.  0FBE1401      |movsx   edx, byte ptr [ecx+eax]               //用户名的每一位以符号扩展送edx,其实送入的是其   

                                                                             ASCII码的十六进制值
004056E1  |.  03FA          |add     edi, edx                              //用户名ASCII码的十六进制值累加
004056E3  |.  40            |inc     eax                                   //计数器加1
004056E4  |.  83F8 50       |cmp     eax, 50                               //可以取80(十六进制50等于十进制80)次,有用这么长  

                                                                             的用户名吗?呵呵!
004056E7  |.^ 7C EE         \jl      short 专业扫雷.004056D7               
----------------------------------------------------------------------------------------------------------------------------
上面的循环过程对输入的用户名的每一位ASCII码的十六进制值进行累加,结果记做D,看清楚了吗?累加结果保存在edi中,我用的用户名

fuzhuhl的累加值等于306(十进制是774)
----------------------------------------------------------------------------------------------------------------------------
004056E9  |>  8BC6          mov     eax, esi                               //还记得esi中装着什么吧?对了,是余数C(不记得的可

                                                                            以看上面哦),现在把它送到eax中
004056EB  |.  51            push    ecx                                    //ecx压栈
004056EC  |.  B9 0A000000   mov     ecx, 0A                                //10送ecx
004056F1  |.  99            cdq                                            //又出来了,还是edx清0了,其他通用寄存器没有变化
004056F2  |.  F7F9          idiv    ecx                                    //C有符号除以10,商送eax,记做E,余数送edx       
004056F4  |.  59            pop     ecx                                    //ecx出栈
004056F5  |.  03C7          add     eax, edi                               //eax=D+E
004056F7  |.  BF 64000000   mov     edi, 64                                //100送edi
004056FC  |.  99            cdq                                            //又见面了,呵呵,该知道怎么了吧?
004056FD  |.  F7FF          idiv    edi                                    //eax(eax=D+E)有符号除以100,商送eax,余数送edx
004056FF  |.  8BFA          mov     edi, edx                               //余数送edi,记做F
00405701  |.  8BC6          mov     eax, esi                               //esi一直没变过,还是余数C,现在送eax
00405703  |.  BE 0A000000   mov     esi, 0A                                //10送esi
00405708  |.  99            cdq                                            //老朋友你好呀!呵呵
00405709  |.  F7FE          idiv    esi                                    //C有符号除以10,商送eax,余数送edx,记做G
0040570B  |.  8BC7          mov     eax, edi                               //余数F送eax
0040570D  |.  03C0          add     eax, eax                               //eax*2送eax
0040570F  |.  8D0480        lea     eax, [eax+eax*4]                       //eax*5送eax,和上步一起相当于乘了10
00405712  |.  03D0          add     edx, eax                               //edx=eax+G
00405714  |.  8BF2          mov     esi, edx                               //把上面加的结果送esi,记做H
----------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------
00405716  |.  6B45 F0 64    imul    eax, [local.p_reg_broj[3]], 64         //注册码的第4位有符号乘以100
0040571A  |.  8B55 E8       mov     edx, [local.p_reg_broj[1]]             // 注册码的第2位送edx
0040571D  |.  03D2          add     edx, edx                               //edx*2
0040571F  |.  8D1492        lea     edx, [edx+edx*4]                       //edx*5,和上步一起相当于edx乘了10,即注册码第2位

                                                                            乘以10
00405722  |.  03C2          add     eax, edx                               //结果相加送eax
00405724  |.  0345 F8       add     eax, [local.p_reg_broj[5]]             //注册码第6位加上eax送eax
----------------------------------------------------------------------------------------------------------------------------
上面过程对注册码的偶数位进行加权运算,运算结果记做I,I=[4]*100+[2]*10+[6]
----------------------------------------------------------------------------------------------------------------------------
00405727  |.  3BC6          cmp     eax, esi                               //关键比较,H和I的值必须相等
00405729  |.  74 1E         je      short 专业扫雷.00405749                //相等就跳到正确处,关键爆破点
0040572B  |.  68 3DC44100   push    专业扫雷.0041C43D                    ; /src = "-------"
00405730  |.  51            push    ecx                              ; |dest
00405731  |.  E8 4AF00000   call    专业扫雷.strcpy                      ; \strcpy
00405736  |.  83C4 08       add     esp, 8
00405739  |.  68 45C44100   push    专业扫雷.0041C445                    ; /src = "-------"
0040573E  |.  53            push    ebx                              ; |dest
0040573F  |.  E8 3CF00000   call    专业扫雷.strcpy                      ; \strcpy
00405744  |.  83C4 08       add     esp, 8
00405747  |.  33C0          xor     eax, eax
相等跳到这
00405749  |>  5F            pop     edi
0040574A  |.  5E            pop     esi
0040574B  |.  5B            pop     ebx
0040574C  |.  8BE5          mov     esp, ebp
0040574E  |.  5D            pop     ebp
0040574F  \.  C3            retn                                         //返回

============================================================================================================================

总结:00405727  |.  3BC6   cmp  eax, esi,  此处为关键比较
      而 eax=I
         esi={[(A*13%197)/10+774]%100}*10+(A*13%197)%10
      其中774为用户名“fuzhuhl”的每一位ASCII码的十六进制值进行累加所得结果然后转化成的十进制数
      最后别忘了al的值不能为0
本人已用C++编了个注册机程序,由于程序只是针对用户名“fuzhuhl”遍的,不具通用性,而且本人编程水平有限,用的是最笨的方法编的程

序,所以就不发上来贻笑大方了

呵呵,总算写完了,这是本人的第一篇破文,水平不高,如果有什么问题欢迎大家指正,我好及时修改,谢谢!QQ181741232

本文纯属技术交流, 转载请注明作者并保持文章的完整, 谢谢!

[2022冬季班]《安卓高级研修班(网课)》月薪三万班招生中~

上传的附件:
收藏
点赞0
打赏
分享
最新回复 (11)
雪    币: 211
活跃值: 活跃值 (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
误入楼台 活跃值 1 2006-5-3 12:10
2
0
精彩!学习!  沙发
雪    币: 190
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wayy2008 活跃值 2006-5-3 12:49
3
0
老乡,继续努力,多向你学习。
雪    币: 502
活跃值: 活跃值 (35)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
BlueT 活跃值 2 2006-5-3 15:46
4
0
你的注册码不会是:
fuzhuhl
6278889
吧?!
雪    币: 200
活跃值: 活跃值 (63)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
alphabet 活跃值 1 2006-5-3 17:23
5
0
最初由 BlueT 发布
你的注册码不会是:
fuzhuhl
6278889
吧?!


你怎么知道的?
这是一个真注册码
我做的注册机显示一个用户名可以有几百上千个符合条件的注册码
呵呵
我试了其中很多
都正确
雪    币: 435
活跃值: 活跃值 (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
花尽尘香 活跃值 2006-5-3 17:26
6
0
精彩!兄弟你学了多久了!!
能不能也教教小弟!!
小弟现在连入门者都不算
雪    币: 200
活跃值: 活跃值 (63)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
alphabet 活跃值 1 2006-5-3 17:56
7
0
最初由 花尽尘香 发布
精彩!兄弟你学了多久了!!
能不能也教教小弟!!
小弟现在连入门者都不算


心急不能吃热豆腐
从基础看起
不要起点太高
会搞得自己没有信心的
看雪有很多基础的东西
有时间用心的看
会有收获的
雪    币: 202
活跃值: 活跃值 (26)
能力值: ( LV13,RANK:1250 )
在线值:
发帖
回帖
粉丝
冲天剑 活跃值 31 2006-5-3 20:26
8
0
cdq是把双字eax扩充为四字edx:eax的指令,它所做的工作是把eax的最高二进制位填入edx的每一位。因为32位的idiv隐含用edx:eax做除数,在相除之前往往使用这条指令。

另外没必要写那么多注释,关键几处注释一下,起到提示自己的作用就可以了,象什么“10送ecx,”之类都是毫无意义的注释,写上去不但没有帮助,反而会干扰对程序的理解。

我本来是想写这个,因为想起别的事,一时忘了
雪    币: 200
活跃值: 活跃值 (63)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
alphabet 活跃值 1 2006-5-3 21:23
9
0
最初由 冲天剑 发布
cdq是把双字eax扩充为四字edx:eax的指令,它所做的工作是把eax的最高二进制位填入edx的每一位。因为32位的idiv隐含用edx:eax做除数,在相除之前往往使用这条指令。



另外没必要写那么多注释,关键几处注释一下,起到提示自己的作用就可以了,象什么“10送ecx,”之类都是毫无意义的注释,写上去不但没有帮助,反而会干扰对程序的理解。


呵呵
谢谢了
昨天晚上看到了CDQ指令,结果看cdq时却不认得了,心里一直以为是cdp,呵呵

"idiv隐含用edx:eax做除数"
做被除数吧?

多谢指点破文的写法,以后会继续努力的
雪    币: 204
活跃值: 活跃值 (10)
能力值: ( LV9,RANK:290 )
在线值:
发帖
回帖
粉丝
紫色缘 活跃值 7 2006-5-3 21:32
10
0
写的非常精彩!学习
雪    币: 502
活跃值: 活跃值 (35)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
BlueT 活跃值 2 2006-5-4 08:30
11
0
最初由 alphabet 发布
你怎么知道的?
这是一个真注册码
我做的注册机显示一个用户名可以有几百上千个符合条件的注册码
呵呵
我试了其中很多
........


我随意计算的一个。每个名称大概可以计算出10^4个注册码。属于一对多的情况。
雪    币: 152
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
微微虫 活跃值 2006-5-5 14:11
12
0
收下,学习一下!
请问一下:[local.p_reg_broj
  • ] 怎么出来的?
  • 我的 Ollydbg里显示的是:[ebp-*]

    I can do it!
    游客
    登录 | 注册 方可回帖
    返回