• 标 题:算法分析: <献给初学者> 之四 (9千字)
  • 作 者:ccmc[P.J.CHINA]
  • 时 间:2002-6-6 22:32:34
  • 链 接:http://bbs.pediy.com

算法分析:  <献给初学者> 之四

▲ 作  者 : goodbao[P.J.CHINA]

▲软件名称:象棋大战 v1.05

▲下载地址:
http://www.softreg.com/shareware_view.asp?id={31EC207B-10AC-4216-86C7-7A3C4058B0EA}

▲软件简介:
  一款不错的象棋游戏,采用DirectDraw编程,标准Window游戏界面,画面精美,支持人机对战,双人对战。

▲破解难度:非明码比较,较难(反正我是没有跟踪明码,直接看算法就会知道是非明码的。其实,如果使用“偷天换日大法”来破解的话,也可以很快破解成功的,只是需要改变跳转方向的地方稍显多了些。呵呵。。。。。。。。。。)

▲算法难度:较难

▲算法分析▲
  这又是一个非明码的共享软件。应该说其加密并不怎么深奥,之所以把它的算法难度列为较难,是因为作为一名初学者,如果不认真细致地分析其算法的话,很容易失手的。所以,姑且这样评价吧。

  首先,应该说明的是:此款游戏的画面并非精美,而且有种回归DOS的感觉。况且其注册时,注册名是不参与算法之中的,所以注册名可以任意。再者,它的注册码必须有9位,多或少都不行。为什么?请随我来吧!准备好了吗?Let's go!!!!!!!!!

  设断、注册、拦截、清断,不必细说了吧?然后我们按11次F12,就会到达下边这里:

* Reference To: USER32.GetDlgItemTextA, Ord:0104h
|
:004071EC 8B35A8734100 mov esi, dword ptr [004173A8]
:004071F2 8D442440 lea eax, dword ptr [esp+40]
:004071F6 6A13 push 00000013
:004071F8 50 push eax
:004071F9 68E8030000 push 000003E8
:004071FE 53 push ebx
:004071FF FFD6 call esi
:00407201 8D4C2420 lea ecx, dword ptr [esp+20] ==>停在这里。F10直到
:00407205 6A1C push 0000001C
:00407207 51 push ecx

…… 略去 ……

:0040723E AE scasb
:0040723F F7D1 not ecx
:00407241 49 dec ecx
:00407242 83F909 cmp ecx, 00000009 ==>注册码是否是9位?
:00407245 0F85A9010000 jne 004073F4 ==>不是则跳,那就死喽!

==================算法开始===================

:0040724B 8A442420 mov al, byte ptr [esp+20]==>取第一位注册码的16进制值
:0040724F 3C4D cmp al, 4D =======>是否等于4D(即字母M)?
:00407251 740C je 0040725F =======>是就跳!如不是,那么……
:00407253 3C41 cmp al, 41 =======>是否等于41(即字母A)?
:00407255 7408 je 0040725F =======>是就跳!如不是,那么……
:00407257 3C4F cmp al, 4F =======>是否等于4F(即字母O)?
:00407259 0F8595010000 jne 004073F4 =======>全不是?对不起,死喽!!

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00407251(C), :00407255(C)
|
:0040725F 8A442421 mov al, byte ptr [esp+21]==>取第二位注册码的16进制值
:00407263 3C57 cmp al, 57 =======>是否等于57(即字母W)?
:00407265 7410 je 00407277 =======>是就跳!如不是,那么……
:00407267 3C45 cmp al, 45 =======>是否等于45(即字母E)?
:00407269 740C je 00407277 =======>是就跳!如不是,那么……
:0040726B 3C4E cmp al, 4E =======>是否等于4E(即字母N)?
:0040726D 7408 je 00407277 =======>是就跳!如不是,那么……
:0040726F 3C47 cmp al, 47 =======>是否等于47(即字母G)?
:00407271 0F857D010000 jne 004073F4 =======>还不是?惨喽,跳死啦!!

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00407265(C), :00407269(C), :0040726D(C)
|
:00407277 0FBE442422 movsx eax, byte ptr [esp+22]=>取第三位注册码的16进制值
并将此值赋给EAX
:0040727C 99 cdq
:0040727D B911000000 mov ecx, 00000011 =======>ECX=11(16进制)
:00407282 F7F9 idiv ecx =======>EAX除以ECX,余数送EDX
:00407284 85D2 test edx, edx =======>整除尽了吗?
:00407286 0F8568010000 jne 004073F4 =======>除不尽就跳死喽!!!!


:0040728C 8A442423 mov al, byte ptr [esp+23]====>取第四位注册码的16进制值
:00407290 3C4A cmp al, 4A =======>是否等于4A(即字母J)?
:00407292 7410 je 004072A4 =======>是就跳!如不是,那么……
:00407294 3C49 cmp al, 49 =======>是否等于49(即字母I)?
:00407296 740C je 004072A4 =======>是就跳!如不是,那么……
:00407298 3C41 cmp al, 41 =======>是否等于41(即字母A)?
:0040729A 7408 je 004072A4 =======>是就跳!如不是,那么……
:0040729C 3C4E cmp al, 4E =======>是否等于4E(即字母N)?
:0040729E 0F8550010000 jne 004073F4 =======>都不是呀?那死定喽!!!


* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00407292(C), :00407296(C), :0040729A(C)
|
:004072A4 8A442424 mov al, byte ptr [esp+24]====>取第五位注册码的16进制值
:004072A8 3C58 cmp al, 58 =======>是否等于58(即字母X)?
:004072AA 740C je 004072B8 =======>是就跳!如不是,那么……
:004072AC 3C49 cmp al, 49 =======>是否等于49(即字母I)?
:004072AE 7408 je 004072B8 =======>是就跳!如不是,那么……
:004072B0 3C55 cmp al, 55 =======>是否等于55(即字母U)?
:004072B2 0F853C010000 jne 004073F4 =======>还不是呀?完蛋啦!!!!


* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:004072AA(C), :004072AE(C)
|
:004072B8 0FBE442425 movsx eax, byte ptr [esp+25]=>取第六位注册码的16进制值
并将此值赋给EAX
:004072BD 99 cdq
:004072BE B903000000 mov ecx, 00000003 =======>ECX=03(16进制)
:004072C3 F7F9 idiv ecx =======>EAX除以ECX,余数送EDX
:004072C5 85D2 test edx, edx =======>整除尽了吗?
:004072C7 0F8527010000 jne 004073F4 =======>除不尽?完蛋啦!呜呜~~


:004072CD 8A442426 mov al, byte ptr [esp+26]====>取第七位注册码的16进制值
:004072D1 3C51 cmp al, 51 =======>是否等于51(即字母Q)?
:004072D3 7408 je 004072DD =======>是就跳!如不是,那么……
:004072D5 3C49 cmp al, 49 =======>是否等于49(即字母I)?
:004072D7 0F8517010000 jne 004073F4 =======>全不是?玩完大吉啦!!!


* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004072D3(C)
|
:004072DD 8A442427 mov al, byte ptr [esp+27]====>取第八位注册码的16进制值
:004072E1 3C59 cmp al, 59 =======>是否等于59(即字母Y)?
:004072E3 740C je 004072F1 =======>是就跳!如不是,那么……
:004072E5 3C55 cmp al, 55 =======>是否等于55(即字母U)?
:004072E7 7408 je 004072F1 =======>是就跳!如不是,那么……
:004072E9 3C4E cmp al, 4E =======>是否等于4E(即字母N)?
:004072EB 0F8503010000 jne 004073F4 =======>千万不能跳呀!!!!!!

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:004072E3(C), :004072E7(C)
|
:004072F1 0FBE442428 movsx eax, byte ptr [esp+28]=>取第九位注册码的16进制值
:004072F6 99 cdq
:004072F7 B90D000000 mov ecx, 0000000D =======>ECX=0D(16进制)
:004072FC F7F9 idiv ecx =======>EAX除以ECX,余数送EDX
:004072FE 85D2 test edx, edx =======>整除尽了吗?
:00407300 0F85EE000000 jne 004073F4 =======>千万不能跳呀!!!!!

▲以下略去…………▲

:00407306 8D4C2410 lea ecx, dword ptr [esp+10]
:0040730A E8F6960000 call 00410A05

* Possible StringData Ref from Data Obj ->"chess.mjq"
|
:0040730F BF78B14100 mov edi, 0041B178
:00407314 83C9FF or ecx, FFFFFFFF
:00407317 33C0 xor eax, eax
:00407319 8D542454 lea edx, dword ptr [esp+54]
:0040731D F2 repnz
:0040731E AE scasb
:0040731F F7D1 not ecx
:00407321 2BF9 sub edi, ecx
:00407323 C784246001000000000000 mov dword ptr [esp+00000160], 00000000
:0040732E 8BC1 mov eax, ecx
:00407330 8BF7 mov esi, edi
:00407332 8BFA mov edi, edx
:00407334 C644240F0B mov [esp+0F], 0B
:00407339 C1E902 shr ecx, 02
:0040733C F3 repz
:0040733D A5 movsd
:0040733E 8BC8 mov ecx, eax
:00407340 83E103 and ecx, 00000003
:00407343 F3 repz
:00407344 A4 movsb
:00407345 8D4C2454 lea ecx, dword ptr [esp+54]
:00407349 51 push ecx
:0040734A E8B1FDFFFF call 00407100
:0040734F 83C404 add esp, 00000004
:00407352 8D542454 lea edx, dword ptr [esp+54]
:00407356 8D4C2410 lea ecx, dword ptr [esp+10]
:0040735A 6A00 push 00000000
:0040735C 6802300000 push 00003002
:00407361 52 push edx
:00407362 E8B0970000 call 00410B17
:00407367 6A02 push 00000002
:00407369 6A00 push 00000000
:0040736B 8B442418 mov eax, dword ptr [esp+18]
:0040736F 8D4C2418 lea ecx, dword ptr [esp+18]
:00407373 FF5028 call [eax+28]
:00407376 6A01 push 00000001
:00407378 6AFF push FFFFFFFF
:0040737A 8D4C2418 lea ecx, dword ptr [esp+18]
:0040737E E836990000 call 00410CB9
:00407383 8D4C240F lea ecx, dword ptr [esp+0F]
:00407387 6A01 push 00000001
:00407389 51 push ecx
:0040738A 8D4C2418 lea ecx, dword ptr [esp+18]
:0040738E E8DB980000 call 00410C6E
:00407393 8D4C2410 lea ecx, dword ptr [esp+10]
:00407397 E896990000 call 00410D32
:0040739C 6A00 push 00000000
:0040739E 53 push ebx

* Reference To: USER32.ShowWindow, Ord:026Ah
|
:0040739F FF15AC734100 Call dword ptr [004173AC]
:004073A5 6A00 push 00000000

* Possible StringData Ref from Data Obj ->"谢谢"
|
:004073A7 68CCB14100 push 0041B1CC

* Possible StringData Ref from Data Obj ->"非常感谢您的注册!"
|
:004073AC 68B8B14100 push 0041B1B8
:004073B1 53 push ebx

▲算法总结▲
  写了这么多,真地有点儿累啦!好了,让我们总结一下吧!
第一位注册码:必须为M或A或O。
第二位注册码:必须为W或E或N或G。
第三位注册码:必须能被11(16进制)整除。
第四位注册码:必须为J或I或A或N。
第五位注册码:必须为X或I或U。
第六位注册码:必须能被03(16进制)整除。
第七位注册码:必须为Q或I。
第八位注册码:必须为Y或U或N。
第九位注册码:必须能被0D(16进制)整除。

  好累呀!!!!!呵呵,算法真地不是好搞的,只调试过程中的手抄、记录和调试后的算法分析就够让人受得了。哈哈!!!!!!!!!!!!!!

--------------------------------------------------------------------------------
   神龙宝宝
goodbao[P.J.CHINA][BCG][CNCG]