题目:“摸着石头过河法”轻松获取LeapFtp2.7.2 版本注册码(2006元旦向各位看雪论坛大侠献礼)
软件名称:LeapFTP 2.72
文件大小:1018KB
适用平台:Win9x/Me/NT/2000
软件简介:功能强大,媲美Bullet Proof FTP的FTP软件。跟Netscape相仿的书签形式,连线更加方便。下载与上传文件支持续传。可下载或上传整个目录,亦可直接删除整个目录。可让你编列顺序一次下载或上传同一站台中不同目录下的文件。浏览网页时若在文件连结上按鼠标右键选“复制捷径”便会自动下载该文件。具有不会因闲置过久而被站台踢出的功能。可直接编辑远端Server上的文件。可设定文件传送完毕自动中断Modem连接。
破解时间:2005年12月28日
工具:只用一个法宝TRW足矣!当然也需要FI*_^

破解目的:了解注册码计算方法,找到注册码,可以写出注册机,不赞成暴力。

引子:今天闲来无事,在学习看雪精华III,偶尔瞥到LeapFtp2.7破解教程,我想起在我的《电脑报2001合订本》有这个软件,版本2.7.2,看起来细微的差别,我在没有参考精华III里面的文章的前提下,自己独立完成属于我自己的破解教程。等我写完了自己的教程然后再去看那几篇文章,以便对比各自的优缺点,这也是一种积极的学习方法。看到一些教程不要盲目的去亦步亦趋,完全可以先自己尝试做一下,如果没有搞明白再去参考那些大侠的教程,这样比较有针对性。我现在刚刚入门2个月,已经是10几篇菜鸟教程了,当然都比较浅显,大侠莫要取笑!我觉得如果自己破解了一个小东西,如果不写出来觉得心里不塌实。随着破解的深入,写的文章多了,自然水平就提高了。切听如下分解:

首先用FI查看是否带“甲克”,结果比较幸运,没有带壳。下面就顺利了。首先运行LeapFtp2.7.2,点击Help菜单,单击"Enter Registration Data",在弹出的对话框内输入用户名和注册码,这里注意注册码的格式为: mmmx-nnyn-pqpp-zzzz,其中m,n,p为大写字符,x,y,q为数字。(你也许会问“你咋知道的?”,回答我跟踪了一遍)。我输入的用户名bigpig,注册码AAA8-BB8B-C8CC-DDDD,Ctrl+N唤出TRW,下pbx  hmemcpy命令,F5退出,按OK按钮,拦下,按F10数次来到如下代码处。(有人问到底到哪里才合适呢?你看到代码后面不远处不存在RET这样的指令,就说明已经到了程序中心来了。)

0167:0048742A 8B45F8           MOV      EAX,[EBP-08]   
0167:0048742D 8D55FC           LEA      EDX,[EBP-04]   //在这里d eax 看到输入的假注册码
0167:00487430 E87B16F8FF       CALL     00408AB0      //该CALL检查两头是否带有空格,如果有则错误。
0167:00487435 80BBF402000000   CMP      BYTE [EBX+02F4],00
0167:0048743C 740E             JZ       0048744C       //如果注册码两头没有空格,自然不会跳走。
0167:0048743E 8B55FC           MOV      EDX,[EBP-04]
0167:00487441 8BC3             MOV      EAX,EBX
0167:00487443 E888030000       CALL     004877D0     //这个CALL是重点,F8跟入研究,注册算法就在这里啦。见后面代码分析。
0167:00487448 84C0             TEST     AL,AL
0167:0048744A 7526             JNZ      00487472       //通往光明之路,必须跳走。
0167:0048744C 8B83F0020000     MOV      EAX,[EBX+02F0]  
0167:00487452 50               PUSH     EAX
0167:00487453 8D55F4           LEA      EDX,[EBP-0C]
0167:00487456 8B83D0020000     MOV      EAX,[EBX+02D0]
0167:0048745C E867C5FAFF       CALL     004339C8
0167:00487461 8B55F4           MOV      EDX,[EBP-0C]
0167:00487464 8B4DFC           MOV      ECX,[EBP-04]
0167:00487467 8BC3             MOV      EAX,EBX
0167:00487469 E8BA010000       CALL     00487628 
0167:0048746E 84C0             TEST     AL,AL
0167:00487470 7462             JZ       004874D4         //如果程序在这里就跳转则OVER,所以不可以跳。
0167:00487472 8D55F0           LEA      EDX,[EBP-10]  //下面到4874D2都是在注册成功后对注册表进行写入键值的。
0167:00487475 8B83E4020000     MOV      EAX,[EBX+02E4]
0167:0048747B E848C5FAFF       CALL     004339C8
*
*略去10来行代码
*
0167:004874C4 8B55E8           MOV      EDX,[EBP-18]
0167:004874C7 8D83E8020000     LEA      EAX,[EBX+02E8]
0167:004874CD E806C8F7FF       CALL     00403CD8
0167:004874D2 EB15             JMP      SHORT 004874E9   //让程序从这里跳转则活。
0167:004874D4 6A00             PUSH     BYTE +00
0167:004874D6 668B0D3C754800   MOV      CX,[0048753C]
0167:004874DD B201             MOV      DL,01
0167:004874DF B848754800       MOV      EAX,00487548
0167:004874E4 E84333FDFF       CALL     0045A82C    //此CALL出现错误提示窗口
0167:004874E9 33C0             XOR      EAX,EAX
0167:004874EB 5A               POP      EDX
*
*略去10来行代码
*
0167:00487514 8BE5             MOV      ESP,EBP
0167:00487516 5D               POP      EBP
===========================
以下代码片段来自487443的调用,这是最精彩的地方了,慢慢看就明白了,其实很简单的。

0167:004877D0 55               PUSH     EBP
0167:004877D1 8BEC             MOV      EBP,ESP
0167:004877D3 83C4F4           ADD      ESP,BYTE -0C
0167:004877D6 53               PUSH     EBX
0167:004877D7 56               PUSH     ESI
0167:004877D8 57               PUSH     EDI
0167:004877D9 8955FC           MOV      [EBP-04],EDX
0167:004877DC 8B45FC           MOV      EAX,[EBP-04]
0167:004877DF E8D4C8F7FF       CALL     004040B8
0167:004877E4 33C0             XOR      EAX,EAX
0167:004877E6 55               PUSH     EBP
0167:004877E7 683D794800       PUSH     DWORD 0048793D
0167:004877EC 64FF30           PUSH     DWORD [FS:EAX]
0167:004877EF 648920           MOV      [FS:EAX],ESP
0167:004877F2 C645FB00         MOV      BYTE [EBP-05],00
0167:004877F6 8B45FC           MOV      EAX,[EBP-04]
0167:004877F9 E806C7F7FF       CALL     00403F04        //此函数获取注册码长度
0167:004877FE 83F813           CMP      EAX,BYTE +13   //判断是否为19位,不是则错。
0167:00487801 0F8520010000     JNZ      NEAR 00487927
0167:00487807 8B45FC           MOV      EAX,[EBP-04]
0167:0048780A 8078042D         CMP      BYTE [EAX+04],2D  //判断第5位是否为短杠 "-" ,不是则错。
0167:0048780E 0F8513010000     JNZ      NEAR 00487927  
0167:00487814 8B45FC           MOV      EAX,[EBP-04]
0167:00487817 8078092D         CMP      BYTE [EAX+09],2D //判断第10位是否为短杠 "-" ,不是则错。
0167:0048781B 0F8506010000     JNZ      NEAR 00487927
0167:00487821 8B45FC           MOV      EAX,[EBP-04]
0167:00487824 80780E2D         CMP      BYTE [EAX+0E],2D //判断第15位是否为短杠 "-" ,不是则错。
0167:00487828 0F85F9000000     JNZ      NEAR 00487927

0167:0048782E 33F6             XOR      ESI,ESI
0167:00487830 33FF             XOR      EDI,EDI
0167:00487832 33C0             XOR      EAX,EAX
0167:00487834 8945F4           MOV      [EBP-0C],EAX
0167:00487837 BB01000000       MOV      EBX,01
----------------循环开始---------------
0167:0048783C 8BC3             MOV      EAX,EBX
0167:0048783E 2503000080       AND      EAX,80000003 //EAX为注册码串的相对偏移量,跟3进行“逻辑与”运算,如果为结果0,则这个位置需要输入数字,而非字母。可以看出只有第4,8,12个位置是特殊位置。
0167:00487843 7905             JNS      0048784A              //不是负数则跳走,一般都是跳走了。
0167:00487845 48               DEC      EAX
0167:00487846 83C8FC           OR       EAX,BYTE -04
0167:00487849 40               INC      EAX
0167:0048784A 85C0             TEST     EAX,EAX        //测试“与”运算后的结果
0167:0048784C 7516             JNZ      00487864          //如果不为0,则跳走。否则对特别位置(第4,8,12个位置)进行特别检验。
0167:0048784E 8B45FC           MOV      EAX,[EBP-04]
0167:00487851 8A4418FF         MOV      AL,[EAX+EBX-01]
0167:00487855 E84EFFFFFF       CALL     004877A8          //此CALL就是检验“特殊位置”的字符是否是数字的。
0167:0048785A 84C0             TEST     AL,AL        
0167:0048785C 0F84C5000000     JZ       NEAR 00487927   //如果不是数字,则AL=0,那么只有死路一条。
0167:00487862 EB22             JMP      SHORT 00487886
0167:00487864 8BC3             MOV      EAX,EBX
0167:00487866 B905000000       MOV      ECX,05
0167:0048786B 99               CDQ     
0167:0048786C F7F9             IDIV     ECX
0167:0048786E 85D2             TEST     EDX,EDX
0167:00487870 7414             JZ       00487886
0167:00487872 8B45FC           MOV      EAX,[EBP-04]
0167:00487875 8A4418FF         MOV      AL,[EAX+EBX-01]
0167:00487879 E83EFFFFFF       CALL     004877BC      //此函数检测注册码是否为大写字符。如果不是则OVER。
0167:0048787E 84C0             TEST     AL,AL
0167:00487880 0F84A1000000     JZ       NEAR 00487927 

0167:00487886 8B45FC           MOV      EAX,[EBP-04]   //从此处开始对注册码分段求和,第一段的和放在ESI内,第二段的和放在EDI内,第三段的和放在[EBP-0C]的内存。
0167:00487889 8A4418FF         MOV      AL,[EAX+EBX-01]
0167:0048788D 3C2D             CMP      AL,2D                //比较是否是短杠 "-" 
0167:0048788F 742D             JZ       004878BE
0167:00487891 83FB05           CMP      EBX,BYTE +05    //比较计数器EBX是否超过5,如果未超过,则下面对第一段求和
0167:00487894 7D0C             JNL      004878A2

0167:00487896 8B55FC           MOV      EDX,[EBP-04]
0167:00487899 25FF000000       AND      EAX,FF           //取出EAX低字节
0167:0048789E 03F0             ADD      ESI,EAX              //保存到ESI,ESI保存和值,即第一段的和。
0167:004878A0 EB1C             JMP      SHORT 004878BE

0167:004878A2 83FB0A           CMP      EBX,BYTE +0A //计数器是否超过10,如果没有超过,计算第二段的和。
0167:004878A5 7D0C             JNL      004878B3            //计数器超过10后,跳到4878B3处。
0167:004878A7 8B55FC           MOV      EDX,[EBP-04]
0167:004878AA 25FF000000       AND      EAX,FF             //取出EAX低字节
0167:004878AF 03F8             ADD      EDI,EAX               //保存到EDI,EDI保存和值,即第二段的和。
0167:004878B1 EB0B             JMP      SHORT 004878BE

0167:004878B3 8B55FC           MOV      EDX,[EBP-04]   
0167:004878B6 25FF000000       AND      EAX,FF
0167:004878BB 0145F4           ADD      [EBP-0C],EAX    //第三段累加和放在 [EBP-0C]内存。

0167:004878BE 43               INC      EBX                    //计数器增1。上面累加完毕都跳到这里。
0167:004878BF 83FB0F           CMP      EBX,BYTE +0F    //计数器是否到达15?
0167:004878C2 0F8574FFFFFF     JNZ      NEAR 0048783C   //如果没有到达15,则循环返回48783C。继续上述工作。
----------------循环结束---------------

下面的代码计算第四段注册码,使用前面得到的3段注册码来得到第四段注册码,非常简单。

0167:004878C8 8D0C37           LEA      ECX,[EDI+ESI]  // 第一段累加和ESI和第二段累加和EDI相加送ECX保存。
0167:004878CB 034DF4           ADD      ECX,[EBP-0C]  // ECX和第三段和值相加,结果放在ECX内备用。
1.下面取第一段注册码(在ESI内)计算第16个字符
0167:004878CE 8BC6             MOV      EAX,ESI
0167:004878D0 BB1A000000       MOV      EBX,1A
0167:004878D5 99               CDQ             //双字扩展,把EAX符号位扩展到EDX,形成8个字节的被除数。
0167:004878D6 F7FB             IDIV     EBX             //EAX和EDX组成的被除数除以十进制的26,余数(实际上是26个字母的序号)在EDX。
0167:004878D8 83C241           ADD      EDX,BYTE +41 //EDX加上41H形成大写字母
0167:004878DB 8B45FC           MOV      EAX,[EBP-04]  //假注册码起始地址送EAX。
0167:004878DE 3A500F           CMP      DL,[EAX+0F]  //取出第16个字符与DL比较,如果不相同则失败。此时为了能够继续调试,输入e命令,回车,即可修改你想修改的内存单元,把第16个字符改成和DL的值一样即可。
0167:004878E1 7544             JNZ      00487927
2.下面只取第二段注册码(在EDI内)计算第17个字符,方法同上,不要忘记用E命令修改你的内存单元注册码值;
0167:004878E3 8BC7             MOV      EAX,EDI
0167:004878E5 BB1A000000       MOV      EBX,1A
0167:004878EA 99               CDQ     
0167:004878EB F7FB             IDIV     EBX
0167:004878ED 83C241           ADD      EDX,BYTE +41
0167:004878F0 8B45FC           MOV      EAX,[EBP-04]
0167:004878F3 3A5010           CMP      DL,[EAX+10]
0167:004878F6 752F             JNZ      00487927
3.下面只取第三段注册码(在[EBP-0C]内)计算第18个字符,方法同上,不要忘记用E命令修改你的内存单元注册码值;
0167:004878F8 8B45F4           MOV      EAX,[EBP-0C]
0167:004878FB BB1A000000       MOV      EBX,1A
0167:00487900 99               CDQ     
0167:00487901 F7FB             IDIV     EBX
0167:00487903 83C241           ADD      EDX,BYTE +41
0167:00487906 8B45FC           MOV      EAX,[EBP-04]
0167:00487909 3A5011           CMP      DL,[EAX+11]
0167:0048790C 7519             JNZ      00487927
4.下面用三段注册码总和(在ECX内)计算第19个字符,方法同上,不要忘记用E命令修改你的内存单元注册码值;
0167:0048790E 8BC1             MOV      EAX,ECX
0167:00487910 B91A000000       MOV      ECX,1A
0167:00487915 99               CDQ     
0167:00487916 F7F9             IDIV     ECX
0167:00487918 83C241           ADD      EDX,BYTE +41
0167:0048791B 8B45FC           MOV      EAX,[EBP-04]
0167:0048791E 3A5012           CMP      DL,[EAX+12]
0167:00487921 7504             JNZ      00487927

0167:00487923 C645FB01         MOV      BYTE [EBP-05],01
*
*略去10来行代码
*
0167:0048794C 5D               POP      EBP
0167:0048794D C3               RET     
===========================
下面是487855的 CALL     004877A8 调用的函数模块。功能:检查是否是数字,不是则错。
:004877A8 8BD0                    mov edx, eax
:004877AA 80FA2F                  cmp dl, 2F
:004877AD 7608                    jbe 004877B7      //字符ASCII值小于2Fh则错。
:004877AF 80FA3A                  cmp dl, 3A
:004877B2 7303                    jnb 004877B7      //字符ASCII值大于3Ah则错。
:004877B4 B001                    mov al, 01
:004877B6 C3                      ret
:004877B7 33C0                    xor eax, eax
:004877B9 C3                      ret

下面是487879的 CALL     004877BC 调用的函数模块。功能:检查是否是大写字母,不是则错。
0167:004877BC 8BD0             MOV      EDX,EAX
0167:004877BE 80FA40           CMP      DL,40         
0167:004877C1 7608             JNA      004877CB  //不大于40H则失败。
0167:004877C3 80FA5B           CMP      DL,5B
0167:004877C6 7303             JNC      004877CB  //不小于5BH则失败。
0167:004877C8 B001             MOV      AL,01
0167:004877CA C3               RET     
0167:004877CB 33C0             XOR      EAX,EAX
0167:004877CD C3               RET    
===========================
后记:

通过跟踪这个注册码验证过程,我们就可以轻松得到注册码,比如我原来输入的注册码是AAA8-BB8B-C8CC-DDDD,经过修正变成了 AAA8-BB8B-C8CC-RUXI,只有第四段被修改即可。
第一段:ESI=AAA8 =41h+41h+41h+38h=FBh
第二段:EDI=BB8B =42h+42h+38h+42h=FEh
第三段:[EBP-0C]=C8CC =43h+38h+43h+43h=101h
第四段:ESI/1A..... 余11h,加41h=52h=R
              EDI/1A..... 余14h,加41h=55h=U
              [EBP-0C]/1A..... 余17h,加41h=58h=X
              [ECX]/1A..... 余8h,加41h=49h=I

用了30分钟破解,可是用了1个小时写教程,注册机等有时间再写吧。:)算是在元旦来临之际送给菜鸟们的一份礼物吧!祝元旦快乐!

行文中如有不当之处请指出为盼。Emailto:qduwg@163.com

QduWg
2005/12/28