- UID
- 37127
注册时间2007-11-4
阅读权限30
最后登录1970-1-1
龙战于野
该用户从未签到
|
【破文标题】给最最菜鸟的同学写的算法分析
【破文作者】blitz
【作者邮箱】[email protected]
【作者主页】
【破解工具】Peid,OD,计算工具
【破解平台】WinXP SP2
【软件名称】KeyGenMe_04.exe
【软件大小】376K
【原版下载】
【保护方式】无壳
【软件简介】从看雪上找到的一个入门CM,是个大大[HappyTown]给我们写来练习算法的.一共5个,其他4个我也不会..
【破解声明】发表点心得,欢迎交流指导!
------------------------------------------------------------------------
【破解过程】Peid查壳,无壳,Borland Delphi 6.0所写.
OD载入
插件-超级字符串参考
往下拉,在初始CPU选择附近可以看到'Congratulations'字符,双击其来到相关代码处.
00450141 |. 03C2 ADD EAX,EDX
00450143 |. 83F8 70 CMP EAX,70
00450146 |. 75 2A JNZ SHORT KeyGenMe.00450172
00450148 |. 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C]
0045014B |. 0FB640 04 MOVZX EAX,BYTE PTR DS:[EAX+4]
0045014F |. 8B55 F4 MOV EDX,DWORD PTR SS:[EBP-C]
00450152 |. 0FB652 09 MOVZX EDX,BYTE PTR DS:[EDX+9]
00450156 |. F7EA IMUL EDX
00450158 |. 3D 8C0A0000 CMP EAX,0A8C
0045015D |. 75 13 JNZ SHORT KeyGenMe.00450172
0045015F |. 6A 40 PUSH 40 ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
00450161 |. 68 98014500 PUSH KeyGenMe.00450198 ; |congratulations //字符串
00450166 |. 68 A8014500 PUSH KeyGenMe.004501A8 ; |good job,man!
0045016B |. 6A 00 PUSH 0 ; |hOwner = NULL
0045016D |. E8 2E63FBFF CALL <JMP.&user32.MessageBoxA> ; \MessageBoxA
00450172 |> 33C0 XOR EAX,EAX //走到这里就注册失败
00450174 |. 5A POP EDX
00450175 |. 59 POP ECX
00450176 |. 59 POP ECX
00450177 |. 64:8910 MOV DWORD PTR FS:[EAX],EDX
0045017A |. 68 94014500 PUSH KeyGenMe.00450194
0045017F |> 8D45 F4 LEA EAX,DWORD PTR SS:[EBP-C]
00450182 |. BA 02000000 MOV EDX,2
00450187 |. E8 A83CFBFF CALL KeyGenMe.00403E34
0045018C \. C3 RETN
在字符串向上分析,发现在00450158出有一个比较,其下一行代码是00450158处的比较不相等就跳走
但是要跳到哪里呢?选定跳走的那一行,然后按回车键看看如果要跳,跳到哪里
回车就来到00450172这一行,下方的数据框里显示都是那些地方跳到这里
跳转来自 0045008E, 004500B4, 004500D6, 004500E7, 00450107, 0045011C, 00450131, 00450146, 0045015D
哇,好多地方都要来这里.
分析一下,有congratulations字符串的那行肯定是注册码正确后的提示框,而前边的比较命令和后边的JNZ命令意思是和0A8C比较,不相等就跳,但是一跳就没有正确认证的提示框了,就是失败了.一般的软件这里就是关键跳了,但是这个不是,因为它只是关键跳中间的一个.原因很简单,我们跑到了它要跳往的地方,发现好多跳转,它们的作用都一样,就是在某些条件以后,发现不合规矩,就跳向失败,不给你注册成功的的机会.
对付这种验证最好的办法就是跑到最早跳到失败的地方开始分析,看看它都设了什么条件.
好的,我们去0045008E看看.选定'跳转来自..'一行,右键选择'转到JL来自0045008E
00450074 |. 8B80 00030000 MOV EAX,DWORD PTR DS:[EAX+300]
0045007A |. E8 D9F2FDFF CALL KeyGenMe.0042F358
0045007F |. 8B45 F8 MOV EAX,DWORD PTR SS:[EBP-8]
00450082 |. E8 4940FBFF CALL KeyGenMe.004040D0
00450087 |. 8945 F0 MOV DWORD PTR SS:[EBP-10],EAX
0045008A |. 837D F0 02 CMP DWORD PTR SS:[EBP-10],2
0045008E |. 0F8C DE000000 JL KeyGenMe.00450172
00450094 |. 8D55 F4 LEA EDX,DWORD PTR SS:[EBP-C]
00450097 |. 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4]
0045009A |. 8B80 08030000 MOV EAX,DWORD PTR DS:[EAX+308]
004500A0 |. E8 B3F2FDFF CALL KeyGenMe.0042F358
004500A5 |. 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C]
004500A8 |. E8 2340FBFF CALL KeyGenMe.004040D0
004500AD |. 8945 EC MOV DWORD PTR SS:[EBP-14],EAX
004500B0 |. 837D EC 0A CMP DWORD PTR SS:[EBP-14],0A
004500B4 |. 0F85 B8000000 JNZ KeyGenMe.00450172
004500BA |. 8B45 EC MOV EAX,DWORD PTR SS:[EBP-14]
004500BD |. 85C0 TEST EAX,EAX
004500BF |. 7E 34 JLE SHORT KeyGenMe.004500F5
004500C1 |. 8945 E4 MOV DWORD PTR SS:[EBP-1C],EAX
004500C4 |. C745 E8 01000>MOV DWORD PTR SS:[EBP-18],1
004500CB |> 8B45 F4 /MOV EAX,DWORD PTR SS:[EBP-C]
004500CE |. 8B55 E8 |MOV EDX,DWORD PTR SS:[EBP-18]
004500D1 |. 807C10 FF 30 |CMP BYTE PTR DS:[EAX+EDX-1],30
004500D6 |. 0F82 96000000 |JB KeyGenMe.00450172
004500DC |. 8B45 F4 |MOV EAX,DWORD PTR SS:[EBP-C]
004500DF |. 8B55 E8 |MOV EDX,DWORD PTR SS:[EBP-18]
004500E2 |. 807C10 FF 39 |CMP BYTE PTR DS:[EAX+EDX-1],39
004500E7 |. 0F87 85000000 |JA KeyGenMe.00450172
004500ED |. FF45 E8 |INC DWORD PTR SS:[EBP-18]
004500F0 |. FF4D E4 |DEC DWORD PTR SS:[EBP-1C]
004500F3 |.^ 75 D6 \JNZ SHORT KeyGenMe.004500CB
004500F5 |> 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C]
004500F8 |. 0FB600 MOVZX EAX,BYTE PTR DS:[EAX]
004500FB |. 8B55 F4 MOV EDX,DWORD PTR SS:[EBP-C]
004500FE |. 0FB652 05 MOVZX EDX,BYTE PTR DS:[EDX+5]
00450102 |. 03C2 ADD EAX,EDX
00450104 |. 83F8 6D CMP EAX,6D
00450107 |. 75 69 JNZ SHORT KeyGenMe.00450172
00450109 |. 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C]
0045010C |. 0FB640 01 MOVZX EAX,BYTE PTR DS:[EAX+1]
00450110 |. 8B55 F4 MOV EDX,DWORD PTR SS:[EBP-C]
00450113 |. 0FB652 06 MOVZX EDX,BYTE PTR DS:[EDX+6]
00450117 |. 03C2 ADD EAX,EDX
00450119 |. 83F8 67 CMP EAX,67
0045011C |. 75 54 JNZ SHORT KeyGenMe.00450172
0045011E |. 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C]
00450121 |. 0FB640 02 MOVZX EAX,BYTE PTR DS:[EAX+2]
00450125 |. 8B55 F4 MOV EDX,DWORD PTR SS:[EBP-C]
00450128 |. 0FB652 07 MOVZX EDX,BYTE PTR DS:[EDX+7]
0045012C |. 03C2 ADD EAX,EDX
0045012E |. 83F8 69 CMP EAX,69
00450131 |. 75 3F JNZ SHORT KeyGenMe.00450172
00450133 |. 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C]
00450136 |. 0FB640 03 MOVZX EAX,BYTE PTR DS:[EAX+3]
0045013A |. 8B55 F4 MOV EDX,DWORD PTR SS:[EBP-C]
0045013D |. 0FB652 08 MOVZX EDX,BYTE PTR DS:[EDX+8]
00450141 |. 03C2 ADD EAX,EDX
00450143 |. 83F8 70 CMP EAX,70
00450146 |. 75 2A JNZ SHORT KeyGenMe.00450172
00450148 |. 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C]
0045014B |. 0FB640 04 MOVZX EAX,BYTE PTR DS:[EAX+4]
0045014F |. 8B55 F4 MOV EDX,DWORD PTR SS:[EBP-C]
00450152 |. 0FB652 09 MOVZX EDX,BYTE PTR DS:[EDX+9]
00450156 |. F7EA IMUL EDX
00450158 |. 3D 8C0A0000 CMP EAX,0A8C
0045015D |. 75 13 JNZ SHORT KeyGenMe.00450172
0045015F |. 6A 40 PUSH 40 ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
00450161 |. 68 98014500 PUSH KeyGenMe.00450198 ; |congratulations
00450166 |. 68 A8014500 PUSH KeyGenMe.004501A8 ; |good job,man!
0045016B |. 6A 00 PUSH 0 ; |hOwner = NULL
0045016D |. E8 2E63FBFF CALL <JMP.&user32.MessageBoxA> ; \MessageBoxA
00450172 |> 33C0 XOR EAX,EAX
00450174 |. 5A POP EDX
00450175 |. 59 POP ECX
00450176 |. 59 POP ECX
00450177 |. 64:8910 MOV DWORD PTR FS:[EAX],EDX
0045017A |. 68 94014500 PUSH KeyGenMe.00450194
0045017F |> 8D45 F4 LEA EAX,DWORD PTR SS:[EBP-C]
00450182 |. BA 02000000 MOV EDX,2
00450187 |. E8 A83CFBFF CALL KeyGenMe.00403E34
0045018C \. C3 RETN
0045018D .^ E9 8236FBFF JMP KeyGenMe.00403814
00450192 .^ EB EB JMP SHORT KeyGenMe.0045017F
00450194 . 8BE5 MOV ESP,EBP
00450196 . 5D POP EBP
00450197 . C3 RETN
00450198 . 43 6F 6E 67 7>ASCII "Congratulations",0
004501A8 . 47 6F 6F 64 2>ASCII "Good job,man!",0
004501B6 00 DB 00
004501B7 00 DB 00
004501B8 . 55 PUSH EBP
004501B9 . 8BEC MOV EBP,ESP
004501BB . 33C0 XOR EAX,EAX
004501BD . 55 PUSH EBP
004501BE . 68 DD014500 PUSH KeyGenMe.004501DD
004501C3 . 64:FF30 PUSH DWORD PTR FS:[EAX]
004501C6 . 64:8920 MOV DWORD PTR FS:[EAX],ESP
004501C9 . FF05 D43B4500 INC DWORD PTR DS:[453BD4]
004501CF . 33C0 XOR EAX,EAX
004501D1 . 5A POP EDX
004501D2 . 59 POP ECX
004501D3 . 59 POP ECX
004501D4 . 64:8910 MOV DWORD PTR FS:[EAX],EDX
004501D7 . 68 E4014500 PUSH KeyGenMe.004501E4
004501DC > C3 RETN ; RET 用作跳转到 004501E4
这是整个验证过程了.
在0045008E上边,什么东西在赋值(MOV)比较(CMP)之后就给跳(JL)走了,还是走到失败,肯定是什么验证过了,然后不过关才走的.我们在赋值的那一行下F2断点
好了,F9一下运行程序.
在原程序里随便输入几个注册信息,像我就输入注册名blitz,注册码123456,然后点check.
这里注册码输入数字,一会解释.
好神奇,那个程序像卡死了一样,OD弹了出来,显示运行到了我们下断点的位置.好了,我们下断成功.
我们发现中断的这一行经过上边的CALL以后,把EAX中的值赋给了SS堆栈,这个我们不管它
我的EAX里储存的是00000005,和我的注册信息也有什么关系呢?..
先想想你的注册信息位数吧?..我的blitz正好5位,123456是6位,所以它应该是验证注册名的.
你可以CTRL+F2重新载入,输入你的名字,实践证明,它确实存的是位数.
这些东西你先记住,接触的多了自然就有敏感性了.我也才注意到的.
好了.我们F8继续追.拿5和2比较以后,它没让我跳向失败.JL是小于/等于时跳,也就是说注册码在3位和3位以上.
我们F8继续.注意004500A5,因为这歩的数据窗口中出现了我们输入的注册码.我们来分析其内容.
004500A5 |. 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C]
它把堆栈SS:[EBP-C]的值赋给了EAX,然后EAX的值就成了我们的注册码,可见堆栈SS:[EBP-C]里就存的是我们输入的注册码
F8运行到004500AD的时候,我们发现EAX成了6,就是我输入的注册码的位数,还把它赋给了SS:[EBP-14]
F8继续,用我们的注册码位数去和0A比较,我的是6,当然不等啦.人家下边说不等就失败
0A是16进制数,,改成0A的十进制,即10,用计算工具可以换算.
你可以重新载入,然后输入10位注册码再来一遍,但我推荐在右边的寄存器里把EAX改下再比,还可以汇编JNE
这些小技巧累计多了很有用的.
=============================分支,扩展内容==============================
顺便提下004500BD TEST EAX,EAX 是配合下边JLE用的,意思是没填注册码的话就不用过注册码验证,而不是跳向注册失败.这里的注册码验证也算整个软件注册认证的一个分支,就是校验注册码输入是否规范.我们来分析这个程序注册码验证的过程.这些是JLE以后的内容.
004500C1 |. 8945 E4 MOV DWORD PTR SS:[EBP-1C],EAX //把注册码位数存入SS:[EBP-1C]
004500C4 |. C745 E8 01000>MOV DWORD PTR SS:[EBP-18],1 //把1存入SS:[EBP-18]
004500CB |> 8B45 F4 /MOV EAX,DWORD PTR SS:[EBP-C] //取注册码入EAX
004500CE |. 8B55 E8 |MOV EDX,DWORD PTR SS:[EBP-18] //取刚刚赋值的1入EDX
004500D1 |. 807C10 FF 30 |CMP BYTE PTR DS:[EAX+EDX-1],30 //拿注册码第一位与30比较*注
004500D6 |. 0F82 96000000 |JB KeyGenMe.00450172 //小于就跳注册失败
004500DC |. 8B45 F4 |MOV EAX,DWORD PTR SS:[EBP-C] //取注册码入EAX
004500DF |. 8B55 E8 |MOV EDX,DWORD PTR SS:[EBP-18] //取刚刚赋值的1入EDX
004500E2 |. 807C10 FF 39 |CMP BYTE PTR DS:[EAX+EDX-1],39 //拿注册码第一位与39比较*注
004500E7 |. 0F87 85000000 |JA KeyGenMe.00450172 //大于就跳注册失败
004500ED |. FF45 E8 |INC DWORD PTR SS:[EBP-18] //[EBP-18]加1,即本轮的1+1
004500F0 |. FF4D E4 |DEC DWORD PTR SS:[EBP-1C] //注册码位数减1
004500F3 |.^ 75 D6 \JNZ SHORT KeyGenMe.004500CB //这个不是不想等就跳,是不为0就跳
这段的头两行起引导的作用,后边几行是个循环,作用是逐个验证注册码输入是否规范,30和39是在16进制ASCII码里代表0到9,整段是验证注册码输入是否为数字,不为数字就跳.整个验证过程自己多跟几遍就明白了.
想明白的就可以跑出循环了,选定循环底部下边一行,点F4或右键选择断点-运行到选定位置
==========================================================================================
校验完注册码,我们继续跟程序.
F4到004500F5
004500F5|> \8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C] //把注册码入EAX
004500F8 |. 0FB600 MOVZX EAX,BYTE PTR DS:[EAX] //取单个注册码,当前取第1位,入EAX
004500FB |. 8B55 F4 MOV EDX,DWORD PTR SS:[EBP-C] //取注册码到EDX
004500FE |. 0FB652 05 MOVZX EDX,BYTE PTR DS:[EDX+5] //取单个注册码,当前取第6位,入EDX
00450102 |. 03C2 ADD EAX,EDX //把EDX值加到EAX里
00450104 |. 83F8 6D CMP EAX,6D //与固定值6D比较
00450107 |. 75 69 JNZ SHORT KeyGenMe.00450172 //不等跳失败
下边与上边基本相同,不加注释了.
00450109 |. 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C]
0045010C |. 0FB640 01 MOVZX EAX,BYTE PTR DS:[EAX+1]
00450110 |. 8B55 F4 MOV EDX,DWORD PTR SS:[EBP-C]
00450113 |. 0FB652 06 MOVZX EDX,BYTE PTR DS:[EDX+6]
00450117 |. 03C2 ADD EAX,EDX
00450119 |. 83F8 67 CMP EAX,67
0045011C |. 75 54 JNZ SHORT KeyGenMe.00450172
0045011E |. 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C]
00450121 |. 0FB640 02 MOVZX EAX,BYTE PTR DS:[EAX+2]
00450125 |. 8B55 F4 MOV EDX,DWORD PTR SS:[EBP-C]
00450128 |. 0FB652 07 MOVZX EDX,BYTE PTR DS:[EDX+7]
0045012C |. 03C2 ADD EAX,EDX
0045012E |. 83F8 69 CMP EAX,69
00450131 |. 75 3F JNZ SHORT KeyGenMe.00450172
00450133 |. 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C]
00450136 |. 0FB640 03 MOVZX EAX,BYTE PTR DS:[EAX+3]
0045013A |. 8B55 F4 MOV EDX,DWORD PTR SS:[EBP-C]
0045013D |. 0FB652 08 MOVZX EDX,BYTE PTR DS:[EDX+8]
00450141 |. 03C2 ADD EAX,EDX
00450143 |. 83F8 70 CMP EAX,70
00450146 |. 75 2A JNZ SHORT KeyGenMe.00450172
00450148 |. 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C]
0045014B |. 0FB640 04 MOVZX EAX,BYTE PTR DS:[EAX+4]
0045014F |. 8B55 F4 MOV EDX,DWORD PTR SS:[EBP-C]
00450152 |. 0FB652 09 MOVZX EDX,BYTE PTR DS:[EDX+9]
00450156 |. F7EA IMUL EDX //IMUL??,相乘!
00450158 |. 3D 8C0A0000 CMP EAX,0A8C
0045015D |. 75 13 JNZ SHORT KeyGenMe.00450172
好了,整个算法分析完了..
算法总结下.
软件采取注册码的不同位数相加与固定码比较,不相等则失败.算法与注册名无关,但要求注册名大于等于3位
算法过程:
注册名位数大于等于3
注册码位数等于10
注册码第1,6位16位ASCII码相加,与6D相比
注册码第2,7位16位ASCII码相加,与67相比
注册码第3,8位16位ASCII码相加,与69相比
注册码第4,9位16位ASCII码相加,与70相比
注册码第5,10位16位ASCII码相加,与0a8c相比
我也是菜鸟,对进制也不很了解.反正我把6D换成73算得,即把D换成13,再加60
我知道这是绝对错误的,但没办法,基础不好么..就先这么用着,以后提高了再改回来.希望高手能提供些帮助.
自己在那里算一会,除了最后一组乘的,其他都可以算出来.
最后一组我换10进制算出来的.过程如下.0a8c十进制2700,除以ASCII码的十进制,一个个试出来.
提供一组可用的注册码:5128286786
非明码比较,不能做内存注册机!
------------------------------------------------------------------------
【破解总结】我就这么马马虎虎算出来了,更贴近'蒙'一点.希望高手指教.
一点心得,希望可以帮助与我一样的菜鸟理解.
CM及运算工具附件提供.
另外,祝愿12月新来的朋友能一路好走!.
------------------------------------------------------------------------
【版权声明】版权所有 www.chinapyg.com blitz[P.Y.G]
[ 本帖最后由 blitz 于 2007-12-1 12:20 编辑 ] |
|