首页
社区
课程
招聘
[原创]XzzX#CrackMe1破文+注册机
发表于: 2007-5-31 22:10 8541

[原创]XzzX#CrackMe1破文+注册机

2007-5-31 22:10
8541

此乃本菜鸟第一篇破文,期待的高手指点,让和我一样的菜鸟能够有所进步...不说费话现在开始:
这个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中写的过程中程序还崩过一次,把我写的全
弄没了,弄得我差点想去跳楼.嘿嘿.
    由于是第一次写,所以错误在所难免了.希望各位大虾给我批评和指正,也希望和和我一样菜的鸟
一同研讨共同进步.


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 7
支持
分享
最新回复 (12)
雪    币: 244
活跃值: (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
2
把那个原文件和注册机传下,刚才在编辑时不能传,可能是网通的镜像不能上传,全是乱码...
上传的附件:
2007-5-31 22:26
0
雪    币: 1844
活跃值: (35)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
3
厉害+佩服啊。。。。。。。。。。。。。。。
2007-5-31 23:09
0
雪    币: 1969
活跃值: (46)
能力值: (RANK:550 )
在线值:
发帖
回帖
粉丝
4
分析的透彻,支持兄弟,
2007-6-1 08:30
0
雪    币: 206
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
支持,还是有点晕晕的,计算不复杂,就是拐的碗太多
2007-6-3 11:06
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
支持以下 辛苦分析。。
2007-6-3 12:55
0
雪    币: 1919
活跃值: (901)
能力值: ( LV9,RANK:490 )
在线值:
发帖
回帖
粉丝
7
支持+学习~~
2007-6-3 13:31
0
雪    币: 359
活跃值: (429)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
好强的分析能力,支持
2007-6-6 09:53
0
雪    币: 244
活跃值: (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
9
多谢各位兄弟的支持,让我更有信心啊!
2007-6-6 10:38
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
还没看完,先顶一下,确实拐了太多弯弯.头疼,我会坚持看完的,谢谢作者的辛勤劳动
2007-6-10 23:25
0
雪    币: 314
活跃值: (15)
能力值: ( LV12,RANK:410 )
在线值:
发帖
回帖
粉丝
11
好强的分析能力,支持
2007-6-12 21:20
0
雪    币: 41
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
非常棒!!!!!!!!!!
2009-8-18 17:53
0
雪    币: 92
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
我正寻觅楼主的脚步……
2009-12-24 19:19
0
游客
登录 | 注册 方可回帖
返回
//