【破文标题】:专业扫雷注册算法分析
【破文作者】: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 本文纯属技术交流, 转载请注明作者并保持文章的完整, 谢谢!
[注意]APP应用上架合规检测服务,协助应用顺利上架!
上传的附件: