吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 19642|回复: 39
收起左侧

[原创] 初练160个CrakeMe程序之006

  [复制链接]
海天一色001 发表于 2017-5-23 13:48
本帖最后由 海天一色001 于 2017-5-23 15:27 编辑

第六个CM,还是先运行一下看看:
1.png
这个程序一看又是用户/注册码类型的,加一个“about help”按钮干什么?点上去看看,连着出现四个提示窗口,傻眼了!
2.png

3.png

4.png

5.png
找度娘!一个个查找单词翻译吧!
The purpose of this CrackMe v.1.00 by aLoNg3x is to MAKE INVISIBLE the buttons "OK" and "Cancella" in order to see the Ringzer0 logo. So you must insert the correct codes.
这个aLoNg3x制作的CrackMe v.1.00的目标是让"OK"和"Cancella"按键隐藏来看到Ringzer0 logo。因此你必须输入正确的注册码。

Nota: if the buttons does NOT become invisible,then you have NOT cracked this Crackme:)
注意:如果按钮没有变成隐藏,那么你没有破解这个Crackme

If you need some helps e-mail me or if you solve this protection please write me your solution,Many thanks.
如果你需要帮助请给我发邮件或者如果你解决了这个保护请写信给我你的解决方法,非常感谢。

CrackMe v.1.00 written by “aLoNg3x” E-MAIL: albatro@freemail.it; member of “Ringzer0” http://ringzer0.cjb.net
CrackMe v.1.00aLoNg3x编写。E-MAIL: albatro@freemail.it; member of “Ringzer0” http://ringzer0.cjb.net

可能翻译不够准确,大致意思是说不能爆破,只允许输入正确的注册码来隐藏两个按钮。
查壳,天啊,又是这种Delphi程序!说实话,我只是学了一个最最基本的Basic而已,怎么老是要破Delphi!太头疼了!可是头疼也没办法,想学习破解,编程语言是绕不过去的坎啊!不求精通,只求了解,先满足当前需要就行!
6.png
看着界面上的英文,怎么这么别扭呢?汉化一下先!用论坛的工具包里的好几个软件来修改标题、版权之类,总是失败,直到找到了ResScope,才将主界面上的英文改成了汉字。
7.png
将图中所有
Caption(也就是标题或者叫名字)的地方的内容全部修改成自己想改的东东,点击保存的图标,再点击运行的绿三角进行查看,我修改好后的程序界面如下:
8.png
但是这个软件没法修改弹出的消息框,再用OD来修改:
OD导入CM006.exe,搜索字符串,向下查找,看到了消息框中的内容了!这里有三个,还有一个,暂时先不管它,先修改了这三个以后再找。
9.png
点击第一句提示,进入
CPU窗口,
10.png
哈哈,这里四句消息内容都有了,不需要再去找第四句了!
11.png
00442F51地址处右键选择数据窗口跟随---立即数:
12.png
此时的数据窗口已经到了这四句消息内容的地址:
13.png
选中ASCII行中的内容,快捷键“Ctrl+E”,或者右键选二进制编辑:
14.png
ASCII栏中输入想修改的内容,此时显示是一堆乱码,不要紧,只要确定自己修改的内容对就行,如果修改后的内容长度不够,后面可以用二进制“00”填充,下面保持大小也一定选上,保证不超出原来的内容长度即可。编辑完成,先选中所有修改的内容,右键选择“复制到可执行文件”,在新的窗口中仍是右键选中的内容选择“保存文件”,生成新的exe文件。
15.png     16.png
我的新文件是CM006_1.exe,运行一下,点击“关于-帮助”,嗯,成功了,消息框的内容也改了。但是还有标题和“OK”按键还未修改,而且修改后的内容排版很难看:
17.png

18.png

19.png

20.png
我感觉用OD来做汉化,效率还是很低的,还容易出错,盼望哪位大神做一个插件,针对这个问题来解决一下。如果有更好的汉化方法,也请坛友们多指教,这些就这样了! 接下来就是破解了。因为已经是第三个Delphi程序了,所以还是用Dede:
21.png
22.png
代码复制出来,如下,图片代码太长,中间用“.........”代替了:
[Delphi] 纯文本查看 复制代码
object _Nome: TLabel
    Left = 8
    Top = 8
    Width = 31
    Height = 13
    Caption = '用户名:'
  end
  object _Codice: TLabel
    Left = 8
    Top = 32
    Width = 36
    Height = 13
    Caption = '注册码:'
  end
  object Pannello: TPanel
    Left = 0
    Top = 64
    Width = 292
    Height = 68
    Align = alBottom
    BevelOuter = bvLowered
    TabOrder = 0
    object Image1: TImage
      Left = 1
      Top = 1
      Width = 290
      Height = 66
      Align = alClient
      Picture.Data = {
        07544269746D617076870000424D76870000000000003604000028000000BF01
      ..................................................................................................................................  
        0C00}
      Stretch = True
    end
    object Ok: TButton
      Left = 24
      Top = 16
      Width = 113
      Height = 41
      Caption = '确定¨'
      Enabled = False
      TabOrder = 0
      OnClick = OkClick
    end
    object Cancella: TButton
      Left = 152
      Top = 16
      Width = 113
      Height = 41
      Caption = '清除注册码'
      TabOrder = 1
      OnClick = CancellaClick
    end
  end
  object Nome: TEdit
    Left = 56
    Top = 8
    Width = 89
    Height = 21
    MaxLength = 10
    TabOrder = 1
    OnChange = NomeChange
  end
  object Codice: TEdit
    Left = 56
    Top = 32
    Width = 89
    Height = 21
    TabOrder = 2
    Text = '0'
    OnChange = CodiceChange
  end
  object About: TButton
    Left = 168
    Top = 8
    Width = 105
    Height = 49
    Caption = '1关于 – 帮助'
    TabOrder = 3
    OnClick = AboutClick
  End

看到了上面的事件名称,有10个啊!结合ResScope中看到的代码,基本确定用户名最大长度为10个字符,输入字符的事件是“NomeChange”;“CodiceChange”事件是注册码输入;“CancellaClick”事件是点击“清除注册码”的代码;“确定”按钮的Enabled属性 = False,也就是灰色的不可用状态,“OkClick”是点击“确定”按钮后的事件,“AboutClick”是点击“关于-帮助”按钮的事件。其他5个目前不知道是什么东东,先放一边去。
从消息框中猜知程序正确的流程应该是要输入正确的注册码后,确定按钮变可用,点击后将自己和清除注册码这两个按键隐藏,显示出那个logo来,所以应该在判断用户名和注册码关系后不管怎样都跳到确定按钮可用的代码处,仍然能爆破,还是先试一试爆破吧!
猜测这仍是要利用用户名和用户名长度来计算注册码的,所以记下这几个事件开头的地址,在OD中Ctrl+E来查看相关代码:
NomeChange事件感觉是作者将name中的“a”拼写错误成了“o”,除了个长度限制外,在OD中没有看到其他有用的东东。
再来看CodiceChange事件:结合Darkde4中的提示,对OD中的代码进行注释:进入OD,Ctrl+E,到达地址00442C78处,注释写上“注册码输入事件段首”,再看Darkde4中在00442C88和00442C8D之间有个注释“***** TRY”,复制下来,在OD中加到哪个地址后面呢?仔细看看,觉得应该是对00442C8D地址处的注释,也不知对不对,先按照自己的想法来吧,大不了错了再改到上一句地址处!!!
23.png
就这样一路复制粘贴,CodiceChange事件很快就注释完毕,再结合自己的理解,加上段尾的注释;看到OD中下面的代码,又到了确定按钮事件的段首,干脆将这些事件全部注释一下算了!这个工作也很快完成!!!
直到这里,我才确定自己这样注释是正确的!
[Asm] 纯文本查看 复制代码
00442F4C   .  B8 802F4400   mov eax,CM006_1.00442F80                 ;  ASCII "这个由aLoNg3x制作的CM的目标是隐藏“确定和清除注册码这两个按钮使Ringzer0 logo显示出来。因此你必须输入"
00442F51   .  E8 9AF6FFFF   call CM006_1.004425F0                    ;  * Reference to: dialogs.ShowMessage(AnsiString);
00442F56   .  B8 34304400   mov eax,CM006_1.00443034                 ;  注意:如果这两个按钮没有被隐藏,那么你就没有破解这个Crackme
00442F5B   .  E8 90F6FFFF   call CM006_1.004425F0                    ;  * Reference to: dialogs.ShowMessage(AnsiString);
00442F60   .  B8 98304400   mov eax,CM006_1.00443098                 ;  如果你需要帮助请给我发 e-mail 或者你解决了它的保护,请写信给我告诉你的解决方法。非常感谢。
00442F65   .  E8 86F6FFFF   call CM006_1.004425F0                    ;  * Reference to: dialogs.ShowMessage(AnsiString);
00442F6A   .  B8 0C314400   mov eax,CM006_1.0044310C                 ;  CrackMe v. 1.00 由aLoNg3x编写。 我的 E-MAIL: [url=mailto:albatro@freemail.it]albatro@freemail.it[/url] ; member of "Ringzer0" URL: http://ringzer0.cjb.net
00442F6F   .  E8 7CF6FFFF   call CM006_1.004425F0                    ;  * Reference to: dialogs.ShowMessage(AnsiString);

其他几个也这样复制,复制这些注释时发现,在输入用户名、输入注册码和确定按钮事件、清除注册码事件的代码段中有很多代码是一样的,说明作用也是一样。再结合上两个CM程序的练习,猜测这个程序也是在输入用户名时就开始判断注册码是否正确了。
在用户名输入代码段首00442E04处下断,F9运行程序,将“52pojie.cn”粘贴到用户名中,程序马上中断。单步运行,到00442E22处是一个比较,下一句的跳转跳过了确定按钮可用,所以nop掉,再F9运行,此时确定按钮已经是可用状态了。
24.png
先将这一步保存,另存为cm006_1_name_nop.exe,以备下一步使用;
再在注册码输入事件段首地址00442C78处F2下断,F9运行程序,在注册码文本框中刚输入“1”,程序就断下来了,此时确定按钮是可用状态,程序还未来得及判断注册码真假;直接F9运行,此时的确定按钮已变成不可用了!说明只要开始输入注册码,程序就开始判断,不正确,那么确定按钮就被设置成不可用。
25.png          26.png            
因为“1”在程序中可能有很多处,一时半会可能找不到地方,在记事本中输入一串“1234567890”,复制过来作为注册码,马上断在了注册码输入事件段首处:
27.png
F8单步向下,来到00442CA1这里,指令是mov eax,[local.2] ,从信息栏中看到“堆栈 ss:[0012F3DC]=00945E48, (ASCII "1234567890") eax=0000000A”;这一句是取注册码的;继续单步到下一句00442CA7地址处,call CM006_1.00402958,从复制过来的注释(* Reference to: system.@ValLong;)猜测是一个得到整数类型变量的子程序;再单步向下,一直到本段结束,再F9一下,程序界面中没有可看出的任何变化。
本段中其他的call从Dede中的注释能看出都有明确的作用,如TLabel,Tcaption,TButton等控件或事件(过程)的名称、作用之类,只有这个0042D0B处的指令“call CM006_1.00442A3C”,Darkde4中的注释是“* Reference to : TPrincipale._PROC_00442A3C()”,看不出来有什么作用,只能说是一个子程序,很有可能就是关键call了!
来到地址00442CAE处,此处是一个比较指令cmp [local.1],0x0 ,是本代码段中第一个判断,作用是什么呢???(注册码与默认0比较,如为0时就跳过,程序进入错误的流程,确定按钮不可用),所以下一句的跳转指令可以nop掉试试:
28.png
00442CB2处je short CM006_1.00442CCC被nop掉后,F9运行程序,仍是没有变化,说明只nop这一句不行;
重新复制注册码,又断在段首,认真地分析一下本段的代码,00442CDA -00442CE2处、00442D16-00442D1E处和00442D25-00442D2D处的三段指令完全一样,注释中可以看出是关于“确定(OK)”按钮的,猜测是关于按钮enble属性的地方,前两代码处前一个指令是“mov dl,0x1”,说明edx=1,后面一处代码前一条指令是“xor edx,edx”,说明是edx=0,可能edx的值是设置按钮可用不可用的关键,就是不知道0和1哪个是可用,哪个是不可用。
复制注册码,程序断下,然后从段首单步向下,到达00442CD2处,是本段代码的第二个判断,接下来又要跳走,ds:[eax+0x47]还是不知从哪里赋的值:
29.png
00442CD6处指令为“jnz short CM006_1.00442CE7 ”,不等则跳,将指令nop掉;
F8向下,到00442CE5处,“jmp short CM006_1.00442D30”,无条件跳转:继续单步走,很快到达了段尾,于是F9,再看程序界面,确定按钮又是可用状态了,说明这两个nop爆破是正确的;
30.png
此时确定按钮可用,再将修改后的程序保存一下,命名为CM006_1_code_nop.exe备用;
下一步就应该是点击确定,如果用户名和注册码正确,则两个按钮均会隐藏起来,那么就在确定按钮事件段首下断后,点击确定:
程序断在了00442D64处。F8向下,到00442D80处,指令是“cmp byte ptr ds:[eax+0x47],0x1”,与注册码输入事件中不同之处是与1比较!
31.png
再往下观察这段代码,感觉与上面输入用户名、输入注册码事件的代码很相似,作用也应该相似,那么先不管与1或是0比较,同样在jnz处nop掉,单步继续,到00442D91处,F8,忽然又断在了注册码输入事件的段首!说明刚才的call可能是对注册码进行判断之后认为是假码,然后设注册码为默认值0。因断点都还在,所以才又断在了注册码输入事件的段首。
此时F9运行,返回到00442D96处,又一个跳转!我注释了一下,是跳过了setvisible,应该跳吗?
因为跳过了设置不可见,所以这里要先nop掉,不能跳!
33.png
继续单步向下,到地址00442DC8处,又是跳到00442DD7的指令,要跳过设置按钮不可见:
34.png
刚才已nop了到00442DD7这个地址的跳,现在也不例外,继续nop掉:
35.png
然后单步向下,来到了确定按钮事件的段尾,此时F9运行,确定按钮隐藏了,但清除注册码按钮还在,说明自己开始的想法不对,点一个确定不能隐藏两个按钮。
36.png
那么在清除注册码事件里看看:
返回OD,Ctrl+E,输入00442EA8,F2在清除注册码按钮事件段首下断:
37.png
在CM程序中点击清除注册码按钮,在OD中已经断下来了,F8走的过程中看到信息栏中有用户名和注册码的出现,说明也有什么算法要用到这两个参数,但我要爆破,就先放过去了。
来到00442EE7 处,以下代码就很熟悉了,call CM006_1.00442AF4,先是关键call进行计算,返回eax中,再比较,跳转!
38.png
把00442EEE处的跳转指令也nop掉!再单步向下,又有了一个jmp,观察了一下,不动它,继续单步到清除注册码按钮事件段尾,F9,在CM程序中的清除按钮也没有了!
39.png
赶紧将此时修改好的程序再保存一下,命名为CM006_1_nop.exe。打开CM006_1_nop.exe,试运行一下,一切正常,按两个按钮均能隐藏。而且不管在哪个文本框中输入,或是点击清除注册码按钮,确定按钮都会变得可用,不管先点击哪个按钮,哪个按钮就会隐藏,爆破成功!也有一个小问题,点击确定按钮后,注册码会重置成0,还需要下一步看看是怎么回事。
接下来追码。要找注册算法,这是太令人头疼的事!上面的爆破都费了九牛二虎之力才成功,算法???
自己认为程序流程是输入用户名、注册码,确定按钮可用;点击确定按钮,使确定按钮隐藏;再点击清除注册码按钮,则注册码按钮也隐藏,这样程序就算破解成功了。所以要先从用户名输入事件入手:
关闭程序,重新载入OD,将断点除用户名输入的段首地址外全部禁用,F9运行,将“52pojie.cn”复制入文本框中,程序中断,开始分析:
[Asm] 纯文本查看 复制代码
00442E04  /.  55                  push ebp                                 ;  用户名输入代码段首
00442E05  |.  8BEC                mov ebp,esp
00442E07  |.  6A 00               push 0x0
00442E09  |.  6A 00               push 0x0
00442E0B  |.  53                  push ebx
00442E0C  |.  8BD8                mov ebx,eax
00442E0E  |.  33C0                xor eax,eax
00442E10  |.  55                  push ebp
00442E11  |.  68 9B2E4400         push CM006_1.00442E9B
00442E16  |.  64:FF30             push dword ptr fs:[eax]                  ;  ***** TRY
00442E19  |.  64:8920             mov dword ptr fs:[eax],esp
00442E1C  |.  8B83 D0020000       mov eax,dword ptr ds:[ebx+0x2D0]         ;  清除注册码按钮事件
00442E22  |.  8078 47 00          cmp byte ptr ds:[eax+0x47],0x0           ;  ds:[eax+0x47]的值决定了跳转,那么它在什么地方被赋值的?
00442E26      75 0F               jnz short CM006_1.00442E37               ;  跳到了确定按钮不可用,nop后使确定按钮可用了
00442E28  |.  B2 01               mov dl,0x1                               ;  dl=1则确定按钮可用
00442E2A  |.  8B83 CC020000       mov eax,dword ptr ds:[ebx+0x2CC]         ;  确定按钮事件
00442E30  |.  8B08                mov ecx,dword ptr ds:[eax]               ;  CM006_1.0044282C
00442E32  |.  FF51 60             call dword ptr ds:[ecx+0x60]
00442E35  |.  EB 49               jmp short CM006_1.00442E80
00442E37  |>  8D55 FC             lea edx,[local.1]
00442E3A  |.  8B83 E0020000       mov eax,dword ptr ds:[ebx+0x2E0]         ;  * Reference to control Codice : TLabel
00442E40  |.  E8 7B04FEFF         call CM006_1.004232C0                    ;  * Reference to: controls.TControl.GetText(TControl):TCaption;
00442E45  |.  8B45 FC             mov eax,[local.1]                        ;  取注册码
00442E48  |.  50                  push eax
00442E49  |.  8D55 F8             lea edx,[local.2]
00442E4C  |.  8B83 DC020000       mov eax,dword ptr ds:[ebx+0x2DC]         ;  * Reference to control Nome : TLabel
00442E52  |.  E8 6904FEFF         call CM006_1.004232C0                    ;  * Reference to: controls.TControl.GetText(TControl):TCaption;
00442E57  |.  8B45 F8             mov eax,[local.2]                        ;  取用户名
00442E5A  |.  5A                  pop edx                                  ;  CM006_1.0041E13E
00442E5B  |.  E8 DCFBFFFF         call CM006_1.00442A3C                    ;  关键call,计算后返回al
00442E60  |.  84C0                test al,al
00442E62  |.  74 0F               je short CM006_1.00442E73
00442E64  |.  B2 01               mov dl,0x1                               ;  dl=1时,确定按钮可用
00442E66  |.  8B83 CC020000       mov eax,dword ptr ds:[ebx+0x2CC]         ;  确定按钮事件
00442E6C  |.  8B08                mov ecx,dword ptr ds:[eax]               ;  CM006_1.0044282C
00442E6E  |.  FF51 60             call dword ptr ds:[ecx+0x60]
00442E71  |.  EB 0D               jmp short CM006_1.00442E80
00442E73  |>  33D2                xor edx,edx                              ;  edx=0,确定按钮不可用
00442E75  |.  8B83 CC020000       mov eax,dword ptr ds:[ebx+0x2CC]         ;  * Reference to control Ok : TButton确定按钮事件
00442E7B  |.  8B08                mov ecx,dword ptr ds:[eax]               ;  CM006_1.0044282C
00442E7D  |.  FF51 60             call dword ptr ds:[ecx+0x60]
00442E80  |>  33C0                xor eax,eax
00442E82  |.  5A                  pop edx                                  ;  CM006_1.0041E13E
00442E83  |.  59                  pop ecx                                  ;  CM006_1.0041E13E
00442E84  |.  59                  pop ecx                                  ;  CM006_1.0041E13E
00442E85  |.  64:8910             mov dword ptr fs:[eax],edx
00442E88  |.  68 A22E4400         push CM006_1.00442EA2                    ;  ****** FINALLY
00442E8D  |>  8D45 F8             lea eax,[local.2]
00442E90  |.  BA 02000000         mov edx,0x2
00442E95  |.  E8 4209FCFF         call CM006_1.004037DC
00442E9A  \.  C3                  retn                                     ;  用户名输入事件段尾
00442E9B   .^ E9 D803FCFF         jmp CM006_1.00403278
00442EA0   .^ EB EB               jmp short CM006_1.00442E8D
00442EA2   .  5B                  pop ebx                                  ;  ****** END
00442EA3   .  59                  pop ecx                                  ;  CM006_1.0041E13E
00442EA4   .  59                  pop ecx                                  ;  CM006_1.0041E13E
00442EA5   .  5D                  pop ebp                                  ;  CM006_1.0041E13E
00442EA6   .  C3                  retn

单步到00442E1C地址处,指令是mov eax,dword ptr ds:[ebx+0x2D0],这是清除注册码按钮事件的代码,说明输入用户名时,清除注册码按钮已经正常出现;再到00442E26地址处,在爆破时将本行跳转指令nop掉了,现在正常执行,转到了00442E37处;再继续到00442E40处,指令“call CM006_1.004232C0”经猜测验证是得到输入的字符串及字符串的长度,此处是得到默认的注册码0及长度0x1;而到00442E52处,得到的是输入的用户名及用户名长度;
再到达00442E5B处,指令是“call CM006_1.00442A3C”,爆破时猜测是关键call,返回值存入al。现在就要F7跟入:
[Asm] 纯文本查看 复制代码
00442A3C      55                  push ebp                                 ;  第一个关键子程序
00442A3D  |.  8BEC                mov ebp,esp
00442A3F  |.  83C4 F8             add esp,-0x8
00442A42  |.  53                  push ebx
00442A43  |.  56                  push esi
00442A44  |.  8955 F8             mov [local.2],edx                        ;  注册码存入堆栈ss:[local.2]中
00442A47  |.  8945 FC             mov [local.1],eax                        ;  用户名存入堆栈SS:[local.1]中
00442A4A  |.  8B45 FC             mov eax,[local.1]                        ;  取用户名
00442A4D  |.  E8 9611FCFF         call CM006_1.00403BE8                    ;  计数CALL,返回edx?
00442A52  |.  8B45 F8             mov eax,[local.2]                        ;  取注册码
00442A55  |.  E8 8E11FCFF         call CM006_1.00403BE8                    ;  edx从2变1再到2????
00442A5A  |.  33C0                xor eax,eax
00442A5C  |.  55                  push ebp
00442A5D  |.  68 E52A4400         push CM006_1.00442AE5
00442A62  |.  64:FF30             push dword ptr fs:[eax]
00442A65  |.  64:8920             mov dword ptr fs:[eax],esp
00442A68  |.  8B45 FC             mov eax,[local.1]                        ;  取用户名
00442A6B  |.  E8 C40FFCFF         call CM006_1.00403A34                    ;   @LStrLen,取字符串长度
00442A70  |.  83F8 05             cmp eax,0x5                              ;  检测用户名长度是否5位以上
00442A73  |.  7E 53               jle short CM006_1.00442AC8               ;  不大于则跳,确定按钮不可用
00442A75  |.  8B45 FC             mov eax,[local.1]                        ;  取用户名
00442A78  |.  E8 B70FFCFF         call CM006_1.00403A34                    ;  取字符串长度
00442A7D  |.  8BD8                mov ebx,eax
00442A7F  |.  8B45 FC             mov eax,[local.1]                        ;  取用户名
00442A82  |.  E8 AD0FFCFF         call CM006_1.00403A34
00442A87  |.  8BD0                mov edx,eax                              ;  edx=用户名长度
00442A89  |.  4A                  dec edx
00442A8A  |.  85D2                test edx,edx                             ;  test是与运算,只影响标志位,执行该语句后,如edx值不等于0(zr=0),则不跳:检测edx寄存器是否为0,0则跳
00442A8C  |.  7E 20               jle short CM006_1.00442AAE               ;  不大于则跳
00442A8E  |.  B8 01000000         mov eax,0x1                              ;  eax=1,循环的第一个序号为1
00442A93  |>  8B4D FC             /mov ecx,[local.1]                       ;  取用户名
00442A96  |.  0FB64C01 FF         |movzx ecx,byte ptr ds:[ecx+eax-0x1]     ;  ecx的值是所取的1个字符的ASCII的16进制值
00442A9B  |.  8B75 FC             |mov esi,[local.1]                       ;  取用户名
00442A9E  |.  0FB63406            |movzx esi,byte ptr ds:[esi+eax]         ;  esi的值是刚取的字符后1个字符的16进制值
00442AA2  |.  0FAFCE              |imul ecx,esi                            ;  ecx=ecx*esi
00442AA5  |.  0FAFC8              |imul ecx,eax                            ;  ecx=ecx*eax
00442AA8  |.  03D9                |add ebx,ecx                             ;  ebx=ebx+ecx
00442AAA  |.  40                  |inc eax                                 ;  eax=eax+1,eax累加1
00442AAB  |.  4A                  |dec edx                                 ;  edx=edx-1
00442AAC  |.^ 75 E5               \jnz short CM006_1.00442A93              ;  循环,对用户名进行处理
00442AAE  |>  8B45 F8             mov eax,[local.2]                        ;  取注册码
00442AB1  |.  E8 BA4BFCFF         call CM006_1.00407670                    ;  StrToInt,字符串转成16进制数值,返回eax中
00442AB6  |.  2BD8                sub ebx,eax                              ;  用户名处理的结果减去注册码处理的结果是否等于0x29A
00442AB8  |.  81FB 9A020000       cmp ebx,0x29A                            ;  比较
00442ABE  |.  75 04               jnz short CM006_1.00442AC4               ;  跳过可用,使ebx清零
00442AC0  |.  B3 01               mov bl,0x1                               ;  可用
00442AC2  |.  EB 06               jmp short CM006_1.00442ACA               ;  跳至eax清零
00442AC4      33DB                xor ebx,ebx                              ;  不可用
00442AC6  |.  EB 02               jmp short CM006_1.00442ACA
00442AC8  |>  33DB                xor ebx,ebx
00442ACA  |>  33C0                xor eax,eax
00442ACC  |.  5A                  pop edx                                  ;  CM006_1.00442E60
00442ACD  |.  59                  pop ecx                                  ;  CM006_1.00442E60
00442ACE  |.  59                  pop ecx                                  ;  CM006_1.00442E60
00442ACF  |.  64:8910             mov dword ptr fs:[eax],edx
00442AD2  |.  68 EC2A4400         push CM006_1.00442AEC
00442AD7  |>  8D45 F8             lea eax,[local.2]
00442ADA  |.  BA 02000000         mov edx,0x2
00442ADF  |.  E8 F80CFCFF         call CM006_1.004037DC
00442AE4  \.  C3                  retn
00442AE5   .^ E9 8E07FCFF         jmp CM006_1.00403278
00442AEA   .^ EB EB               jmp short CM006_1.00442AD7
00442AEC   .  8BC3                mov eax,ebx
00442AEE   .  5E                  pop esi                                  ;  CM006_1.00442E60
00442AEF   .  5B                  pop ebx                                  ;  CM006_1.00442E60
00442AF0   .  59                  pop ecx                                  ;  CM006_1.00442E60
00442AF1   .  59                  pop ecx                                  ;  CM006_1.00442E60
00442AF2   .  5D                  pop ebp                                  ;  CM006_1.00442E60
00442AF3   .  C3                  retn

分析后得出结论,如果输入的注册码=用户名经循环处理后得到的一个16进制数值-16进制数值29A,将bl设为1,从而使确定按钮可用:
用VB编写从用户名计算出注册码的代码(直接将16进制数转换成10进制了)如下:
Serial= Len(name)
Serial = Serial +asc (mid(name,1,1)*asc(mid(name,2,1)*1+ asc(mid(name,2,1)*asc(mid(name,3,1)*2+...+ asc (mid(name,Len(name)-1,1)*asc (mid(name,Len(name),1)*( Len(name)-1)
Serial = Serial -666
用计算器计算了一下,用户名为“52pojie.cn”,循环处理后的结果为0x5DDD0,减去0x29A,结果为0x5DB36 ,转换成10进制数为383798。复制这个结果,继续单步走,这个关键子程序返回到00442E60处,因注册码是默认的0,所以eax=0,使确定按钮为灰色不可用状态。继续F8,直到运行到用户名输入事件结束,再F9运行,程序此时的状态如下左图:
42.png              43.png          
将刚才复制的注册码粘贴入注册码文本框中,确定按钮可用了!(如上右图)
在OD中禁用用户名输入事件的断点,激活注册码输入事件断点,重新粘贴一遍注册码,程序中断:
[Asm] 纯文本查看 复制代码
00442CE7  |>  8D55 F8       lea edx,[local.2]
00442CEA  |.  8B83 E0020000 mov eax,dword ptr ds:[ebx+0x2E0]              ;  * Reference to control Codice : TLabel
00442CF0  |.  E8 CB05FEFF   call CM006_1.004232C0                         ;  * Reference to: controls.TControl.GetText(TControl):TCaption;
00442CF5  |.  8B45 F8       mov eax,[local.2]                             ;  取假码
00442CF8  |.  50            push eax
00442CF9  |.  8D55 F0       lea edx,[local.4]
00442CFC  |.  8B83 DC020000 mov eax,dword ptr ds:[ebx+0x2DC]              ;  * Reference to control Nome : TLabel
00442D02  |.  E8 B905FEFF   call CM006_1.004232C0                         ;  * Reference to: controls.TControl.GetText(TControl):TCaption;
00442D07  |.  8B45 F0       mov eax,[local.4]                             ;  eax=用户名
00442D0A  |.  5A            pop edx                                       ;  0012F6F4
00442D0B  |.  E8 2CFDFFFF   call CM006_1.00442A3C                         ;  * Reference to : TPrincipale._PROC_00442A3C(),猜测是计算并比较注册码
00442D10  |.  84C0          test al,al                                    ;  eax的值很重要!!!!
00442D12  |.  74 0F         je short CM006_1.00442D23
00442D14  |.  B2 01         mov dl,0x1                                    ;  edx=1时确定按钮可用
00442D16  |.  8B83 CC020000 mov eax,dword ptr ds:[ebx+0x2CC]              ;  * Reference to control Ok : TButton
00442D1C  |.  8B08          mov ecx,dword ptr ds:[eax]
00442D1E  |.  FF51 60       call dword ptr ds:[ecx+0x60]
00442D21  |.  EB 0D         jmp short CM006_1.00442D30
00442D23  |>  33D2          xor edx,edx
                                   ;
单步向下,遇到的几个跳转指令时也仔细看了半天,分析流程,才让它继续下去,一直到本段代码结束,再F9运行,程序状态没有变化。
反复观察本段代码,并与用户名输入事件代码比较,看到整体流程与用户名输入事件一样,一输入字符就开始判断,而且也用了call CM006_1.00442A3C这个关键call,所以使用计算出的注册码会使确定按钮可用。
此时再禁用注册码输入事件的断点,激活确定按钮事件断点,点击确定按钮,程序又中断:
[Asm] 纯文本查看 复制代码
00442D64  /.  55                  push ebp                                 ;  确定按钮事件段首
00442D65  |.  8BEC                mov ebp,esp
00442D67  |.  6A 00               push 0x0
00442D69  |.  53                  push ebx
00442D6A  |.  8BD8                mov ebx,eax
00442D6C  |.  33C0                xor eax,eax
00442D6E  |.  55                  push ebp
00442D6F  |.  68 ED2D4400         push CM006_1.00442DED
00442D74  |.  64:FF30             push dword ptr fs:[eax]                  ;  ***** TRY
00442D77  |.  64:8920             mov dword ptr fs:[eax],esp
00442D7A  |.  8B83 D0020000       mov eax,dword ptr ds:[ebx+0x2D0]         ;  * Reference to control Cancella : TButton(清除注册码按钮)
00442D80  |.  8078 47 01          cmp byte ptr ds:[eax+0x47],0x1           ;  此处与注册码输入事件中不同之处是与1比较
00442D84      75 12               jnz short CM006_1.00442D98
00442D86  |.  BA 002E4400         mov edx,CM006_1.00442E00                 ;  0
00442D8B  |.  8B83 E0020000       mov eax,dword ptr ds:[ebx+0x2E0]         ;  * Reference to control Codice : TLabel
00442D91  |.  E8 5A05FEFF         call CM006_1.004232F0                    ;  * Reference to: controls.TControl.SetText(TControl;TCaption);
00442D96      EB 3F               jmp short CM006_1.00442DD7               ;  跳过了TControl.SetVisible,应该跳吗?
00442D98      8D55 FC             lea edx,dword ptr ss:[ebp-0x4]
00442D9B  |.  8B83 E0020000       mov eax,dword ptr ds:[ebx+0x2E0]         ;  * Reference to control Codice : TLabel
00442DA1  |.  E8 1A05FEFF         call CM006_1.004232C0                    ;  * Reference to: controls.TControl.GetText(TControl):TCaption;
00442DA6  |.  8B45 FC             mov eax,[local.1]
00442DA9  |.  E8 C248FCFF         call CM006_1.00407670                    ;  * Reference to: sysutils.StrToInt(S:
00442DAE  |.  50                  push eax
00442DAF  |.  8D55 FC             lea edx,[local.1]
00442DB2  |.  8B83 DC020000       mov eax,dword ptr ds:[ebx+0x2DC]         ;  * Reference to control Nome : TLabel
00442DB8  |.  E8 0305FEFF         call CM006_1.004232C0                    ;  * Reference to: controls.TControl.GetText(TControl):TCaption;
00442DBD  |.  8B45 FC             mov eax,[local.1]                        ;  取用户名
00442DC0  |.  5A                  pop edx                                  ;  取注册码?????
00442DC1  |.  E8 DAFDFFFF         call CM006_1.00442BA0                    ;  * Reference to : TPrincipale._PROC_00442BA0()关键call
00442DC6  |.  84C0                test al,al
00442DC8      74 0D               je short CM006_1.00442DD7
00442DCA  |.  33D2                xor edx,edx
00442DCC  |.  8B83 CC020000       mov eax,dword ptr ds:[ebx+0x2CC]         ;  * Reference to control Ok : TButton
00442DD2  |.  E8 D903FEFF         call <CM006_1.SetVisible>                ;  * Reference to: controls.TControl.SetVisible(TControl;Boolean);确定按钮是否可见的call
00442DD7  |>  33C0                xor eax,eax
00442DD9  |.  5A                  pop edx                                  ;  0012F24C
00442DDA  |.  59                  pop ecx                                  ;  0012F24C
00442DDB  |.  59                  pop ecx                                  ;  0012F24C
00442DDC  |.  64:8910             mov dword ptr fs:[eax],edx
00442DDF  |.  68 F42D4400         push CM006_1.00442DF4                    ;  ****** FINALLY
00442DE4  |>  8D45 FC             lea eax,[local.1]
00442DE7  |.  E8 CC09FCFF         call CM006_1.004037B8
00442DEC  \.  C3                  retn                                     ;  确定按钮事件段尾
00442DED   .^ E9 8604FCFF         jmp CM006_1.00403278
00442DF2   .^ EB F0               jmp short CM006_1.00442DE4
00442DF4   .  5B                  pop ebx                                  ;  ****** END
00442DF5   .  59                  pop ecx                                  ;  0012F24C
00442DF6   .  5D                  pop ebp                                  ;  0012F24C
00442DF7   .  C3                  retn

单步到00442D80处,指令是“cmp byte ptr ds:[eax+0x47],0x1”,注册码输入事件中是与0比较,此处是与1比较!这个比较应该也是一个关键的比较吧。两个事件中均有这种比较,然后跳走,说明程序在不同的流程下结果不同,就是不知道这些类似ds:[eax+0x47]、 [local.1]之类的堆栈表示什么东西,是如何赋值的?这也算是下一步学习的一个关键疑点吧!
40.png
下一句的跳转是jnz,跳过了设置按钮不可见的一个jmp指令,说明上一个算法计算出的注册码不能满足确定按钮隐藏的条件,点击确定按钮后可能会使注册码清零,确定按钮重新变成不可用状态吧!试一次,单步向下,走到本段结束处,再F9,程序状态果然和我猜想的一样了。
重新将注册码复制入文本框,确定按钮又可用了,点击它,程序中断到本段代码开头,重新F8向下走,再次来到00442D80处,ds:[eax+0x47]=1,所以仍然不会跳,程序不能正确破解,所以要在寄存器窗口双击Z标志位的数字1,让它变成0,使反汇编窗口的跳转前面的灰线变成红色,说明跳转能够执行了。
41.png
继续向下,可以很轻松地发现关键call是在00442DC1处的call CM006_1.00442BA0,F7跟进去查看:
[Asm] 纯文本查看 复制代码
00442BA0   /$  55              push ebp                                 ;  确定按钮事件的关键call,从注册码反算出用户名
00442BA1   |.  8BEC            mov ebp,esp
00442BA3   |.  6A 00           push 0x0
00442BA5   |.  6A 00           push 0x0
00442BA7   |.  6A 00           push 0x0
00442BA9   |.  53              push ebx
00442BAA   |.  56              push esi
00442BAB   |.  8BF2            mov esi,edx
00442BAD   |.  8945 FC         mov [local.1],eax
00442BB0   |.  8B45 FC         mov eax,[local.1]                        ;  取用户名
00442BB3   |.  E8 3010FCFF     call CM006_1.00403BE8                    ;  计数call?edx=2
00442BB8   |.  33C0            xor eax,eax
00442BBA   |.  55              push ebp
00442BBB   |.  68 672C4400     push CM006_1.00442C67
00442BC0   |.  64:FF30         push dword ptr fs:[eax]
00442BC3   |.  64:8920         mov dword ptr fs:[eax],esp
00442BC6   |.  33DB            xor ebx,ebx
00442BC8   |.  8D55 F8         lea edx,[local.2]
00442BCB   |.  8BC6            mov eax,esi
00442BCD   |.  E8 6E4AFCFF     call CM006_1.00407640
00442BD2   |.  8D45 F4         lea eax,[local.3]
00442BD5   |.  8B55 F8         mov edx,[local.2]                        ;  取注册码
00442BD8   |.  E8 730CFCFF     call CM006_1.00403850                    ;  edx=0
00442BDD   |.  8B45 F8         mov eax,[local.2]                        ;  取注册码
00442BE0   |.  E8 4F0EFCFF     call CM006_1.00403A34                    ;  取注册码长度
00442BE5   |.  83F8 05         cmp eax,0x5                              ;  比较注册码的位数,小于5位则死
00442BE8   |.  7E 60           jle short CM006_1.00442C4A
00442BEA   |.  8B45 F8         mov eax,[local.2]                        ;  eax=注册码
00442BED   |.  E8 420EFCFF     call CM006_1.00403A34                    ;  取注册码长度
00442BF2   |.  8BF0            mov esi,eax                              ;  esi=注册码长度
00442BF4   |.  83FE 01         cmp esi,0x1                              ;  注册码长度与默认的长度1比较,不大于则死
00442BF7   |.  7C 2F           jl short CM006_1.00442C28
00442BF9   |>  8D45 F4         /lea eax,[local.3]
00442BFC   |.  E8 0310FCFF     |call CM006_1.00403C04
00442C01   |.  8D4430 FF       |lea eax,dword ptr ds:[eax+esi-0x1]
00442C05   |.  50              |push eax
00442C06   |.  8B45 F8         |mov eax,[local.2]                       ;  取注册码
00442C09   |.  0FB64430 FF     |movzx eax,byte ptr ds:[eax+esi-0x1]     ;  取每个循环中的最后一个字符的ASCII值
00442C0E   |.  F7E8            |imul eax                                ;  eax=eax*eax
00442C10   |.  0FBFC0          |movsx eax,ax
00442C13   |.  F7EE            |imul esi                                ;  eax=eax*esi
00442C15   |.  B9 19000000     |mov ecx,0x19                            ;  ecx==19  ???????
00442C1A   |.  99              |cdq
00442C1B   |.  F7F9            |idiv ecx                                ;  有符号数除法,eax/ecx=eax...edx 结果商入eax,余数入edx
00442C1D   |.  83C2 41         |add edx,0x41
00442C20   |.  58              |pop eax
00442C21   |.  8810            |mov byte ptr ds:[eax],dl                ;  注册码最后一位被计算出的余数+41后的dl代表的字符代替
00442C23   |.  4E              |dec esi                                 ;  esi递减,控制循环,注册码最后一位为原来的倒数第二位
00442C24   |.  85F6            |test esi,esi                            ;  esi不为0则循环,为0向下出循环
00442C26   |.^ 75 D1           \jnz short CM006_1.00442BF9              ;  循环处理注册码
00442C28   |>  8B45 F4         mov eax,[local.3]                        ;  处理后的注册码存入eax中
00442C2B   |.  8B55 FC         mov edx,[local.1]                        ;  用户名
00442C2E   |.  E8 110FFCFF     call CM006_1.00403B44                    ;  计算比较的call?
00442C33   |.  75 17           jnz short CM006_1.00442C4C
00442C35   |.  8B45 FC         mov eax,[local.1]
00442C38   |.  8B55 F4         mov edx,[local.3]                        ;  user32.77D4048F
00442C3B   |.  E8 040FFCFF     call CM006_1.00403B44
00442C40   |.  75 04           jnz short CM006_1.00442C46
00442C42   |.  B3 01           mov bl,0x1
00442C44   |.  EB 06           jmp short CM006_1.00442C4C
00442C46   |>  33DB            xor ebx,ebx
00442C48   |.  EB 02           jmp short CM006_1.00442C4C
00442C4A   |>  33DB            xor ebx,ebx
00442C4C   |>  33C0            xor eax,eax
00442C4E   |.  5A              pop edx
00442C4F   |.  59              pop ecx
00442C50   |.  59              pop ecx
00442C51   |.  64:8910         mov dword ptr fs:[eax],edx
00442C54   |.  68 6E2C4400     push CM006_1.00442C6E
00442C59   |>  8D45 F4         lea eax,[local.3]
00442C5C   |.  BA 03000000     mov edx,0x3
00442C61   |.  E8 760BFCFF     call CM006_1.004037DC
00442C66   \.  C3              retn
00442C67    .^ E9 0C06FCFF     jmp CM006_1.00403278
00442C6C    .^ EB EB           jmp short CM006_1.00442C59
00442C6E    .  8BC3            mov eax,ebx
00442C70    .  5E              pop esi
00442C71    .  5B              pop ebx
00442C72    .  8BE5            mov esp,ebp
00442C74    .  5D              pop ebp
00442C75    .  C3              retn

从代码看,与00442A3C这个关键call类似,对照着这个call,相对应地进行注释后,发现这个关键子程序的作用是用注册码运算出一个用户名,再和输入的用户名比较,相同则确定按钮点击后隐藏,否则不成功!
算法是:
[Visual Basic] 纯文本查看 复制代码
Private Sub SerialButton_Click()
Dim Name, Lend, Code, Num, INum()
If Text1.Text <> "" Then
   Name = (Text1.Text)
   Lend = Len(Name) 'Lend = LenB(StrConv(Name, vbFormUnicode))’两种取字符串长度的函数
   If Lend < 6 And Lend > 10 Then
      MsgBox ("用户名长度必须在6到10位之间")
      Text1.Text = ""
   End If
   Num = Asc(Mid(Name, 5, 1)) Mod 7 + 2
   n = 1
   For i = 1 To Num
   n = n * i
   Next i
   ReDim INum(Lend)
   For j = 1 To Lend
       INum(j) = Asc(Mid(Name, j, 1)) * n
       Code = Code + INum(j)
   Next j
   Code = Code - 31337
   If Len(Code) < 6 Then MsgBox ("得到的注册码长度小于6位,请重新输入用户名进行计算!")
   Text2.Text = Code
Else
   MsgBox ("用户名不能为空!")
End If
End Sub

天啊,从注册码输入事件中的关键call的算法与这里的算法怎么看也不是互为反运算!用注册码383798算出的用户名是“BWDAUQ”,一看就跟“52pojie.cn”差远了!将这个反算出的用户名复制到用户名文本框中,确定按钮又不可用了!
从上面三个事件中找不到成功的希望了!最后看看清除注册码按钮事件吧:
重新将程序载入OD,将清除注册码按钮事件断点激活,其他断点禁用,F9,输入用户名“52pojie.cn”,算出的注册码“383798”,确定按钮可用了;点击清除注册码按钮,程序中断:
[Asm] 纯文本查看 复制代码
00442EA8   /.  55              push ebp                                 ;  清除注册码按钮事件段首
00442EA9   |.  8BEC            mov ebp,esp
00442EAB   |.  6A 00           push 0x0
00442EAD   |.  53              push ebx
00442EAE   |.  8BD8            mov ebx,eax
00442EB0   |.  33C0            xor eax,eax
00442EB2   |.  55              push ebp
00442EB3   |.  68 322F4400     push CM006_1.00442F32
00442EB8   |.  64:FF30         push dword ptr fs:[eax]                  ;  ***** TRY
00442EBB   |.  64:8920         mov dword ptr fs:[eax],esp
00442EBE   |.  8D55 FC         lea edx,[local.1]
00442EC1   |.  8B83 E0020000   mov eax,dword ptr ds:[ebx+0x2E0]         ;  * Reference to control Codice : TLabel注册码标签
00442EC7   |.  E8 F403FEFF     call CM006_1.004232C0                    ;  取注册码字符串及字符串长度
00442ECC   |.  8B45 FC         mov eax,[local.1]
00442ECF   |.  E8 9C47FCFF     call CM006_1.00407670                    ;  * Reference to: sysutils.StrToInt(S:字符串转换成16进制数
00442ED4   |.  50              push eax
00442ED5   |.  8D55 FC         lea edx,[local.1]
00442ED8   |.  8B83 DC020000   mov eax,dword ptr ds:[ebx+0x2DC]         ;  * Reference to control Nome : TLabel(用户名标签)
00442EDE   |.  E8 DD03FEFF     call CM006_1.004232C0                    ;  * Reference to: controls.TControl.GetText(TControl):TCaption;取用户名字符串及长度
00442EE3   |.  8B45 FC         mov eax,[local.1]
00442EE6   |.  5A              pop edx                                  ;  0012F674
00442EE7   |.  E8 08FCFFFF     call CM006_1.00442AF4                    ;  * Reference to : TPrincipale._PROC_00442AF4()关键call
00442EEC   |.  84C0            test al,al
00442EEE       74 1C           je short CM006_1.00442F0C
00442EF0   |.  33D2            xor edx,edx
00442EF2   |.  8B83 D0020000   mov eax,dword ptr ds:[ebx+0x2D0]         ;  * Reference to control Cancella : TButton(清除注册码按钮)
00442EF8   |.  E8 B302FEFF     call CM006_1.004231B0                    ;  * Reference to: controls.TControl.SetVisible(TControl;Boolean);设置可见与否
00442EFD   |.  B2 01           mov dl,0x1                               ;  edx=1时,确定按钮可用
00442EFF   |.  8B83 CC020000   mov eax,dword ptr ds:[ebx+0x2CC]         ;  * Reference to control Ok : TButton(确定按钮)
00442F05   |.  8B08            mov ecx,dword ptr ds:[eax]
00442F07   |.  FF51 60         call dword ptr ds:[ecx+0x60]             ;  调用确定按钮是否可用
00442F0A   |.  EB 10           jmp short CM006_1.00442F1C
00442F0C   |>  BA 482F4400     mov edx,CM006_1.00442F48                 ;  0
00442F11   |.  8B83 E0020000   mov eax,dword ptr ds:[ebx+0x2E0]         ;  * Reference to control Codice : TLabel注册码标签
00442F17   |.  E8 D403FEFF     call CM006_1.004232F0                    ;  * Reference to: controls.TControl.SetText(TControl;TCaption);设置控件文本内容
00442F1C   |>  33C0            xor eax,eax
00442F1E   |.  5A              pop edx                                  ;  0012F674
00442F1F   |.  59              pop ecx                                  ;  0012F674
00442F20   |.  59              pop ecx                                  ;  0012F674
00442F21   |.  64:8910         mov dword ptr fs:[eax],edx
00442F24   |.  68 392F4400     push CM006_1.00442F39                    ;  ****** FINALLY
00442F29   |>  8D45 FC         lea eax,[local.1]
00442F2C   |.  E8 8708FCFF     call CM006_1.004037B8
00442F31   \.  C3              retn                                     ;  清除注册码按钮事件段尾
00442F32    .^ E9 4103FCFF     jmp CM006_1.00403278
00442F37    .^ EB F0           jmp short CM006_1.00442F29
00442F39    .  5B              pop ebx                                  ;  ****** END
00442F3A    .  59              pop ecx                                  ;  0012F674
00442F3B    .  5D              pop ebp                                  ;  0012F674
00442F3C    .  C3              retn

仔细分析代码,看到00442EE7地址处的call CM006_1.00442AF4是一个关键call ,它的返回值存入al中,如果al=1,则确定按钮可用,清除注册码按钮隐藏!
单步运行一下,到00442EE7处,F7跟进去查看:
[Asm] 纯文本查看 复制代码
00442AF4   /$  55              push ebp                                 ;  清除注册码按钮事件的关键call
00442AF5   |.  8BEC            mov ebp,esp
00442AF7   |.  83C4 F8         add esp,-0x8
00442AFA   |.  53              push ebx
00442AFB   |.  56              push esi
00442AFC   |.  8955 F8         mov [local.2],edx                        ;  注册码值入【local.2】
00442AFF   |.  8945 FC         mov [local.1],eax                        ;  用户名入【local.1】
00442B02   |.  8B45 FC         mov eax,[local.1]                        ;  取用户名
00442B05   |.  E8 DE10FCFF     call CM006_1.00403BE8                    ;  edx=2
00442B0A   |.  33C0            xor eax,eax
00442B0C   |.  55              push ebp
00442B0D   |.  68 902B4400     push CM006_1.00442B90
00442B12   |.  64:FF30         push dword ptr fs:[eax]
00442B15   |.  64:8920         mov dword ptr fs:[eax],esp
00442B18   |.  8B45 FC         mov eax,[local.1]                        ;  取用户名
00442B1B   |.  E8 140FFCFF     call CM006_1.00403A34                    ;  得到用户名长度
00442B20   |.  83F8 05         cmp eax,0x5                              ;  如果用户名长度不大于5则死
00442B23   |.  7E 53           jle short CM006_1.00442B78
00442B25   |.  8B45 FC         mov eax,[local.1]                        ;  取用户名
00442B28   |.  0FB640 04       movzx eax,byte ptr ds:[eax+0x4]          ;  取用户名的第5个字符的ASCII值
00442B2C   |.  B9 07000000     mov ecx,0x7                              ;  ecx=7
00442B31   |.  33D2            xor edx,edx
00442B33   |.  F7F1            div ecx                                  ;  eax/ecx,商入eax,余数入edx
00442B35   |.  8BC2            mov eax,edx
00442B37   |.  83C0 02         add eax,0x2
00442B3A   |.  E8 E1FEFFFF     call CM006_1.00442A20                    ;  求阶乘
00442B3F   |.  8BF0            mov esi,eax
00442B41   |.  33DB            xor ebx,ebx
00442B43   |.  8B45 FC         mov eax,[local.1]                        ;  取用户名
00442B46   |.  E8 E90EFCFF     call CM006_1.00403A34                    ;  取用户名长度
00442B4B   |.  85C0            test eax,eax
00442B4D   |.  7E 16           jle short CM006_1.00442B65
00442B4F   |.  BA 01000000     mov edx,0x1                              ;  edx==1,edx为循环的第一个序号
00442B54   |>  8B4D FC         /mov ecx,[local.1]                       ;  ecx=用户名
00442B57   |.  0FB64C11 FF     |movzx ecx,byte ptr ds:[ecx+edx-0x1]     ;  得到第一个字符的ASCII值
00442B5C   |.  0FAFCE          |imul ecx,esi                            ;  ecx=ecx*esi[esi为上面call返回的eax的值]
00442B5F   |.  03D9            |add ebx,ecx                             ;  ebx=ebx+ecx
00442B61   |.  42              |inc edx                                 ;  edx递加
00442B62   |.  48              |dec eax                                 ;  eax递减
00442B63   |.^ 75 EF           \jnz short CM006_1.00442B54              ;  循环得到每个用户名字符ASCII值*上一步阶乘的值的总和
00442B65   |>  2B5D F8         sub ebx,[local.2]                        ;  处理用户名得到的注册码与输入的注册码的16进制数值比较
00442B68   |.  81FB 697A0000   cmp ebx,0x7A69                           ;  值与0x7A69比较要相等
00442B6E   |.  75 04           jnz short CM006_1.00442B74               ;  不等时,ebx=0
00442B70   |.  B3 01           mov bl,0x1                               ;  相等时,ebx=1
00442B72   |.  EB 06           jmp short CM006_1.00442B7A
00442B74   |>  33DB            xor ebx,ebx
00442B76   |.  EB 02           jmp short CM006_1.00442B7A
00442B78   |>  33DB            xor ebx,ebx
00442B7A   |>  33C0            xor eax,eax                              ;  eax=0
00442B7C   |.  5A              pop edx                                  ;  CM006_1.00442B8F
00442B7D   |.  59              pop ecx                                  ;  CM006_1.00442B8F
00442B7E   |.  59              pop ecx                                  ;  CM006_1.00442B8F
00442B7F   |.  64:8910         mov dword ptr fs:[eax],edx
00442B82   |.  68 972B4400     push CM006_1.00442B97
00442B87   |>  8D45 FC         lea eax,[local.1]
00442B8A   |.  E8 290CFCFF     call CM006_1.004037B8                    ;  ??????
00442B8F   \.  C3              retn
00442B90    .^ E9 E306FCFF     jmp CM006_1.00403278
00442B95    .^ EB F0           jmp short CM006_1.00442B87
00442B97    .  8BC3            mov eax,ebx
00442B99    .  5E              pop esi                                  ;  CM006_1.00442B8F
00442B9A    .  5B              pop ebx                                  ;  CM006_1.00442B8F
00442B9B    .  59              pop ecx                                  ;  CM006_1.00442B8F
00442B9C    .  59              pop ecx                                  ;  CM006_1.00442B8F
00442B9D    .  5D              pop ebp                                  ;  CM006_1.00442B8F
00442B9E    .  C3              retn

其中又有一个call CM006_1.00442A20的子程序,经研究后是取用户名的第5位对7求余然后再加2得到的数,求阶乘,最后得到的值。
这个关键call的算法其实就是取阶乘的结果再乘以用户名的每个ansi值相乘然后求和,再减去0x7A69,这个结果能够满足确定按钮可用,并且清除注册码按钮消失的要求。这样一来,就意味着程序的流程应该是输入用户名、注册码,点击清除注册码按钮,使清除注册码消失,让确定按钮可用;点击确定按钮,再将确定按钮隐藏!
试一试吧!
44.png
程序运行到00442B65处,从信息栏中看出算出的注册码值是0x14EE(5358),它减去0x7A69(31337)的值是一个负数(-25979)!负数能用吗?我用计算器算了一下,结果是“FFFFFFFFFFFF9A85”!再转换成10进制值是“18446744073709525637”这样的一组数字,和实际上将的值“-25979”相差太太太太太远了!!将这三组字符都充当注册码试了一次,前两个失败,不仅是按钮没有隐藏,而且注册码真的清0了,确定按钮也马上不可用了!第三个的负数成功了!
45.png
再点击确定按钮,没有任何反应!哦,这个注册码只能满足隐藏清除注册码的要求,确定按钮还无法隐藏啊。再将确定按钮段首断点激活,禁用其他断点,再点确定:
单步走到00442D80处,此时看到信息栏中是“ds:[00944EEF]=00”,说明ds:[eax+0x47]=0。根据前面对确定按钮事件代码的分析,我认为ds:[eax+0x47]这个堆栈中存的就是清除注册码按钮是否隐藏的属性值,隐藏为0,不隐藏为1!那么程序流程就是可以正确破解的步骤了!继续向下单步到关键call,F7跟入,运行到0042C28处,信息栏中用户名出来了:(ASCII "AACVAT")!
46.png
F9运行,将 “AACVAT”字符串复制到用户名文本框中(见左下图),嗯,确定按钮仍然可用!
47.png             48.png                
点击确定按钮,程序又中断了。F9一下,再看程序界面(右上图),成功了!!!!!
从注册码逆推出用户名的算法如下:
[Visual Basic] 纯文本查看 复制代码
Private Sub NameButton_Click()
Dim Serial, nome, lendS, Codice
If Text2.Text = "" Then
   MsgBox ("注册码不能为空或者为0!")
End If
Serial = Text2.Text
lendS = Len(Serial)
If lendS < 6 Then
   MsgBox ("注册码长度小于6位,请重新输入用户名进行计算!")
End If
For k = 1 To lendS
    Codice = (Mid(Serial, k, 1))
    Codice = Asc(Codice)
    Codice = Codice * Codice * k
    Codice = Codice Mod 25
    Codice = Codice + 65
    Codice = Chr(Codice)
    nome = nome + Codice
Next k
Text3.Text = nome
End Sub

总结一下自己这些日子的学习过程,感到虽然走了不少弯路,但也在不断地加深自己对各方面知识的理解。
一种思路是先用清除注册码事件里的算法先得出一个注册码,先点击清除注册码按钮使之消失,再利用确定按钮事件里的算法反算出一个用户名,代替原来的用户名,点击确定按钮,就能够完成程序破解了。这种思路不够完美;
第二种思路则是用穷举的方法,算出满足用户名和注册码之间的三种不同的关系算法,这应该是最正确的方法,可是自己目前只实现了两种算法的有限穷举,实在无奈!
试着做成了两个注册机,一个是需要两个用户名,一个注册码来完成破解,一个是只输入一组用户名和注册码就达到目的的,但这两个注册机都不够完善,特别是关于穷举法注册机的,一是限定死了生成的用户名只有6位,7到10位的未考虑;二是其中未将用户名输入事件的算法加入比较,只符合两种算法;三是且穷举法只找到了第一组用户名和注册码后就被强行结束了。我的VB也只是初入门的水平,代码可能很啰嗦,也可能存在其他错误,敬请论坛的大神们多多指教!!
自己的006练习附件: 006.rar (865.22 KB, 下载次数: 50) 包括原程序,我汉化后的程序及爆破后的程序。
百度链接是: http://pan.baidu.com/s/1skMkJY9 密码: 86pm,个人学习过的crackme程序都在里面。


免费评分

参与人数 9威望 +2 吾爱币 +18 热心值 +9 收起 理由
pk8900 + 1 + 1 我很赞同!速度不慢,我也是刚刚搞定了这个。
冬日安好 + 1 + 1 谢谢@Thanks!
385290864 + 1 + 1 用心讨论,共获提升!
Hmily + 2 + 10 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
x358650 + 1 + 1 66666冲着排版也奶你一口。。。
那份执着 + 1 + 1 66666冲着排版也奶你一口。。。
rxsheng + 1 + 1 用心讨论,共获提升!
钱后佛 + 1 + 1 666,学习学习
pwp + 1 + 1 楼主,您这160个cm哪下载的,我也想练练

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

angel8327 发表于 2017-5-23 15:50 来自手机
观摩高手
倍儿爽 发表于 2018-6-30 19:16
谢谢你的思路,不过真的寻找注册码是很费力气的,毕竟你要跟着他的算法走,所以能爆破基本不跟着软件设计师的算法走,有些算法能绕半天,还是爆破好用!!
紫夜残风 发表于 2017-5-23 14:03
夜雨润无声 发表于 2017-5-23 14:08
谢谢楼主分享
花花小公子w 发表于 2017-5-23 14:19
这种排版我能扣分么,太恐怖了
 楼主| 海天一色001 发表于 2017-5-23 15:01
紫夜残风 发表于 2017-5-23 14:03
这排版眼睛要瞎的.....

排版是我心中永远的痛!!!!
在word中排的好好的,一复制进来就完了,还有些图片的地址如“file:///C:\Users\Administrator\AppData\Local\Temp\ksohtml\wpsF06A.tmp.jpg”之类的,编辑了5遍,还没完全消除!
有没有能原封不动地支持word的输入框啊!
灰太狼大王 发表于 2017-5-23 15:22
我第01才整了一个注册码,另一个没找出来,你这么快都整到6了
 楼主| 海天一色001 发表于 2017-5-23 15:33
灰太狼大王 发表于 2017-5-23 15:22
我第01才整了一个注册码,另一个没找出来,你这么快都整到6了

断断续续一个多月才到第6个,而且前面还有没有完全破解出来的呀。
这也算是学习吧。
每个程序的练习过程都不是一帆风顺的,只能坚持着学下去吧。
白吱声 发表于 2017-5-23 16:31
同求全部文件 -
肥牛 发表于 2017-5-23 16:35
楼主说的这160个CrackMe在哪里下载?
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-4-24 15:42

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表