此乃本菜鸟第一篇破文,期待的高手指点,让和我一样的菜鸟能够有所进步...不说费话现在开始:
这个Crackme是我从www.crakmes.de下载的,原程序下载链接:
http://www.crackmes.de/users/xzzx/xzzxcrackme1/
先运行下程序看看有什么特点,输入用户名和注册码,CHECK,会跳出注册错误的对话框.
好,现在打开OD,在GetDlgItemTextA下断,看下能不能在这断下.
断下了:
004012F2 /$ 6A 1E PUSH 1E ; /Count = 1E (30.)
004012F4 |. 68 D4304000 PUSH XzzX#Cra.004030D4 ; |Buffer = XzzX#Cra.004030D4
004012F9 |. 68 59980000 PUSH 9859 ; |ControlID = 9859 (39001.)
004012FE |. FF35 D0304000 PUSH DWORD PTR DS:[4030D0] ; |hWnd = 00100B14
00401304 |. E8 C5030000 CALL <JMP.&user32.GetDlgItemTextA> ; \GetDlgItemTextA
00401309 |. 83F8 08 CMP EAX,8 //这里比较我们输入的用0040130C |. 73 18 JNB SHORT XzzX#Cra.00401326 //户名是否小于8位,是就跳
0040130E |. 6A 00 PUSH 0 ; /Style =MB_APPLMODAL
00401310 |. 68 0E304000 PUSH XzzX#Cra.0040300E ; |Title = "XzzX#CrackMe1"
00401315 |. 68 78304000 PUSH XzzX#Cra.00403078 ; |Text = "Name is too short!"
0040131A |. FF35 D0304000 PUSH DWORD PTR DS:[4030D0] ; |hOwner = 00100B14
00401320 |. E8 C1030000 CALL <JMP.&user32.MessageBoxA> ; \MessageBoxA
00401325 |. C3 RETN
00401326 |> BB D4304000 MOV EBX,XzzX#Cra.004030D4
0040132B |. 33C9 XOR ECX,ECX
0040132D |. 33C0 XOR EAX,EAX
0040132F |. 8A0419 MOV AL,BYTE PTR DS:[ECX+EBX]
00401332 |. EB 09 JMP SHORT XzzX#Cra.0040133D //这一段是对我们的用户名进行处理
00401334 |> 34 C5 /XOR AL,0C5 //把每一位与0XC5异或并把结果存到
00401336 |. 880419 |MOV BYTE PTR DS:[ECX+EBX],AL //XzzX#Cra.004030D4这一片中....
00401339 |. 41 |INC ECX
0040133A |. 8A0419 |MOV AL,BYTE PTR DS:[ECX+EBX]
0040133D |> 0BC0 OR EAX,EAX
0040133F |.^ 75 F3 \JNZ SHORT XzzX#Cra.00401334
00401341 |. 68 7E164000 PUSH XzzX#Cra.0040167E
00401346 |. 68 E3134000 PUSH XzzX#Cra.004013E3
0040134B |. 6A 1E PUSH 1E ; /Count = 1E (30.)
0040134D |. 68 F2304000 PUSH XzzX#Cra.004030F2 ; |Buffer = XzzX#Cra.004030F2
00401352 |. 68 5A980000 PUSH 985A ; |ControlID = 985A (39002.)
00401357 |. FF35 D0304000 PUSH DWORD PTR DS:[4030D0] ; |hWnd = 00100B14
0040135D |. E8 6C030000 CALL <JMP.&user32.GetDlgItemTextA> ; \GetDlgItemTextA
00401362 |. BB F2304000 MOV EBX,XzzX#Cra.004030F2 //把注册码输入进来.同样也
00401367 |. 33C9 XOR ECX,ECX //做一定处理,看下面
00401369 |. 33C0 XOR EAX,EAX
0040136B |. 8A0419 MOV AL,BYTE PTR DS:[ECX+EBX]
0040136E |. FF0D D0304000 DEC DWORD PTR DS:[4030D0]
00401374 |. EB 09 JMP SHORT XzzX#Cra.0040137F //把每一位和0X78与,结果存到
00401376 |> 34 78 /XOR AL,78 //zzX#Cra.004030F2中
00401378 |. 880419 |MOV BYTE PTR DS:[ECX+EBX],AL
0040137B |. 41 |INC ECX
0040137C |. 8A0419 |MOV AL,BYTE PTR DS:[ECX+EBX]
0040137F |> 0BC0 OR EAX,EAX
00401381 |.^ 75 F3 \JNZ SHORT XzzX#Cra.00401376
00401383 |. E8 01000000 CALL XzzX#Cra.00401389
00401388 \. C3 RETN
在下面我们找不到关键跳,那就在那个错误对话框MessageBoxA处下断,F9运行,断在下面:
0040167E . E8 70FDFFFF CALL XzzX#Cra.004013F3
00401683 . 3D B77A5CAB CMP EAX,AB5C7AB7
00401688 . 75 19 JNZ SHORT XzzX#Cra.004016A3 //这就是关键跳了.
0040168A . 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL
0040168C . 68 0E304000 PUSH XzzX#Cra.0040300E ; |Title = "XzzX#CrackMe1"
00401691 . 68 33304000 PUSH XzzX#Cra.00403033 ; |Text = "Correct! Now write a tutorial!"
00401696 . FF35 D0304000 PUSH DWORD PTR DS:[4030D0] ; |hOwner = 00220474
0040169C . E8 45000000 CALL <JMP.&user32.MessageBoxA> ; \MessageBoxA
004016A1 . EB 17 JMP SHORT XzzX#Cra.004016BA
004016A3 > 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL
004016A5 . 68 0E304000 PUSH XzzX#Cra.0040300E ; |Title = "XzzX#CrackMe1"
004016AA . 68 52304000 PUSH XzzX#Cra.00403052 ; |Text = "Sorry, wrong name/serial combination!"
004016AF . FF35 D0304000 PUSH DWORD PTR DS:[4030D0] ; |hOwner = 00220474
004016B5 . E8 2C000000 CALL <JMP.&user32.MessageBoxA> ; \MessageBoxA
004016BA > C3 RETN
哈哈,看到那个关键跳没?想要爆破,把这里的JNZ改为JZ就完事,不过咱们不能老停在爆破的阶段不是?嘿嘿,接着分析,把它的注册机给写出来!
在跳的地方往上看看,有个CALL,出来后就看看EAX里的值是不是AB5C7AB7,嘿嘿,在那个CALL的地方下断,单步进去看看它在干什么!
004013F3 /$ 55 PUSH EBP
004013F4 |. 8BEC MOV EBP,ESP
004013F6 |. 83C4 F8 ADD ESP,-8
004013F9 |. C745 FC 00000>MOV DWORD PTR SS:[EBP-4],0
00401400 |. C745 F8 00000>MOV DWORD PTR SS:[EBP-8],0
00401407 |. BB D4304000 MOV EBX,XzzX#Cra.004030D4 //看到这个地址,你熟悉吗?
0040140C |. 33C9 XOR ECX,ECX //忘了?回去看看咱们用户
0040140E |. BF DEFDD7F7 MOV EDI,F7D7FDDE //经过处理后存在哪了.知道了吧.
00401413 |. 33C0 XOR EAX,EAX
00401415 |. 8A0419 MOV AL,BYTE PTR DS:[ECX+EBX]
00401418 |. EB 0E JMP SHORT XzzX#Cra.00401428 //下面一段处理用户名并把
0040141A |> 33D2 /XOR EDX,EDX
0040141C |. 8AD0 |MOV DL,AL //处理结果放入SS:[EBP-4]中
0040141E |. 0355 FC |ADD EDX,DWORD PTR SS:[EBP-4]
00401421 |. 8955 FC |MOV DWORD PTR SS:[EBP-4],EDX
00401424 |. 41 |INC ECX
00401425 |. 8A0419 |MOV AL,BYTE PTR DS:[ECX+EBX]
00401428 |> 0BC0 OR EAX,EAX
0040142A |.^ 75 EE \JNZ SHORT XzzX#Cra.0040141A
0040142C |. BB F2304000 MOV EBX,XzzX#Cra.004030F2 //注册码处理后的结果地址.
00401431 |. 33C9 XOR ECX,ECX
00401433 |. 33C0 XOR EAX,EAX
00401435 |. 8A0419 MOV AL,BYTE PTR DS:[ECX+EBX] //下面就是处理注册码并把
00401438 |. EB 0E JMP SHORT XzzX#Cra.00401448 //结果放入[EBP-8]中
0040143A |> 33D2 /XOR EDX,EDX
0040143C |. 8AD0 |MOV DL,AL
0040143E |. 0355 F8 |ADD EDX,DWORD PTR SS:[EBP-8]
00401441 |. 8955 F8 |MOV DWORD PTR SS:[EBP-8],EDX
00401444 |. 41 |INC ECX
00401445 |. 8A0419 |MOV AL,BYTE PTR DS:[ECX+EBX]
00401448 |> 0BC0 OR EAX,EAX
0040144A |.^ 75 EE \JNZ SHORT XzzX#Cra.0040143A
0040144C |. 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4] //下面是对两个结果进行
0040144F |. 8B5D F8 MOV EBX,DWORD PTR SS:[EBP-8] //一定的运算
00401452 |. 0FAFC3 IMUL EAX,EBX
00401455 |. 23C7 AND EAX,EDI
00401457 |. C9 LEAVE
00401458 \. C3 RETN
看到这你可能认为已经完了,只须去分析那几个地方的算法就可以写注册机了.如果是这样,那你就上了作者的当了.哈哈.
我们先来简单看看最后几步,他不是要EAX的值和AB5C7AB7相等吗,我们看看EAX最后是在哪改动的,啊,是这里:00401455 |. 23C7 AND EAX,EDI
那EDI又是什么呢?向上找找,看看能不能找到最近一次赋值.找到了:
0040140E |. BF DEFDD7F7 MOV EDI,F7D7FDDE
原来是和F7D7FDDE与,再和AB5C7AB7比较,相等就对了.嘿嘿,那与之前的EAX应该是什么呢.与是没有逆运算的,我们把这两个值换成二制看看:
AB5C7AB7---10101011010111000111101010110111
--------------------------------
F7D7FDDE---11110111110101111111110111011110
哈哈,看出什么来没?你能不能把与之前EAX的值推出来?如果你说能那你就只能是神了...
在数据的第二位,操作数是0,而结果是1,你能找出一个数和0与结果是1吗?......
也就是说这里的EAX永远也不可能是F7D7FDDE,那么就永远也跳不到那个正确的地方.
嘿嘿,这时候你可能会说这是个CRACKME有BUG,可作者却说没有...我在这里也郁闷了...恨不到去暴虐下那个变态作者...
不过我见不到那个变态的外国作者,没办法,只能拿他的CRACKME出出气了.
不费话了,进入正题.
这个不可能是正确的注册算法,那里才是呢?想了老半天也不得要领,突然想到我们输入了用户和注册后程序中间还有一段
不知道在干什么的东东,去看看,没准会有发现.嘿嘿...
来到输入注册信息后的那个CALL:
00401383 |. E8 01000000 CALL XzzX#Cra.00401389
步进去看看,好像没发现什么.
接着看吧...
RETN完后就来到下面:
004013E3 . 68 EE154000 PUSH XzzX#Cra.004015EE
004013E8 . 68 59144000 PUSH XzzX#Cra.00401459
004013ED . E8 77010000 CALL XzzX#Cra.00401569
进到那个CALL中去看看.
哈哈,看到下面的第一句没?JMP.&user32.GetDlgItemTextA!!!好像又要去取我们刚才输入的信息了.机会,得抓住了.下面得看仔细点了,嘿嘿.
00401569 $ BB CE164000 MOV EBX,<JMP.&user32.GetDlgItemTextA> ; 入口地址
0040156E . FF05 D0304000 INC DWORD PTR DS:[4030D0]
00401574 . 6A 1E PUSH 1E
00401576 . 68 10314000 PUSH XzzX#Cra.00403110
0040157B . 68 59980000 PUSH 9859
00401580 . FF35 D0304000 PUSH DWORD PTR DS:[4030D0]
00401586 . B8 91154000 MOV EAX,XzzX#Cra.00401591
0040158B . 33C9 XOR ECX,ECX
0040158D . FFE0 JMP EAX
进入到这里时你仔细看它跳转的地方!!!是不是看不到,那你看看EAX的值!EAX=00401591,这个是地址,去这看看,没有?
不是没有,其实是00401590的后半部分了.唉,这个程序玩了好多这样的把戏,把我差点弄得拿电脑出气了....
现在小心地按F8,OD就会闪一下,程序的源代码就会一下变个样,不过这才是真正的执行过程......
(这时不随便动鼠标滚轮,要不又变了,那程序就看不清晰了.)变为下面的这样:
00401591 ? FFD3 CALL EBX //此处又是去取用户名了.
00401593 ? BB 10314000 MOV EBX,XzzX#Cra.00403110 //这里OD可能会跳出一个对话,不管它,点"是"就行了.
00401598 . 33C9 XOR ECX,ECX
0040159A . 33C0 XOR EAX,EAX
0040159C . 8A0419 MOV AL,BYTE PTR DS:[ECX+EBX]
0040159F . EB 09 JMP SHORT XzzX#Cra.004015AA //下面又对用户名进行处理了,并把结果保存到
004015A1 > 34 E8 XOR AL,0E8 //XzzX#Cra.00403110里去了.哈哈,这里才是真正的
004015A3 . 880419 MOV BYTE PTR DS:[ECX+EBX],AL //处理用户名啊.
004015A6 . 41 INC ECX //过程是对每一位用户名和0XE8异或
004015A7 . 8A0419 MOV AL,BYTE PTR DS:[ECX+EBX]
004015AA > 0BC0 OR EAX,EAX
004015AC .^ 75 F3 JNZ SHORT XzzX#Cra.004015A1
004015AE . BB CE164000 MOV EBX,<JMP.&user32.GetDlgItemTextA> // 入口地址 又去取注册码了.
004015B3 . 6A 1E PUSH 1E
004015B5 . 68 2E314000 PUSH XzzX#Cra.0040312E ; ASCII "# !&'$%*+"
004015BA . 68 5A980000 PUSH 985A
004015BF . FF35 D0304000 PUSH DWORD PTR DS:[4030D0]
004015C5 . B8 D0154000 MOV EAX,XzzX#Cra.004015D0
004015CA . 33C9 XOR ECX,ECX
004015CC . FFE0 JMP EAX //这里又有一个像上面的跳转了,下面就是处理
//注册码了,还是要小心
F8后代码又变为下面的了:
004015D0 ? FFD3 CALL EBX ; <JMP.&user32.GetDlgItemTextA>
004015D2 ? BB 2E314000 MOV EBX,XzzX#Cra.0040312E ; ASCII "# !&'$%*+"
004015D7 . 33C9 XOR ECX,ECX
004015D9 . 33C0 XOR EAX,EAX
004015DB . 8A0419 MOV AL,BYTE PTR DS:[ECX+EBX]
004015DE . EB 09 JMP SHORT XzzX#Cra.004015E9 //处理注册码啊,不详说,很简单的,
004015E0 > 34 12 XOR AL,12 //对每一位注册码去和0X12异或.并存入0040312E
004015E2 . 880419 MOV BYTE PTR DS:[ECX+EBX],AL
004015E5 . 41 INC ECX
004015E6 . 8A0419 MOV AL,BYTE PTR DS:[ECX+EBX]
004015E9 > 0BC0 OR EAX,EAX
004015EB .^ 75 F3 JNZ SHORT XzzX#Cra.004015E0
004015ED . C3 RETN
到这里,才真正的对注册码和用户名进行了处理.咱们接分析,工作才做了一点点呢...
接下来咱们就到下面了:
00401459 /. 55 PUSH EBP
0040145A |. 8BEC MOV EBP,ESP
0040145C |. 83C4 F0 ADD ESP,-10
0040145F |. C745 FC 00000>MOV DWORD PTR SS:[EBP-4],0
00401466 |. C745 F8 00000>MOV DWORD PTR SS:[EBP-8],0
0040146D |. C745 F4 00000>MOV DWORD PTR SS:[EBP-C],0
00401474 |. C745 F0 00000>MOV DWORD PTR SS:[EBP-10],0
0040147B |. BB 10314000 MOV EBX,XzzX#Cra.00403110
00401480 |. 33C9 XOR ECX,ECX
00401482 |. 33C0 XOR EAX,EAX
00401484 |. 8A0419 MOV AL,BYTE PTR DS:[ECX+EBX]
00401487 |. EB 18 JMP SHORT XzzX#Cra.004014A1
00401489 |> 33D2 /XOR EDX,EDX
0040148B |. 8AD0 |MOV DL,AL
0040148D |. 0355 FC |ADD EDX,DWORD PTR SS:[EBP-4]
00401490 |. 8955 FC |MOV DWORD PTR SS:[EBP-4],EDX //每一位注册名累加到[EBP-4]
00401493 |. 33D2 |XOR EDX,EDX
00401495 |. 8AD0 |MOV DL,AL
00401497 |. 3355 F8 |XOR EDX,DWORD PTR SS:[EBP-8]
0040149A |. 8955 F8 |MOV DWORD PTR SS:[EBP-8],EDX //每一位注册名和[EBP-8]异或
0040149D |. 41 |INC ECX //并存回[EBP-8]
0040149E |. 8A0419 |MOV AL,BYTE PTR DS:[ECX+EBX]
004014A1 |> 0BC0 OR EAX,EAX
004014A3 |.^ 75 E4 \JNZ SHORT XzzX#Cra.00401489
004014A5 |. BB 2E314000 MOV EBX,XzzX#Cra.0040312E ; ASCII "# !&'$%*+"
004014AA |. 33C9 XOR ECX,ECX
004014AC |. 33C0 XOR EAX,EAX
004014AE |. 33D2 XOR EDX,EDX
004014B0 |. 8A0419 MOV AL,BYTE PTR DS:[ECX+EBX]
004014B3 |. EB 49 JMP SHORT XzzX#Cra.004014FE
004014B5 |> 34 12 /XOR AL,12 //把处理后的注册码又异或回去
004014B7 |. 3C 2D |CMP AL,2D //看是否是'-',是就把压缩的BCD
004014B9 |. 75 07 |JNZ SHORT XzzX#Cra.004014C2 //码放入[EBP-C]里面
004014BB |. 8955 F4 |MOV DWORD PTR SS:[EBP-C],EDX
004014BE |. 33D2 |XOR EDX,EDX
004014C0 |. EB 38 |JMP SHORT XzzX#Cra.004014FA
004014C2 |> BF CE144000 |MOV EDI,XzzX#Cra.004014CE
004014C7 |. 33F6 |XOR ESI,ESI
004014C9 |. 75 02 |JNZ SHORT XzzX#Cra.004014CD
004014CB |. FFE7 |JMP EDI
004014CD |> 6A 3C |PUSH 3C
004014CF |. 61 |POPAD
004014D0 |. 72 0D |JB SHORT XzzX#Cra.004014DF
004014D2 |. 3C 66 |CMP AL,66 //这里看否是a~f
004014D4 |. 77 09 |JA SHORT XzzX#Cra.004014DF
004014D6 |. 2C 57 |SUB AL,57
004014D8 |. C1E2 04 |SHL EDX,4
004014DB |. 0AD0 |OR DL,AL
004014DD |. EB 1B |JMP SHORT XzzX#Cra.004014FA
004014DF |> BF EB144000 |MOV EDI,XzzX#Cra.004014EB
004014E4 |. 33F6 |XOR ESI,ESI
004014E6 |. 75 02 |JNZ SHORT XzzX#Cra.004014EA
004014E8 |. FFE7 |JMP EDI
004014EA |> 6A 3C |PUSH 3C //这里处理数字0~9
004014EC |. 3072 0B |XOR BYTE PTR DS:[EDX+B],DH
004014EF |. 3C 39 |CMP AL,39
004014F1 |. 77 07 |JA SHORT XzzX#Cra.004014FA
004014F3 |. 2C 30 |SUB AL,30
004014F5 |. C1E2 04 |SHL EDX,4
004014F8 |. 0AD0 |OR DL,AL
004014FA |> 41 |INC ECX
004014FB |. 8A0419 |MOV AL,BYTE PTR DS:[ECX+EBX]
004014FE |> 0BC0 OR EAX,EAX
00401500 |.^ 75 B3 \JNZ SHORT XzzX#Cra.004014B5
00401502 |. 8955 F0 MOV DWORD PTR SS:[EBP-10],EDX //下面的这些就是两个运算
00401505 |. 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4]
00401508 |. 8B5D F4 MOV EBX,DWORD PTR SS:[EBP-C]
0040150B |. 8B4D F0 MOV ECX,DWORD PTR SS:[EBP-10]
0040150E |. 6BDB 40 IMUL EBX,EBX,40
00401511 |. 69C9 C3000000 IMUL ECX,ECX,0C3
00401517 |. 03D9 ADD EBX,ECX
00401519 |. 2BC3 SUB EAX,EBX
0040151B |. 85C0 TEST EAX,EAX
0040151D |. 75 16 JNZ SHORT XzzX#Cra.00401535
0040151F |. 8B45 F8 MOV EAX,DWORD PTR SS:[EBP-8]
00401522 |. 8B5D F4 MOV EBX,DWORD PTR SS:[EBP-C]
00401525 |. 8B4D F0 MOV ECX,DWORD PTR SS:[EBP-10]
00401528 |. 6BDB 55 IMUL EBX,EBX,55
0040152B |. 69C9 03010000 IMUL ECX,ECX,103
00401531 |. 03D9 ADD EBX,ECX
00401533 |. 2BC3 SUB EAX,EBX
00401535 |> C9 LEAVE
00401536 \. C3 RETN
其中就有对用户名和注册码分别进行运算.看看最后面的是不是跟我们刚开始分析的有点
相同?不过这个对注册码的运算就比那个要复杂点.而且在分析注册码时又有我们刚刚分析
的那种情况,跳到一段代码的中间...看到这就郁闷...代码太长,我就不详细说明了(代码
后面有些注解,可以参考下).大致的算法是这样的:
对经过处理后的用户名(在00403110里面,忘记了的看上面)每一位累加,放到SS:[EBP-4]
里面.注册码的里面可以含有0~9和小写的a,b,c,d,e,f和-.把这些字符当作十六进制看待,并
把它们以压缩的BCD码的形式放到[EBP-10],当然这个里面只能是'-'后的最后8位,对于含-
的,就把它前面的8位注册码也以压缩的BCD码的形式放到[EBP-C]中.例如:如果我输入的
是:324536457583145-35918471978980958,则[EBP-10]中的是:0X78980958,[EBP-C]中的是
0x57583145.
最后对这些值进行如下判断:
[EBP-4]?=[EBP-C]*0X40+[EBP-10]*0XC3
[EBP-8]?=[EBP-C]*0X55+[EBP-10]*0X103
在这里面要注意有些跳转又是那种跳到指令中间的.
好,接着向下分析吧,出来后到了这:
004015EE . B9 19164000 MOV ECX,XzzX#Cra.00401619
004015F3 . 33DB XOR EBX,EBX
004015F5 . 75 02 JNZ SHORT XzzX#Cra.004015F9
004015F7 . FFE1 JMP ECX
这个跳转又是那种讨厌的跳了...让它跳吧,看它能跳到什么时候:
00401619 ? 0BC0 OR EAX,EAX
0040161B ? 75 31 JNZ SHORT XzzX#Cra.0040164E
这个跳转比较重要.跟着它跳吧:
0040164E . BB 59164000 MOV EBX,XzzX#Cra.00401659
00401653 . 33C9 XOR ECX,ECX
00401655 . FFE3 JMP EBX
又是这种跳~~~~~~无语了......
00401659 ? B8 52304000 MOV EAX,XzzX#Cra.00403052
0040165E ? BB F9154000 MOV EBX,XzzX#Cra.004015F9
00401663 . 33C9 XOR ECX,ECX
00401665 . 8A10 MOV DL,BYTE PTR DS:[EAX]
00401667 . 80FA 43 CMP DL,43
看到第一条后面的没?ASCII "Sorry, wrong name/serial combination!"
难道这是个错误的分支?那我们重新调试回到上个JNZ.
0040161B ? /75 31 JNZ SHORT XzzX#Cra.0040164E
0040161D . |BB 28164000 MOV EBX,XzzX#Cra.00401628
00401622 . |33C9 XOR ECX,ECX
00401624 . |FFE3 JMP EBX
在这个JNZ这,我们把右上角的寄存器Z的值改为1,让它不跳,去看看它干什么了.
又看到那个JMP了.这个弄完就去把作者打一顿!
00401628 ? B8 52304000 MOV EAX,XzzX#Cra.00403052
0040162D ? BB F9154000 MOV EBX,XzzX#Cra.004015F9
00401632 . 33C9 XOR ECX,ECX
00401634 . 8A10 MOV DL,BYTE PTR DS:[EAX]
00401636 . 80FA 53 CMP DL,53 //第一个字符是否为S
00401639 . 75 42 JNZ SHORT XzzX#Cra.0040167D
0040163B . EB 0A JMP SHORT XzzX#Cra.00401647
0040163D > 8A1401 MOV DL,BYTE PTR DS:[ECX+EAX]
00401640 . 321419 XOR DL,BYTE PTR DS:[ECX+EBX]
00401643 . 881401 MOV BYTE PTR DS:[ECX+EAX],DL
00401646 . 41 INC ECX
00401647 > 83F9 1F CMP ECX,1F
0040164A .^ 72 F1 JB SHORT XzzX#Cra.0040163D
0040164C . EB 2F JMP SHORT XzzX#Cra.0040167D
来到这里,有人可能会问这里也是"Sorry, wrong name/serial combination!"
啊,别急,向下看,看看它干什么了.
当我们一步一步看下去时,我们可以看到它正在把00403052里的值改为:
"Correct! Now write a tutorial!",哈哈,我们记下这个地址!
到这了是不是有点兴奋了?接下来程序就来到了我们一开始分析的那个错误的注册算法的
CALL,接下来看看以前跳转为错误的地方的Text变成什么了?
是不是"Correct! Now write a tutorial!"了?
接下来你是不是更兴奋了?但是为什么这里的字符串变了呢?看看上面我们记的那个地址,
和这里的
004016AA . 68 52304000 PUSH XzzX#Cra.00403052
是不是一样,嘿嘿.这个程序就是在那把这个字符改掉,变为正确的注册!也就是说不管你输
入什么都跳到这来!不过显示的字符会不一样!
现在再分析下那里的注册算法吧,以便我们写出算法,看看那两个表达式:
[EBP-4]?=[EBP-C]*0X40+[EBP-10]*0XC3
[EBP-8]?=[EBP-C]*0X55+[EBP-10]*0X103
如果相等则正确.[EBP-4]和[EBP-8]为我们的用户名处理后得到的,可以说是已知的,[EBP-C]
和[EBP-10]则是注册名的-的前半部分和后半部分得来的.那我们只要知道这两个部分,然后
把它连起来就可以,上面两个表达式可以看成一个方程组,有两个未知数,有唯一解!
解为:[EBP-C]=0x103*[EBP-4]-0xc3*[EBP-8]
[EBP-10]=0x55*[EBP-4]-0x40*[EBP-8]
以下是注册机C++源码:
#include<iostream>
using namespace std;
int main()
{
char name[100],c;
char sn[8];
int n=0;
unsigned int EBP8=0,EBP4=0,x;
cout<<"Input your name:\n";
cin>>name;
while(name[n]!='\0')
{
name[n]=name[n]^ 0xe8;
c=name[n];
x=c;
x=x&0x000000ff;
EBP4+=x;
EBP8=x^EBP8;
n++;
}
cout<<"Your SN is: "<<hex<<0x103*EBP4-0xc3*EBP8<<"-"<<0x40*EBP8-0x55*EBP4<<endl;
system("pause");
return 0;
}
到此结束,哈哈,这个破文杀了我不少脑细胞啊,在TXT中写的过程中程序还崩过一次,把我写的全
弄没了,弄得我差点想去跳楼.嘿嘿.
由于是第一次写,所以错误在所难免了.希望各位大虾给我批评和指正,也希望和和我一样菜的鸟
一同研讨共同进步.
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)