March 2006 Archives

[转帖]让注册码自己“跳”出来

| No Comments | No TrackBacks

大家都有使用共享软件的经验吧?为了生存许多共享软件作者都将软件设计成要注册才能使用其全部功能,如果不注册会怎么样呢?要么有使用时间限制,要么有功能限制。可有时在规定的时间内我们还想继续使用该软件,或者使用软件的全部的功能--只有使用了全部的功能后我们才能知道该软件到底怎么样,到底是否值得购买。此时,我们必须注册我们要使用的这个软件,可没有钱的我们该怎么办呢?到各大破解站点查找注册码?姑且不说是否有你要找的软件注册码,单说说如果软件出了新版本、破解站点没有来得及公布注册码你又该怎么办呢?我想答案应该是:自己动手,自力更生! 基本知识 可能有些朋友要说了:我不懂汇编语言能行吗?当然可以!我要说的方法只要你能跟着做就一定行的!先来说说共享软件破解的基本方法。我们知道,对软件解密大概有两类方法:动态解密和静态解密。动态解密是使用专门的解密软件如:SoftIce、Trw2000等软件跟踪注册码,在这个过程中要用解密软件加载运行你想解密的软件,然后设定相应的断点,再点击软件中“注册”之类的按钮,使其中断,再找到软件注册码计算、比较的地方,从中得到软件的注册码。整个过程是个动态跟踪的过程,故为动态解密;静态解密就是用W32Dasm、IDA Pro等解密软件反编译相应的软件,从程序的反汇编代码中、提示信息中找到对解密有用的东西,如“注册失败”、“注册成功”之类的信息,从这些信息中可以找到软件注册码计算、对比的地方,因为一般情况下,它们离得并不远。这个过程相对来说是静态的,所以称之为静态解密。我们今天要为您介绍的就是用静态分析法找到软件的注册码,并制作自己的“注册机”。具体说来,我们要用的软件就是W32Dasm,用来举例的软件就是木马终结者,用来制作“注册机”的软件是CrackCode。 先来介绍一下W32Dasm。W32Dasm是个非常不错的反汇编工具软件,可方便地反汇编程序,它能静态分析程序流程,也可动态分析程序。在原有的普通版的基础上,一些解密高手又开发出了W32Dasm 8.93黄金版,加强了对中文字符串的提取,可以完美显示中文字符串,绝对是反汇编的极品,解密者的屠龙宝刀!例如开心斗地主这个很好玩的共享软件,用黄金版对其反汇编可以直接看到注册码(对低版本的有效),普通版不能,您说它厉害不?W32Dasm 8.93黄金汉化版下载地址:http://person.longcity.net/home3/fpxfpx/pw32dasmgold.rar。 再来看一下我们要破解的这个软件:木马终结者。我想大家都用过木马终结者这个小软件吧?木马终结者是所有特洛伊木马的克星,是一个专门检查特洛伊木马的软件。它可以对你的电脑端口进行全方位扫描,从而可以发现那些狡猾的木马。木马终结者还可以关闭指定端口,让木马无用武之地,为你的网络安全保驾护航。木马终结者下载地址:http://www.ttian.net/downaqgj/notrojan2.zip。 最后再介绍一下用来制作注册机的软件CrackCode。CrackCode是国人开发的软件,这是个可以很方便地制作出自己的“注册机”的软件。之所以给注册机加上了引号,是因为用它来制作的“注册机”并不是真正的注册机,不过,令人惊奇的是用CrackCode制作的“注册机”在运行后,可以让注册码自己跳出来,直接显示在屏幕上! 事实上,CrackCode的出现主要是为了方便初学者。以前我们写注册机时,一般都要了解程式的算法,之后用汇编语言或C、C++、VB来把算法还原,这样做一个注册机一般都要花费不少的时间,并且要求制作者对汇编语言和编程有比较深入的了解,对于初学者来说,这是一件很困难的事情。许多初学者,有时他们能在内存中找到注册码,但却没有能力写出注册机来,这大大削弱了他们的积极性,还有更为可恶的事情,就是目前有不少的程序,它的注册码都与硬件有关,就是在每一台机上安装都有一个机身码,要把这个机身码E-MAIL给作者,作者把收到的机身码用注册程式算出注册码后再寄回给用户,一机一码的结果就是软件只能一机一用,不过,这样做给用户却造成了不少的麻烦,因为只要用户重装系统或升级主板等,就要重新去注册软件。对于这种程式,一般初学者只能在内存中找到自己机器的注册码,但这种注册码到了其它的机器上又不能用了,而自己又没有办法写出注册机来,为了解决这方面的问题,作者写了这个小软件,它可以从另一进程中取出注册码,并在屏幕中显示出来,同时,不需要你去了解注册程式的算法。CrackCode下载地址:http://www.pediy.com/tools/Patchers/crackcode/crackcode.zip。好了,现在我们可以正式开始了。 实战操作 1.破解软件 首先,检查木马终结者是否被加了壳。有的朋友可能要问了:“壳”是什么东西?“壳”不是东西^_^,它是一段专门负责保护软件不被非法修改或反编译的程序。它们一般都是先于程序运行,拿到控制权,然后完成保护软件的任务。经过加壳的软件在跟踪时已无法看到其真实的代码,因此可以起到保护软件的目的。目前,大多数的软件都加了“壳”,所以我们在破解软件前都要用工具检查软件是否加了“壳”,如果发现软件加了“壳”,就要手动或用专门的软件来脱去它的“壳”(好比先将甲鱼的壳给扒去,这样再对付甲鱼就容易多了--宰杀全由您!),然后再用解密软件来分析它。检查软件是否加了“壳”可以使用FileInfo或Language2000等软件。检查结果表明木马终结者用Aspack加的“壳”!用Unaspack脱壳即可(由于用Language2000检查软件是否加壳、用Unaspack脱壳都很简单,运行软件试试就清楚了,所以就不一步一步的详细介绍了)。 FileInfo下载地址:http://person.longcity.net/home1/fpx425/fi249.zip Language2000下载地址:http://person.longcity.net/home3/fpxfpx/HA_language2k451144_YY.zip Unaspeck下载地址:http://person.longcity.net/home3/fpxfpx/unaspack.rar 接下来,运行木马终结者,点击“注册”,随便填入名字和注册码,点击“确定”,弹出个对话框,显示“注册码错误!”,记住这个提示信息,我们下面要用到它。 现在,运行W32Dasm,点击“反汇编”菜单下的“打开文件”,在弹出的对话框中找到木马终结者的主软件NoTrojan2.exe将其载入,等一会儿,待反汇编结束,会在W32Dasm中出现反汇编的结果,如图所示(图1)。然后请点击“参考”菜单中的“串式参考”(图2),在弹出的“W32Dasm串式参考清单”中找到“注册码错误!”(图3),这是软件注册失败时出现的提示信息,前面讲过,它对我们非常有用!用鼠标双击“注册码错误!”,会找到如图所示画面(图4),在画面中我们可以看到“感谢你支持本软件”这样的信息,这是软件注册成功才会出现的信息。这说明真、假注册码比对的地方离此不远!那么到底在哪里才是比对的关键所在呢?在图4所示窗口中向上看!找哪段代码可以跳过这个错误的信息(我们为什么没有注册成功,那是因为在正确注册信息前有代码段跳过了这个正确的信息,所以我们就要查找是哪条语句使我们跳过了正确的程序流程、来到了错误的信息处),找啊找,咦!这里好像可以(图5)!在图5中,偏移地址0046BCBC处语句为: jne 0046BD76,意思是如果不等于就跳转到偏移地址0046BD76处,跳转到0046BD76处的结果使我们跳过了注册成功的那一段代码,来到了注册失败的那个提示信息处。也就是说,只要偏移地址0046BCBC处语句 jne 0046BD76不跳转我们就可以注册成功!如果你想暴力破解软件,将jne 0046BD76改为je 0046BD76,在注册时输入任何注册信息软件都会显示注册成功! 从上面的分析中我们可以判定出,偏移地址0046BCBC上面的那个CALL 00403D14(偏移地址0046BCB7)就是软件注册码对比的地方。要得到软件的注册码必须进入此CALL。将光标移到此CALL上,点击如图6所示工具栏上的“CALL”按钮进入此CALL(图6),此时你会看到如图7所示画面(图7),在该图中偏移地址00403D1B处的cmp eax, edx就是真假注册码对比的地方。其中,寄存器EDX中就是真正的注册码,EAX中就是你输入的假注册码。 2.制造注册机 知道了注册码对比所在地址,我们就可以用前面提到的工具软件CrackCode写个简单的“注册机”了--让注册码自己跳出来!不要头痛,不用编程的。将下载回来的文件crackcode.exe和crackcode.ini复制到木马终结者的安装目录下,然后用记事本打开、编辑crackcode.ini,按照如下内容填写: [Options] CommandLine=NoTrojan2.exe Mode=2 First_Break_Address=46BCB7 First_Break_Address_Code=E8 First_Break_Address_Code_Lenth=5 Second_Break_Address=403D1B Second_Break_Address_Code_Lenth=2 Save_Code_Address=EDX 说明: [Options]:这是必须的,是默认格式。 CommandLine:这行写上你要破解的软件的名字,在此是NoTrojan2.exe。 Mode=2:由于注册码在某个CALL内,故采用增强模式2读取注册码。 First_Break_Address:程式的中断地址1,在此为46BCB7。 First_Break_Address_Code:中断地址1的1Byte代码,0046BCB7处那个CALL的机器码为E85880F9FF,所以填E8 First_Break_Address_Code_Lenth:中断行代码的长度(单位:byte),0046BCB7代码长度为5。 Second_Break_Address:程式的中断地址2,在此为403D1B。 Second_Break_Address_Code_Lenth:中断行代码的长度,00403D1B处机器码为39D0,故代码长度为2。 Save_Code_Address:存放注册码的内存地址,在本例中该代码在EDX中。 将写好的crackcode.ini保存,在木马终结者的安装目录下运行crackcode.exe,会弹出如图所示画面(图8),点击“确定”就会载入木马终结者的运行窗口,点击“注册”,在弹出的窗口中随便填入“姓名”和“注册码”(图9),点击“确定”,此时会弹出个对话框,里面出现了你梦寐以求的东西--正确的注册码(图10)!是不是觉得很神奇呢!你编写的crackcode.ini连同crackcode.exe就是木马终结者的“注册机”了,拿到朋友那里试试,让她(他)们也体验一下你的神奇吧! 总结与说明 1.在用W32Dasm静态解密前必须检查软件是否有“壳”,如果软件加“壳”了,则必须先脱壳再用W32Dasm加载、分析。 2.一定要先运行要解密的软件,看注册失败后弹出的显示信息是什么,记住它。 3.到W32Dasm中查找这个注册失败后的显示信息,双击这个信息找到相应的汇编代码。 4.向上看,看哪个地方可以跳过这个失败信息。由此找到注册码对比的地方。 5.如果你会用SoftIce或TRW2000,最好能在注册码对比的地方下断点,中断后查看得到的注册码是否正确。这一步的目的是校验你找到的注册码比对的地址是否正确。如果不会使用SoftIce或TRW2000也可略过这一步。 5.用CrackCode写“注册机”很方便、很简单,但它的应用面是很有限的,只能对付符合以下条件的软件: 1)必须在内存中或在寄存器中可以找到正确的注册码; 2)被取注册码的软件不能反跟踪程式; 3)被取注册码的软件的比较部分程式是静态的、存在的; 6.必须将crackcode.exe和crackcode.ini复制到要制作“注册机”的软件目录下才行。另外,编制crackcode.ini文件时要注意其中的“Mode”,关于“Mode”的说明可以查看下载回来的CrackCode中的教程,里面有详细的说明,在此就不赘述了。

(以前在看雪学院有人破过,今天写一下最新的破解文章,我不提倡破解国产软件,正式道歉) 破解工具:W32Dasm10.0 ,HIEW7.8 ,language2000中文版 软件名称:1860手机短信发送器-个人版.exe CRACK BY : 冰雨 最新版本:2.2 文件大小:100KB 软件授权:共享软件 使用平台:Win9x/Me/NT/2000 软件简介:   可免费使用、多号码短信群发、多条短消息连发、内容智能分段、客户电话簿、根据手机号码查询归属地、根据地区选择号码段等。商业版是面向广大企事业单位开发的手机短信群发系统。费用低廉,6-9分/条。由于用手机发送短信与中文输入的*作过于复杂,用户难以接受,更不适合于像群发,广告,通知等使用频率非常高的业务。像证券营业部,银行,服务行业等都非常急需要一整套的短信服务解决方案以方便他们与客户之间的沟通。当需要向用户发布公告或消息时他们与只能采用传统的电话与广告方式。这种做法不仅耗时耗力,还需花掉一笔不少的费用。如果将这些业务都通过短信来实现,一切都会变得简单。企业省钱、省力,用户也容易接受。个人版是面向广大经常发送短信的个人用户开发的短信发送系统。费用低廉,一个账号注册费五十元,每天可以发送五条,总共可以发送1万条,平均0.5分/条(手机直接发送10-15分/条)。 本地下载http://go6.163.com/unitech/home.htm ; 破解过程:                               1. 运行 “1860手机短信发送器-个人版.exe" 2. 随便输入几个字符,然后点”登录“就会得到一个错误信息”登录失败“ , 然后点 ” 退出 “。 3.用language2000中文版检查无壳! 4.运行 w32dasm, 将 “1860手机短信发送器-个人版.exe”反汇编 . 5. 完成反汇编后, 点 “string data reference” 按钮 , 在列出的字符串列表中找到 : “登录失败!!!!账号错误,请与作者联系。”并双击它 . 6.关闭这个窗口回到主窗口 , 你应该能够看到下面的程序 : * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00402CB9(C) | :00402CCC 8B07 mov eax, dword ptr [edi] :00402CCE 8BCE mov ecx, esi :00402CD0 50 push eax * Possible StringData Ref from Data Obj ->"登录失败!!!!账号错误,请与作者联系。 7.现在你必须从这行起向上找 , 直到找到有这样的命令为止 :jne,je 等等 . :00402CAB 25FF000000 and eax, 000000FF :00402CB0 83C40C add esp, 0000000C :00402CB3 48 dec eax :00402CB4 7427 je 00402CDD -----跳向成功 :00402CB6 48 dec eax :00402CB7 6A00 push 00000000 :00402CB9 7411 je 00402CCC ------跳向失败 :00402CBB 8B17 mov edx, dword ptr [edi] :00402CBD 8BCE mov ecx, esi :00402CBF 52 push edx * Possible StringData Ref from Data Obj ->"登录失败!!!可能当前服务器忙,或网络故障," 8. 现在你应该知道当你输入一个错误注册码时程序将跳到哪里运行了 . 现在可以想一想如果将上面那条 je命令换成 jne或jmp, 会发生什么 ? 将绿色的光条移到 :00402CB4 7427 je 00402CDD 上 , 在窗口底部有一行字指示这句 命令的偏移地址 , 此处为 @Offset 00007427h. 这就是应该修改的地方. 9.再向上找找有其他的问题吗?看见下面的程序: :00402C41 83C408 add esp, 00000008 :00402C44 83F809 cmp eax, 00000009 ----比较注册码是否为9位 :00402C47 0F85B1000000 jne 00402CFE ----如果不是,跳向失败 10.启动hiew7.8, 打开”1860手机短信发送器-个人版.exe“,把je命令换成 jne或jmp后,按 F9 将修改存盘 . 然后按 ESC 离开 . 11.运行 1860手机短信发送器-个人版.exe, 随便输入9位字符试试 . 成功了!

软件加密解密[转载]

| No Comments | No TrackBacks

一章--前言 第一章--前言 好多哥们儿说看教程跟老大的书都看不太明白,所以,我尽量把话说到最容易理解的份上,本文写给那 些刚入门和尚未入门的朋友们... 目录 no.1------------------前言(说明一下) no.2------------------汇编语言 no.3------------------Windows程序 no.4------------------调试器及相关工具入门 no.5------------------破解原理 no.6------------------初级破解实践,强暴一个软件 no.7------------------中级破解实践,找到注册码及写内存注册机 no.8------------------高级破解实践,分析软件算法,编写注册机 由于现在网吧,临时写来,所以,今天只写个前言吧,呵呵... 本章只作一些说明,现在也说了这么多了,没别的了,卖个广告,推荐几本书吧。 首先,力荐看雪老大《加密与解密--软件保护技术及完全解决方案》,绝对物超所值,要的抢先了.. .(汗~~俺都没看过,看来要落伍了)。当然,还有看雪精华一、二、三、四以及将要出来的五,足够带你 上 路,还有风飘雪大虾的《风飘雪破解教程》等等等等(其它一些,没说到的就请自行搜集吧),还有就 是常到论坛来转转 ;=》 另外,我觉的你真的很有必要学一门编程语言以及掌握一些Win32程序的知识... 课后FAQ Q:哪些人可以学习破解? A:任何会启动电脑并运行软件同时又想学习破解的人。我说的全是实话,如果你既不会启动电脑又不会 运行软件,那么我教你一个更高深的吧--破解电脑,呵呵,很简单,到大街上随便抡个板砖什么的,回 去慢慢破解吧 记得关电源) Q:有没有什么办法可以使我快速入门并成为高手? A:有。但你得是个MM(P不PL无所谓),然后找个离你家最近的破解达人,什么也不用做,眨个眼放个电 之类的会吧(现在连初中的小女生都会这个),然后就成了,呵呵,想破什么的话,让高手帮忙吧,到 时说成是自己破的就成了 MM问为什么?因为那些高手大都奇丑无比,呵呵,有了头脑就没了长相,男 的也是这样,而且越是高手,长的就是越丑。据说一次市里到CCG考察奶牛们的出乳情况,看到大哥Sun 某的时候,说了句“这奶牛个儿这么小啊,中午大家吃涮锅” (众大哥:大家准备好家伙,我们一会儿 要去械斗)。呵呵,玩笑开到这里,其实我说这么多,只是想告诉你,学习破解跟其它技术一样,请你 不要试图投机取巧,要想学,就脚踏实地,多看教程多动手实践积累经验,不要经常POSE那种弱智问题 “我不懂XX,请问我能学破解吗?”,答案是不能,你问的同时,不也正在学吗?想知道重要吗?那我 告诉你好了,凡是看雪教程上要求掌握的,你全要掌握,这还不算,要想成为高手就必须精通,如果你 不想一直只停留在入门阶段的话。不要想偷机取巧,谁一开始也不是什么都会的,但你只要花一些时间 和一小部分精力,那么没有什么你学不会的,知识是要积累的,你知道自己不会却不去学,而在那儿问 重不重要,人家会觉的你这个人并不想认真学破解,而是报有侥幸心理在浪费时间,请不要做浪费时间 的人。不要刚开始学就想马上成为高手,没有高手,你没必要立下超越的目标,只把学知识放在首位就 够了,欲速则不达,请不要做急于求成的人。 Q:学破解对我来说有什么好处? A:这个问题应该你自己来回答,呵呵,你为什么要学?“我想免费使用共享软件”倒...那多少也算是个 目的,但我希望你不要只报这种目的(目前国内共享软件业还有待发展)。我只是想说给那些只是因为一 时冲动才学习破解的人,请将你们当初的冲动继续维持下去,你需要明白,学习破解的目的不只在于破 解软件这个词,也许后来你会变为软件分析,随着学习时间的增加,对你的编程水平,相信会有相当大 的提高。学习别人好的思想,并化为已用 就我个人来说,学习破解可以把我的汇编的基础给打好,呵 呵,俺对操作系统这玩意儿感兴趣,到时候还想写出来个玩玩儿呢,所以汇编这关必须要过.... Q:我很笨,那些大虾的教程我大都看不明白,我能学会吗? A:永远不要说你笨,你只是学的比人家晚而已,太高深的看不懂,那你就捡能看懂的看,别人能入门, 你也能,不得要领只是暂时,大虾与你,也许差的就是一两年时间的问题。 答网友问 Q:寄存器可以随便用么,有没有什么限制?写个程序的时候那些变量什么的可以放在任意的寄存器么? A:呵呵,我现在就来回答楼上朋友的问题。 寄存器有它的使用机制,及各个寄存器都有着明确的分工。 如小翠儿 如数据寄存器(EAX-EDX),它们都是通用寄存器,及在软件中,任何数据都可存放于此。但 是除此之外,它们又可以都可以用于各自的专用目的。 例如: EAX可以作为累加器来使用,所以它是算术运算的主要寄存器。在乘除法等指令中指定用来存放操作数。 比如在乘法中,你可以用AL或AX或EAX来装被乘数,而AX或DX:AX或EAX或EDX:EAX则用来装最后的积。 EBX一般在计算存储器地址时,它经常用作基址寄存器。 ECX则常用来保存计数值,如在移位指令它用来装位移量、循环和串处理指令中作隐含的计数器。 最后就剩下四大天王中的黎明了,近一段时间来,他总是比较低调...(你别打我了,我去撞墙好了) 最后就剩下EDX了,一般在作双字长运算时把DX和AX组在一起存放一个双字长数(你还记的什么是双字 长吧,举个例子,比如说有一个数二进制数据01101000110101000100100111010001,你要把它寄存起来, 就可以把0110100011010100(即高十六位)放在DX中,把0100100111010001(即低十六位)放在AX中,这个 数表示为DX:AX)当然完全可以用一个EDX就把这个数给装下。所以,还可以用EDX:EAX来装一个64位数 据,这个你会推断出来吧。 而ESP、EBP、EDI、ESI,我上边儿以经大概介绍的差不多了,所以这里不说它们了。 当然还有其它的一些限制,因为我们只是要看程序的汇编代码(人家写好了的,肯定不会犯错误吧),而 不是要去写,所以可以不必掌握。有性趣的话,去看相关书籍。 另外再说一下你的最后一个问题“写个程序的时候那些变量什么的可以放在任意的寄存器么? ”这句 话我不明白你要问的是什么。我想你可能是把一些关点给搞错了,变量这词通常都是出现在高级语言 中的,而你用高级语言写程序的话,完全不用理解那些寄存器什么的,这些都跟高级语言没什么关系。 但是最终,高级语言也还是把你写的程序转换为对寄存器、内部存储器的操作。 <本章完> 第三章—Windows程序 这一章我都不知道该如何写了,呵呵~~ 毕竟,Win32是一个非常深奥的系统,目前还容不得我这种小辈在这儿说三道四,不过,我既然是要写 给那些入门阶段的朋友们看的,又不是写给那些搞程序设计老鸟看的,所以,我也犯不着怕被人背后指 着骂 本章的名字就叫《Windows程序》而不是《Windows程序设计》所以,我只是讲一些关于Windows程 序运作的原理: Windows为什么叫Windows,相信所有用过的朋友都可以明白,那桌面上一个一个的窗口,就是它名字的 由来。也就是这一个又一个窗口的出现,使计算机的使用一下子简单了巨多。几年前接触过电脑的朋友 一定知道DOS吧,不知道的话,去问加解密工具下载版的版主老哥,让他跟你解释 你还记的DOS下那黑 乎乎的窗口吧,没见过的哥们儿可以在开始菜单中找出来看看。DOS通过一系列的命令来进行相应的操 作,如进入一个目录,删除一个目录等等等等。那种工作方式就叫做命令提示符方式,也即命令行。 现在国内不懂电脑的人还老爱说要想学电脑,必须要英语过关。(就是这个,吓跑了多少仅仅是想学习 一些基本操作的朋友)可能也就是源自DOS的原因吧。 后来,随着硬件的支持以及技术上的提高,当然还有为了使电脑更方便的服务与人,慢慢的就有了所谓 的视图操作系统,从此,你不用再记忆那些大堆的指令了,而且操作上,也有了相大的提高,可以说操 作系统发展到今天的份儿上,操作已经够简单了,去看看那些在网吧里一把鼻涕的小孩子们吧… 当然,就像当年DOS之于命令提示行一样,今天的Windows仍和当年一样,占据着大部分的用户群。 (场外:一观众扔来一烂柿饼,你是唐僧啊,这么多废话) 马上转入正题,Windows之所以好用,除了不用背N多的命令外,一个原因就是因为它本身提供了大量的 标准Windows GUI函数。所以对于用户,面对的是同一套标准的窗口,对这些窗口的操作都是一样的, 所以使用不同的应用程序时无须重新学习操作。不用像当年在DOS下面那样一安装新程序,就要马上看 帮助,看说明。 而Windows GUI函数,只不过是微软提供给程序开发人员的API(Application Programming Interface 应用编程接口)中的一小部分而以。Windows API是一大组功能强大的函数,它们本身驻扎在 Windows 中供人们随时调用。这些函数的大部分被包含在几个动态链接库(DLL)中,譬如:kernel32.dll、 user32.dll 和 gdi32.dll。 Kernel32.dll中的函数主要处理内存管理和进程调度;user32.dll中的函 数主要控制用户界面;gdi32.dll中的函数则负责图形方面的操作等等。 你可能多多少少听说过API函数,如果你不太清楚到底是怎么一回事的话,我尽量给你解释的清楚一点。 不知道你有没有想过,Windows中的那一个又一个窗口是怎么画出来的呢?呵呵,你可能用VB、Delphi 编过程序,你有没有想过你写的程序中的那些窗口是怎么形成的?是控件变成的。倒...呵呵,相信你 当初学VB或Delphi的时候,所看的书上一定对可视化编程环境大肆赞扬了一番吧,是不是也提到过比 VC++怎么怎么方便?怎么怎么不用再为生成程序的界面而花费大量无用时间了等等。 (台下上来一东北民工:小子,你找抽啊,还讲不讲了) 马上开说,其实我只是想告诉你,所有你用的Windows下的程序,都是通过调用一个又一个的Windows API来执行相应任务的,没有API,你的程序什么也做不了。用VB、Delphi以及MFC的朋友也许会说我根 本没有调用什么API啊!其实这些API都是由你所用的开发环境自动进行相应的转换的。比如说你用 Delphi新建一程序,什么也不用动就直接按F9来运行它,是不是出现一个空白的窗体?这就是个标准的 Windows程序,它有Windows程序所具有的一切特征,如最大化按钮、最小化按钮、关闭按钮…你可以通 过鼠标来移动它。 但是如果你想用VC++或MASM32来写这样一个程序,那么你有两种方法,在VC++中,你可以用MFC或直接 调用API,而在MASM32中,你就只有直接调用API这一种方法。所谓直接调用API,就是指所有的操作都 通过最原始的API来完成。通过直接调用API来生成这样一个程序,你必须要先注册窗口类(除非您使用 Windows 预定义的窗口类,如 MessageBox 或 dialog box);然后产生窗口;然后在桌面显示窗口(除 非您不想立即显示它); 然后刷新窗口客户区; 麻烦吧,如果你想真正的让这个程序能正常地运行下来,还要再加入以下步骤: 1.你要得到您应用程序的句柄。2.窗体显示后就进入无限的获取窗口消息的循环。3. 如果有消息到达, 由负责该窗口的窗口回调函数处理。4. 如果用户关闭窗口,进行退出处理。 上面这此步骤,都需要调用相应的API来完成。比如说得到程序的句柄用GetModuleHandle注册窗口类用 RegisterClass或RegisterClassEx;注册后,还要用CreateWindowEx函数来生成相应窗口,而后用 ShowWindow来显示它,之后还会用UpdateWindow 来更新客户区等等等等。这些还都不算呢,如果你真 通过直接调用API去写一个稍大一点儿的程序的话,你会发现那是一个多么不令人愉快的事情。 上面说的这些,只不过是API中的一小小小小小小小小小小….部分,这才几个,真正的API有成百上千个, 包括对系统各个方面进行的操作。没有API,你的程序什么也干不了。比如说你的程序中有一个Edit控件, VB中应该叫做Text控件吧,你想将用户输入到里面的信息放到一个变量中去,那么Delphi中可以用Str:= Edit1.text来实现。VB中应该是Str=Text1.Text;但是如果你用API,想要得到Edit输入框里的文本内容, 就要调用GetDlgItemInt(Edit中输入的值当做数值来用)GetDlgItemText、GetDlgItemTextA(Edit中 输入的值当做字符串来用)。而上面我说的VB、Delphi得到编辑框中输入的内容的方法,最终在编译 成可执行文件的时候,也会由编译器自动对其进行相应的转换。你只要明白一件事就好了,那就是你 所用的程序,无时无刻都在调用着系统中的各种各样的API函数。 其实Windows中的API,就相当于当年DOS系统中的系统功能调用,及中断21。只不过在数量上和功能上, 都是DOS系统功能调用所不及的。 如果你还是看不明白,那我不怪你,可能是我讲的不清楚,所以,还是给你推荐老牛写的书吧。力推 《Windows程序设计》,看过之后你会内力大增的,那时候你所知道的知识就不止是API而以了。 其实话说回来,我这篇文章不是教你编程的,所以关于Windows程序的原理,没有必要说那么多,我之所 以跟你讲API,是想让你知道Windows程序的运行机制。免的到时候用调试器下断点的时候问什么是API。 (众人(十分愤怒地)冲上台来:“拉下去PK!把我们当什么了!”) (我再次来到台上,镜头切向脸的一侧,来个特写。只见上面有若干处大小不同的伤口)可能还有些重 点的地方我没有提到,欢迎指正。如果你有什么不明白的地方,欢迎跟贴提问。只要别太那个,比如说 “你能把所有的API给我列出来让我回去背背好吗?” 附上几个常用的API函数吧。相信你此时因该以经对API有个大概的了解了。 MessageBox 显示一信息对话框 MessageBoxEx 显示一信息对话框 MessageBoxIndirect 显示一定制信息对话框 (以上这三个,可以用来中断那些错误提示,比如说你注册码输入错误了,程序就可能通过这几个函数 中的一个,来提示你错误) GetDlgItemInt 得指定输入框整数值 GetDlgItemText 得指定输入框输入字符串 GetDlgItemTextA 得指定输入框输入字符串 (软件可以用这三个来得到用户输入的注册码) GetLocalTime 得当前本地时间 GetSystemTime 得当前系统时间 (软件可以用这两个来判断软件是否过期) RegQueryvalueA 获取一个项的设置值 RegQueryvalueExA 获取一个项的设置值 RegSetvalueA 设置指定项或子项的值 RegSetvalueExA 设置指定项的值 (如果软件用注册表存储注册信息的话,那么这几个也许会有用) 上面讲的,只是几个平时比较常见的,更多请参见看雪以前的教程或Windows开发人员手册。 最后,我们还要隆重介绍一个重量级函数,你可能不知道API是什么,但你只要用过调试器,就一定知 道它的名字。你可以不知道美国现任的总统是谁,但是你一定要知道这个函数。我虽然知道现任美国 总统是鲍威尔 但我同时也知道这个函数是谁。 它就是----吴孟达!(导演:NG)重新说。它就是hmemcpy。 这个函数是干什么的? 它是一个非常简单的函数。只完成一项非常非常基本的任务,就是把数据从一个地方复制到另一个地方。 应用程序本身并不调用它,理由很简单,它很低级(汇编:谁敢说跟我一样?)。但是大部分API函数 却非常频繁地调用它。所以,它也叫万能函数。平时你可能都不知道有这么个东西,但是断起程序来却 非常管用。但目前到了2K跟Xp下,却没有这个函数了,与之相应的是一个叫memcpy的函数,虽然功能与 其相同,但是基本上已经是个废人了 总知,你用memcpy根本就断不下什么来。所以,这么一个好使的 函数只能在98下使用了。这就像美国的总统一样,再好使也只能使八年,不好使的就别说了。说不定 明年就把他踢飞 别的我也不多说什么了,这章你就知道API是什么就成了。 如果你觉的有什么不妥的地方或有什么问题,并且想文明一点地表代出来的话,就请在回复。如果想野 蛮一点的话,就拿鸡蛋往你显示器上丢吧 <本章完>   第四章--调试器及相关工具入门 在写这章之前,我看了一下看雪以往的教程。本来想参考一下,可忽然发现,写这样的一章,是一件 非常愚蠢的事情,因为我觉的关于这些工具的使用教程。看雪教程中已经写的够详细的了,我并不认 为你会看不懂。所以我不想做浪费时间的人,本章就此搁浅。 推荐看《Crack Tutorial 2001》,推荐看《看雪论坛精华一、二、三、四》,推荐看《加密与解密-- 软件保护技术及完全解决方案》,推荐看一切与之有关的教程。 本章补遗: 要想上路,你最少应该熟练掌握以下工具: SoftICE:目前公认最好的跟踪调试工具。(由于我使用的分辩率的关系,从没有用过它) Trw2000: 国人骄傲,其中有我最喜欢的pmodule命令。(河南老乡,殷墟旧人) W32Dasm8.93或其它任意版本:反汇编的极品工具。 Hiew 或者Ultra Edit或者其它:十六进制工具。爆破时使用,DOS下使用Hiew,Windows下使用Ultra Edit、WinHex、Hex Workshop等,我个人喜欢用Ultra Edit。 侦测文件类型工具:比如TYP、gtw或FileInfo等。这是一个能侦测你的软件是被哪一种「壳」给加密了。 PROCDUMP与其它N多的脱壳软件。 EXESCOPE:拥有执行文件(EXE, DLL等)的解析与显示功能;提取资源到外部文件 ;资源的重新写入; 记录文件的记录及其再编辑(成批编辑)等功能。是汉化软件的常用工具,当然破解软件时也很有用。 其它许多......(等你入了门后再学也不迟) (作者注:以上工具的使用方法,大都可在看雪以有的教程中找到,故不愿复之) 第五章--破解原理 从本章开始,我们来一步一步学习Crack软件(80%读者昏死过去,且不省人世...另有20%在寻找附近 可以用来打人的东西) 不可不说一下学习破解的三个阶段: 初级,修改程序,用ultraedit等工具修改exe文件,称暴力破解,简称爆破 中级,追出软件的注册码 高级,写出注册机 先说这爆破。所谓爆破,就是指通过修改可执行文件的源文件,来达到相应的目的。你不明白?呵呵 ,举个例子好了,比如说某共享软件,它比较用户输入的注册码,如果用户输入的,跟它通过用户名 (或其它)算出来的注册码相等的话(也就是说用户输入的注册码正确了),那么它就会跳到注册成 功的地方去,否则就跳到出错的地方去。 明白过来了吧,我们只要找到这个跳转指令,把它修改为我们需要的“造型”,这样,我们是不是就 可以为所欲为了?(某软件双手放在胸口,你要干嘛?) 常见的修改方法有两种,我给你举例说明: no.1 在某软件中,这样来进行注册: 00451239 CALL 00405E02 (关键CALL,用来判断用户输入的注册码是否正确) 0045123D JZ 004572E6 (!!!<--此为关键跳转,如果用户输入的注册码正确,就跳向成功处,即 004572E6处) 0045XXXX YYYYYYYYYY XXXXXXXX YYYYYYYYYY XXXXXXXX YYYYYYYYYY XXXXXXXX 执行到此处,就提示用户注册失败 ...提示用户注册码不正确等相关信息 ... 004572E6 ... <--(注册成功处!!!) ...提示用户注册成功等相关信息 呵呵,看明白了吗?没有的话,我来给你讲一下。在软件执行到00451239处的时候,CALL置0045E02处来 进行注册码判断。接着回来后就来一个跳转语句,即如果用户输入的注册码正确就跳到004572E6处,跳 到此处,就算是注册成功了。如果用户输入的注册码不正确的话,那么就不会在0045123D处进行跳转, 而一直执行下去。在下面等它的,是注册失败部分。 想明白了吗?嘿嘿...没错,我们只要把那个关键跳转JZ给改为JNZ(如果用户输入的注册码错误,就注 册成功,输入正确则注册失败)。当然你也可以将JNZ修改为Jmp,这样的话,你输入的注册码无论正确 与否。都可以注册成功。 no.2 我们再来讲一下另外的一种情况: 00451239 CALL 00405E02 (关键CALL,用来判断用户输入的注册码是否正确) 0045123D JNZ 004572E6 (!!!<--此为关键跳转,如果用户输入的注册码不正确,就跳向失败处,即 004572E6处) 0045XXXX YYYYYYYYYY XXXXXXXX YYYYYYYYYY XXXXXXXX YYYYYYYYYY XXXXXXXX 执行到此处,就提示用户注册成功 ...提示用户注册成功等相关信息 ... 004572E6 ... <--(注册失败处!!!) ...提示用户注册码不正确等相关信息 这次我相信,并且深信不疑。你一定明白了。我还是不明白...倒... 你一定看出跟第一种情况不同的地方了吧。没错!它与第一种不同的,就是第一种情况是如果注册码正 确,就跳到注册成功处,如果没有跳走,就会执行到失败处。而这一种情况则是如果注册码不正确,就 跳到注册失败处,否则将执行到注册成功处。 这种情况的修改,除了把JNZ改为JZ外,还可以将其改为Nop,Nop这个指令没有任何意义,将该条指令修 改为Nop后,便可随意输入注册码来进行注册了。 原理以经给你讲了,下面我们再来讲一下具体的修改办法吧。(我假设你以经明白了我所说的工具的使 用方法) 先说一下虚拟地址和偏移量转换的问题,在SoftICE和W32Dasm下显示的地址值是所谓的内存地址 (memory offset),或称之为虚拟地址(Virual Address,VA)。而十六进制工具里,如:Hiew、Hex Workshop等显示的地址就是文件地址,称之为偏移量(File offset) 或物理地址(RAW offset)。 所以当我们要通过那些十六进制工具来对可执行文件中的相应指令进行修改的话,先要找到它的File offset。我们没有必要去使用那些专门的转换工具,在W32Dasm中就有这个功能,比如说你W32Dasm中来 到0045123D处,在W32Dasm界面下方的状态栏中就会出现该条指令的虚拟地址和偏移地址,即@:0045123D @offset 0005063Dh 后面的这个0005063Dh就是相应的偏移地址。我们得到该地址后,便可用UltraEdit 等十六进制工具来对可执行文件进行修改了。比如使用UltraEdit,你先用UltraEdit打开该可执行文件, 然后按Ctrl+G,接着输入你得到的偏移地址,就可以来到其相应的机器码处。 再给你讲一下机器码,所谓的机器码。就是你看到的那些个十六进制数据了。还记的它们与汇编指令是 一一对应的吗? 以下这几个是爆破时要用到的,其它的如果感兴趣,可自行查看相关资料: JZ=74;JNZ=75;JMP=EB;Nop=90 爆破的时候,只要对以上机器码进行相应的修改就行了,比如第一种情况的时候,可以将74修改为EB, 即将JZ修改为JMP。而第二种情况,责需将75修改为90,即将JNZ修改为Nop。 由于本章只讲原理,具体一点的。如怎样找到关键跳转等,我们在下一章中再讲。(一个砖头飞了上来! 嘿嘿,这次被俺接到了) 上边讲了爆破的原理,你需要明白的是。爆破只是你学习Crack的开始,是很简单的手段。刚入门的时 候可以玩玩儿,但希望你不要就此不前! (嘿嘿,再说了。人家的软件中不是都说了嘛,不准对其进行逆向修改。你动了人家的身子,怎么能不 买帐呢? ) 偶就不喜欢爆破,做不出注册机也要找出注册码。否则我就不会去注册这个软件,既然想不掏钱,就要 靠你自己的本事。(等以后我有钱了,会考虑去注册那些优秀的共享软件的 )。所以,从某种意义上来 说,我是一个正人君子 其实要找到注册码并不是一件多么难的事,我是指你所针对的软件不太那个的时候 不过你无需惧怕。 刚才我们说爆破的时候不提到过关键CALL吗?一般情况下,这个关键CALL就是对两个注册码(一个是软 件自身通过你的注册名或机器什么的计算出来的正确的注册码,令一个就是你输入的错误的注册码)进行 比较。我前边提到过,CALL之前一般会把所用到的数据先放到一个地方,CALL过去的时候再从这些地方把 先前放入的数据取出来,进行相应的处理。这个关键CALL也是这样,在CALL之前,一般会把那两个注册码 放到堆栈或某个寄存器中。嘿嘿,我们只要在调试器中,单步执行到该CALL,在未进去之前通过CALL 之前的指令判断其将正确的和不正确的注册码放到哪里了。然后再用相应指令进行查看就成了,我说过不 难的。 下面列出两个最常见的情况(可参考相关教程): no.1 mov eax [ ] 这里可以是地址,也可以是其它寄存器 mov edx [ ] 同上,该条指令也可以是pop edx call 00?????? 关键call test eax eax jz(jnz)或jne(je) 关键跳转 看明白了吧,在关键CALL之前,软件会把两个注册码分别放入eax和edx中,你只要在CALL处下d eax或 d edx就能看到正确的注册码了。 no.2 mov eax [ ] 这里可以是地址,也可以是其它寄存器 mov edx [ ] 同上,该条指令也可以是pop edx call 00?????? 关键call jne(je) 关键跳转 以上两种情况最为常见,而那些个不太常见的情况,我们这里就不再提了。到下下一章的时候,我会 给你讲相关方法的... 关于查找软件注册码的部分,就到这里。具体内容,下下一章咱们再说。(不是说了吗?我以经可以接 到你的砖头了,干嘛还要丢呢? ) 最后,再来说最后的所谓的高级阶段,如果你相信自己。并且热爱Crack,那么你一定会熬到这个阶段 的,只是时间因人而异。 其实分析软件的算法,是有好多技巧在里面的。呵呵,最起码我刚开始的时候就摸不着头脑,那么多 CALL,每个看起来,都很重要,都追一遍?结果连好多API都被追了进去。等你自己真正用心分析了一个 软件的算法,并写出了注册机后。你就会明白其中的道理了,我们下下下一章再说。(大哥,你不是吧, 连你家太阳能都丢过来了 ) <本章完> 第六章--爆破软件 爆破其实很简单,最起码比你能一下把你家的牙膏给全挤出来要容易多了。你只要先到大街上买几根 雷管,然后放到你的显示器上再点着就OK了(不难吧,记的点着后跑远点儿) 爆破的原理我也说过了,相信你很容易就能理解了。我们今天就具体讲一下如何找到那个关键跳转以及 如何才能买到即便宜又好用的雷管... 爆破一个软件一般只需要很少的几个步骤,首先先看一下其有无加壳,有的话是用何工具加的壳,知道 了以后用相应的工具将其脱掉或进行手工脱壳,参考以有教程。接着我们就可以对脱过壳之后的软件来 开刀了。你有两种选择,用W32Dasm或调试器,一般如果你遇上的是那种很菜的软件的话,用W32Dasm就 可以搞定了。如果遇上的不是那种比较菜的,就买股票吧,因为股票是你如胶似漆的妻子!当!快醒醒 啊...哦,一般如果你遇上的不是那种很菜的软件的话,就用调试器吧。先来说W32Dasm:我们首先用 W32Dasm来进行反汇编(废话!)之后在串式参考中找到错误提示信息或可能是正确的提示信息双击鼠标 左键来到相应的地址处。在W32Dasm的主窗口中分析相应汇编代码,找出关键跳转和关键call。绿色光条 停在关键跳转,在W32Dasm主窗口底部找到关键跳转的偏移地址(实际修改地址)。用ultraedit找到偏移 地址(实际修改地址)修改机器码(或放上一根雷管),保存(点火)!而用调试器也同样简单,等会儿会详 细说明。 道理废话了那么多,来实例动手说明吧: 首先讲解用W32Dasm来进行爆破: 【软件名称】中华压缩(ChinaZip) 【软件版本】7.0 【文件大小】1041KB 【适用平台】Win9x/Me/NT/2000 【软件简介】ChinaZip(中华压缩)是一款压缩、解压各种压缩文档的工具软件,它支持包括ZIP格式文 件在内的各种常见压缩格式如:ARJ、CAB、GZIP、JAR、LHA、TAR、ZOO、ARC、LZH、Pak等等。 软件的出处是电脑报2001年的合订本配套光盘,7.0时的保护做的很那个,目前最新版应该好多了... 好的,我们开始吧,首先第一步是你得把它装上(引来野狼N头),之后先随便找个字符串填上去注册一 下,会看到一个错误对话框,提示\"注册码不正确,无法注册\"。接着我们用FI来看一下它用的是什么 壳。ASPack 2.001,caspr出场。脱过壳后我们用W32Dasm花上半分钟或半小时的时间来对它进行反汇编。 我们以经反汇编完毕。之后在串式参考中(字符串数据参考)中找刚才你看到的那个错误提示,找到之 后双击几次,发现其只有一处调用。我们会来到004F0E64处,我把具体代码给贴上(请你从代码的最下 边开始看): :004F4DD1 E84EE1F3FF call 00432F24 :004F4DD6 8B55F0 mov edx, dword ptr [ebp-10] :004F4DD9 8D4DF4 lea ecx, dword ptr [ebp-0C] :004F4DDC 8BC3 mov eax, ebx :004F4DDE E8C9010000 call 004F4FAC :004F4DE3 8B55F4 mov edx, dword ptr [ebp-0C] :004F4DE6 58 pop eax :004F4DE7 E830F3F0FF call 0040411C :004F4DEC 7576 jne 004F4E64 <--这个就是传说中的男人,Stop!这个就是传说中的关键跳转 :004F4DEE B201 mov dl, 01 :004F4DF0 A158254500 mov eax, dword ptr [00452558] * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004F4D86(C) | :004F4DF5 E85ED8F5FF call 00452658 :004F4DFA 8945FC mov dword ptr [ebp-04], eax :004F4DFD 33C0 xor eax, eax :004F4DFF 55 push ebp :004F4E00 685D4E4F00 push 004F4E5D :004F4E05 64FF30 push dword ptr fs:[eax] :004F4E08 648920 mov dword ptr fs:[eax], esp :004F4E0B B101 mov cl, 01 * Possible StringData Ref from Code Obj ->\"Software\\XDZHAN\\ChinaZip\" | :004F4E0D BAA84E4F00 mov edx, 004F4EA8 :004F4E12 8B45FC mov eax, dword ptr [ebp-04] :004F4E15 E822DAF5FF call 0045283C * Possible StringData Ref from Code Obj ->\"Real Programmers Use Pascal!\" | :004F4E1A B9CC4E4F00 mov ecx, 004F4ECC * Possible StringData Ref from Code Obj ->\"Key\" | :004F4E1F BAF44E4F00 mov edx, 004F4EF4 :004F4E24 8B45FC mov eax, dword ptr [ebp-04] :004F4E27 E854DEF5FF call 00452C80 * Possible StringData Ref from Code Obj ->\"软件注册成功,谢谢您的支持!\" <--我们向上看会在 这里发现注册成功后的正确信息。正确信息处向上找第一个跳转就是我们要找的关键跳转。 | :004F4E2C B8004F4F00 mov eax, 004F4F00 :004F4E31 E8563DF6FF call 00458B8C :004F4E36 A16C305000 mov eax, dword ptr [0050306C] :004F4E3B 8B00 mov eax, dword ptr [eax] * Possible StringData Ref from Code Obj ->\"中华压缩(ChinaZip)-注册版\" | :004F4E3D BA244F4F00 mov edx, 004F4F24 :004F4E42 E80DE1F3FF call 00432F54 :004F4E47 33C0 xor eax, eax :004F4E49 5A pop edx :004F4E4A 59 pop ecx :004F4E4B 59 pop ecx :004F4E4C 648910 mov dword ptr fs:[eax], edx :004F4E4F 686E4E4F00 push 004F4E6E * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004F4E62(U) | :004F4E54 8B45FC mov eax, dword ptr [ebp-04] :004F4E57 E868E2F0FF call 004030C4 :004F4E5C C3 ret :004F4E5D E9C2E9F0FF jmp 00403824 :004F4E62 EBF0 jmp 004F4E54 * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004F4DEC(C) | * Possible StringData Ref from Code Obj ->\"注册码不正确,无法注册!\" <--这个就是出错的信息 了,那正确信息也就在附近,上下看看。 | :004F4E64 B8484F4F00 mov eax, 004F4F48 <--双击来到这里 :004F4E69 E81E3DF6FF call 00458B8C :004F4E6E 33C0 xor eax, eax :004F4E70 5A pop edx :004F4E71 59 pop ecx :004F4E72 59 pop ecx :004F4E73 648910 mov dword ptr fs:[eax], edx :004F4E76 689B4E4F00 push 004F4E9B 你可能有点不明白,为什么我说它就是关键跳转呢?还记的在破解原理中我举的例子吗? 我再给你讲一遍好了,通常我们会遇到两种关键跳转,我分别举例说明: (1) je (jne,jz,jnz) 19870219 ........ XXXXXXXXXX ........ XXXXXXXXXX ........ 软件注册正确的相关信息 ... ... 19870219 软件的出错信息 ....... ....... 也就是说这第一种情况是先判断注册码是否正确,如果不正确就跳到19870219处,正确的话就不跳转, 一直执行下去,直至注册正确处。 对于这种情况,我们要找的关键跳转,就是正确信息上面的第一个跳转。我们可能对其作相应修改或将 其给nop掉就万事OK了。 (2) je (jne,jz,jnz) 19870219 ........ XXXXXXXXXX ........ XXXXXXXXXX ........ 软件的出错信息 ... ... 19870219 软件注册正确的相关信息 ....... ....... 而这第二种情况就是先判断注册码正确与否,如果正确就跳到19870219处,不正确的话就不跳转,一直 执行下去,直至出错处。 对于这种情况,我们要找的关键跳转就是出错信息上面的第一个跳转。将其做相应修改或改为jmp后我们 就可以为所欲为了 呵呵,道理也都给你讲明白了,我们来改一下试试吧。我们在W32Dasm中选中关键跳转,在右下角的状 态栏中看到相应的偏移地址为000F41EC。好的,我们用UltraEdit来打开它。Ctrl+G,接着输入0xF41EC, 回车后便会跳到相应的位置。相应的机器码是75(jne),我们将其改为74(jz)后存盘退出。 好了,运行一下看看,我们来随便输入一个注册码注册一下试试。呵呵,注册成功! 用W32Dasm我们就讲到这里,呵呵,很简单的,你下去之后自己找些保护简单的软件上上手吧。 我们接着来讲用调试器来进行爆破。 如果你真的试图用W32Dasm去爆破几个软件的话,用不了多少时间你就会发现一些问题。比如说有的软 件你用W32Dasm反汇编后串式参考根本就不能用。或者串式参考中没有出错或正确的信息。还有就是有的 软件就算你通过串式参考来到了相应的地方,刚想去找关键跳转你就会发现眼前的东西比你想像中的要 乱的多...虽然你有可能通过认真仔细地找,仍会找到,但我不认为那是一件聪明的事情。毕竟,有一 些动静是只有在程序执行期间才能看出来的。好的,如果你用W32Dasm遇到了找不到关键跳转的软件, 就去用调试器吧!(你用调试器前可先用W32Dasm打开一遍看个先,如果很容易就让你找到了。那就没必 要了) 在开始之前我们有必要讲一下用调试器来爆破的步骤(我知道你一定会用调试器的 ):首先,我们当然 还是要把你要Crack的软件给装上(我挡我挡我挡,不要乱丢东西嘛!)然后来到输入注册码的地方,仍 旧随便输入一个,接着不要按确定,待我们把调试器叫出来先。还记的我前面跟你讲的API的事情吗?软 件要得到你输入的注册码,就一定会调用某个API函数来达到目的。我们就在调试器中用相应的API来做 断点,这样的话,只要一有程序调用这个API,就会被调试器给拦截下来。 GetDlgItemInt、GetDlgItemText、GetDlgItemTextA这三个函数可能会有用。但是如果你用的是98,那 为什么不用hmemcpy呢?那真的是一个不错的主意。当我们下完断点后就返回到你要注册的那个软件中, 点确定这类的按钮。如果被调试器给断了下来,就说明你刚才下的断点有用,如果没有被断下来,就换 个断点试试。接下来我们在调试器中来取消刚才你下的那个断点,我们以TRW2000为例(SoftICE与其操 作大体相同)取消断点用bc *指令。然后我们就输入pmodule指令来返回到程序的领空(而在SoftICE中 由于没有相应指令,呵呵,狂按F12吧)。现在我们把话题岔开一下,什么是领空呢?举个例子吧,你的 程序要得到你输入的那个注册码,就会去调用相应的函数。比如调用GetDlgItemTextA,而 GetDlgItemTextA本身又会去调用Hmemcpy这个函数,而这些函数都是存在于系统中的某个DLL文件中的。 那么当这个程序调用相应的API函数的话,程序的领空就会转到这个相应的DLL文件中去执行这个API函数。 (你就这样理解就行了)我前边也说过了,Hmemcpy这个函数应用程序本身并不直接调用,而是由其它的 API函数来调用。那么,你就可以理解为你的程序调用了一个API函数,调用的同时程序的领空会转到这 个API所在的DLL文件里,而这个API又调用了Hmemcpy函数,那么此时领空就会又转到了Hmemcpy所在的 DLL文件中,之后当Hmemcpy执行完毕,就会返回到调用它的API的领空中去,而当这个API执行完毕的后 就会返回到调用它的应用程序的领空中去。比如说我们用Hmemcpy这个函数来当断点,当我们输入完注 册码按确定后,程序就会去调用某个API来得到你输入的那些数据,而这“某个API”又会去调用Hmemcpy, 所以程序就被断到了。当然此时程序的领空也就不会在应用程序中了,但是当我们输入过pmodule指令之 后我们就可以反回到应用程序本身的领空中去了。这样的话你看到的就是应用程序自身的代码了,而不 是API的!好了,我接着刚才的说(到哪儿了来着?)当我们返回到程序自身的领空中去后就一直狂按 F12吧,F12的作用是一直执行程序,直到遇上ret等指令。也就是一大坨一大坨地来执行程序^_^你一直 按F12,直到程序出现注册错误对话框。然后记下刚才你按的次数,接着从头做起,这一次按F12的次数 是你刚才按的次数-1,也就是说比上一次要少按一次。而后按键由F12换至F10(怎么没有F4?),还是一 路狂按,直到软件提示出错,这次记下你按F10的次数。好的,再从头来一遍,我们再次按F10的时候, 要一步一步慢慢来,一般你按F10的次数离你上次按的次数相差五六步的时候,一般就会看见一个CALL, 接着是一个跳转指令。你一步一步地来,看过了这个跳转指令之后会不会跳走,如果跳走了,那一般你 不会再过两三步就应该出错了。当然也有可能是你没有跳走,而过了两三步就出错了。这个应该不难理 解,因为基本上它和我前边跟你介绍过的是一个道理。然而另外一种情况是你一路按F10下来,到了最后 会发现根本没什么跳转指令,呵呵,别害怕,这个很常见的。遇上这种情况,我们只要把F10的次数变换 为上次按F10的次数-1,这样的话你一般就会停在一个CALL处,而这个CALL,就是程序中的关键CALL,我 们之后要吃点儿苦,要按F8追进去分析它,程序注册的成功与失败,就在这个CALL中,也就是说我们要 修改的关键跳转,也在这个CALL中。呵呵,其实也很好理解的,就是把我上边说的那些个判断什么地放 到了一个CALL里面。我们按F8追进去之后便仍旧按F10来一步一步执行,过不了多长时间你就会发现关键 跳转了,找关键跳转的方法跟我前边说的一样,即按F10的次数跟上一次差五六步的时候慢下来,就会看 到了。 你应该明白,程序是很灵活的东西,并没有那么多公式化的东西在里边,大概的分析方法就是这个样子, 一切都要靠你自己去掌握,别人跟你讲,也只是讲一个分析的方法而以,我相信随着你以后经验的提高, 你慢慢地就能应付各种情况了。 现在,我们再用调试器来对CHINAZIP这个软件进行分析,希望你能够掌握这个并不难的方法。 首先,你要把刚才爆破过了的再改回来,或直接重装一遍。之后我们打开它,任意输入注册码,接着按 Ctrl+N呼出TRW,下断点hmemcpy。下过后按F5退出(它就是不用F4,我也没办法^_^)然后我们点击确定。 好的,程序被断了下来: KERNEL?HMEMCPY 0147:9e62 push bp 0147:9e63 mov bp,sp 0147:9e65 push ds 0147:9e66 push edi 0147:9e68 push esi 0147:9e6a cld 0147:9e6b mov ecx,[bp+06] 0147:9e6f jcxz 9ee9 ……以下N多代码省略…… 我们输入bc *来取消断点,然后用pmodule来返回到程序的领空: 0167:00436d13 mov [ebx+0c],eax 0167:00436d16 mov eax,[ebx] 0167:00436d18 cmp eax,byte +0c 0167:00436d1b jnz 00436d38 0167:00436d1d mov edx,[ebx+08] 0167:00436d20 push edx 0167:00436d21 mov ecx,[ebx+04] 0167:00436d24 mov edx,eax 0167:00436d26 mov eax,esi 0167:00436d28 call 00432b24 ……N多代码仍旧省略…… 按7下F12另加1下F10来到0167:004f4dc4处,我们接着一下一下来按F10,大概按了10多下,就可以看到 004f4dec处有一个跳转,我们执行到004f4dec处后果然跳走了。会跳到004f4e64处,我们跳过去之后按 不了三下,程序就提示出错了。呵呵,明白过来了吧,004f4dec处的那个跳转jnz 004f4e64就是关键跳 转,嘿嘿,找到了之后不用我说了吧 0167:004f4dc4 mov eax,[ebp-08] 0167:004f4dc7 push eax 0167:004f4dc8 lea edx,[ebp-10] 0167:004f4dcb mov eax,[ebx+02e0] 0167:004f4dd1 call 00432f24 0167:004f4dd6 mov edx,[ebp-10] 0167:004f4dd9 lea ecx,[ebp-0c] 0167:004f4ddc mov eax,ebx 0167:004f4dde call 004f4fac 0167:004f4de3 mov edx,[ebp-0c] 0167:004f4de6 pop eax 0167:004f4de7 call 0040411c 0167:004f4dec jnz 004f4e64 <--关键跳转!! 0167:004f4dee mov dl,01 0167:004f4df0 mov eax,[00452558] 0167:004f4df5 call 00452658 0167:004f4dfa mov [ebp-04],eax 0167:004f4dfd xor eax,eax 0167:004f4dff push ebp 0167:004f4e00 push dword 004f4e5d 0167:004f4e05 push dword [fs:eax] 0167:004f4e08 mov [fs:eax],esp 0167:004f4e0b mov cl,01 0167:004f4e0d mov edx,004f4ea8 0167:004f4e12 mov eax,[ebp-04] 0167:004f4e15 call 0045283c 0167:004f4e1a mov ecx,004f4ecc 0167:004f4e1f mov edx,004f4ef4 0167:004f4e24 mov eax,[ebp-04] 0167:004f4e27 call 00452c80 0167:004f4e2c mov eax,004f4f00 0167:004f4e31 call 00458b8c 0167:004f4e36 mov eax,[0050306c] 0167:004f4e3b mov eax,[eax] 0167:004f4e3d mov edx,004f4f24 0167:004f4e42 call 00432f54 0167:004f4e47 xor eax,eax 0167:004f4e49 pop edx 0167:004f4e4a pop ecx 0167:004f4e4b pop ecx 0167:004f4e4c mov [fs:eax],edx 0167:004f4e4f push dword 004f4e6e 0167:004f4e54 mov eax,[ebp-04] 0167:004f4e57 call 004030c4 0167:004f4e5c ret 0167:004f4e5d jmp 00403824 0167:004f4e62 jmp short 004f4e54 0167:004f4e64 mov eax,004f4f48 <---由上面的0167:004f4dec处跳来,出错!; 0167:004f4e69 call 00458b8c 0167:004f4e6e xor eax,eax 再来给你举另一个例子: 【软件名称】天网防火墙 【软件版本】2.46 Beta 【文件大小】1289KB 【适用平台】Win9x/Me/NT/2000 【软件简介】天网防火墙个人版是一套给个人电脑使用的网络安全程序,它可以帮你抵挡网络入侵和攻 击,防止信息泄露,并可与我们的网站相配合,根据可疑的攻击信息,来找到攻击者。同时天网防火墙 个人版把网络分为本地网和互联网,可以针对来自不同网络的信息,来设置不同的安全方案,它适合于 在拨号上网的用户,也适合通过网络共享软件上网的用户。 该软件仍旧是我从电脑报2001年合订本的配套光盘中找的,软件的注册码可以到其网站免费获得... 我们还是要先把它装上(某民工:你小子敢再说一句废话试试!^_^)之后我们用FI看一下它有没有加壳 ,呵呵,BC++编译,没有加壳,爽!运行它,在注册对话框中随便输入点什么,比如说这星期又出了几 部新电影,都叫什么名字等等... 好的,我们接下来请TRW2000出场。先胡乱输入两个字符串,比如第一个输入“英雄的导演是?”第二个 输入“可能是赵本山”:) 接下来就按Ctrl+N把TRW2K叫出来,下bpx hmemcpy,之后按F5退出。 接着可以按确定就成了,程序会被TRW2K断掉,我们紧接着输入bc *以及pmodule。 下面可以开始按F12了,一共按8下程序就会报错,我们第二次就按7下然后开始按F10,按70下F10程序 就又报错了(呵呵,一定要有耐心哦)。 好的,我把反汇编后的代码给你贴出来: 0167:0041c617 lea edx,[ebp-04] <--7下F12后按一下F10来到这里 0167:0041c61a mov ecx,[0052ae7c] 0167:0041c620 mov eax,[ecx] 0167:0041c622 mov eax,[eax+0318] 0167:0041c628 add eax,byte +2c 0167:0041c62b call 00517740 0167:0041c630 dec dword [ebp-20] 0167:0041c633 lea eax,[ebp-04] 0167:0041c636 mov edx,02 0167:0041c63b call 00517710 0167:0041c640 mov word [ebp-2c],14 0167:0041c646 lea eax,[ebp-08] 0167:0041c649 call 00401d60 0167:0041c64e mov edx,eax 0167:0041c650 inc dword [ebp-20] 0167:0041c653 mov ecx,[ebp-40] 0167:0041c656 mov eax,[ecx+02e0] 0167:0041c65c call 004b9f14 0167:0041c661 lea edx,[ebp-08] 0167:0041c664 mov ecx,[0052ae7c] 0167:0041c66a mov eax,[ecx] 0167:0041c66c mov eax,[eax+0318] 0167:0041c672 add eax,byte +30 0167:0041c675 call 00517740 0167:0041c67a dec dword [ebp-20] 0167:0041c67d lea eax,[ebp-08] 0167:0041c680 mov edx,02 0167:0041c685 call 00517710 0167:0041c68a lea eax,[ebp-10] 0167:0041c68d call 00401d60 0167:0041c692 mov edx,eax 0167:0041c694 inc dword [ebp-20] 0167:0041c697 mov ecx,[ebp-40] 0167:0041c69a mov eax,[ecx+02e0] 0167:0041c6a0 call 004b9f14 0167:0041c6a5 lea edx,[ebp-10] 0167:0041c6a8 push dword [edx] 0167:0041c6aa mov word [ebp-2c],20 0167:0041c6b0 lea eax,[ebp-0c] 0167:0041c6b3 call 00401d60 0167:0041c6b8 mov edx,eax 0167:0041c6ba inc dword [ebp-20] 0167:0041c6bd mov ecx,[ebp-40] 0167:0041c6c0 mov eax,[ecx+02d4] 0167:0041c6c6 call 004b9f14 0167:0041c6cb lea edx,[ebp-0c] 0167:0041c6ce mov edx,[edx] 0167:0041c6d0 mov eax,[0052ae7c] 0167:0041c6d5 mov eax,[eax] 0167:0041c6d7 pop ecx 0167:0041c6d8 call 0040525c 0167:0041c6dd mov [ebp-45],al 0167:0041c6e0 dec dword [ebp-20] 0167:0041c6e3 lea eax,[ebp-10] 0167:0041c6e6 mov edx,02 0167:0041c6eb call 00517710 0167:0041c6f0 dec dword [ebp-20] 0167:0041c6f3 lea eax,[ebp-0c] 0167:0041c6f6 mov edx,02 0167:0041c6fb call 00517710 0167:0041c700 cmp byte [ebp-45],00 0167:0041c704 jz 0041c750 <--按了60多下F10后会在这里发现一个跳转,嘿嘿,就是它了!!! 0167:0041c706 mov ecx,[0052ae7c] 0167:0041c70c mov eax,[ecx] 0167:0041c70e mov eax,[eax+0318] 0167:0041c714 call 00411fd0 0167:0041c719 mov word [ebp-2c],2c 0167:0041c71f mov edx,00521b50 0167:0041c724 lea eax,[ebp-14] 0167:0041c727 call 005175b0 0167:0041c72c inc dword [ebp-20] 0167:0041c72f mov eax,[eax] 0167:0041c731 call 004b41b0 0167:0041c736 dec dword [ebp-20] 0167:0041c739 lea eax,[ebp-14] 0167:0041c73c mov edx,02 0167:0041c741 call 00517710 0167:0041c746 mov eax,[ebp-40] 0167:0041c749 call 004a81d0 0167:0041c74e jmp short 0041c77d 0167:0041c750 mov word [ebp-2c],38 0167:0041c756 mov edx,00521b6b 0167:0041c75b lea eax,[ebp-18] 0167:0041c75e call 005175b0 0167:0041c763 inc dword [ebp-20] 找到了关键跳转之后就别闲着了,呵呵,放雷管吧!(你可以用W32Dasm打开这个文件,然后按Shift+ F12,之后输入0041c704,这样就可以在右下角看到相应的偏移地址了) 小技巧:在TRW中,如果你觉的某处可能是关键跳转的话,可以用r fl z这个指令来进行测试,该指令可 使以成立的条件取反,比如说本来JZ XXXXXXXX成立,可以跳走了,用r fl z指令后该条指令就不成立了 ,即就不会跳走了。以上也是,你可以在0041c704处输入r fl z,呵呵,再执行几步看看,是不是成功 了?还有就是如果你只是想达到注册软件的目的,且该软件只在注册的时候验证一次的话,用这个方法 就可以代替雷管了! 呵呵,最后还是要说一句,爆破只是一些雕虫小技。刚入门时玩几次就够了,切莫就此不前... 后话:你可能慢慢就会发现,有一些软件其实并没有你想象中那么简单,你甚至连找到它的关键跳转 都找不到。这很正常,你要做的便是多动手多练习,慢慢你就会明白过来的。我今天之所以给你举这两 个例子,就是因为它们两个都比较简单,且能说明重点,给你讲那些比较那个的软件的爆破,反而会让 你看的一头雾水... <本章完>   chensu198 2005-7-19 03:55 寻找软件的注册码 第七章-寻找软件的注册码 我们来寻找软件真正的注册码! 寻找软件的注册码就像你小时玩的躲猫猫一样,简单又有趣,虽然后来你会不这样觉的 好的,我们开始。 我不知道你有没有明白我前面在原理中讲的那些东西,如果没明白,我就再说一遍 软件通过你输入的用户名或者机器码什么的生成一个正确的注册码来与你输入的注册码进行比较,如果 两个相同,也就是说你输入的注册码是正确的话,那软件就会完成注册。如果你输入的不正确,嘿嘿, 当然就不会注册成功。 好的,现在你已经知道软件会有一个比较两个注册码的过程,这就是关键所在。一般如果你遇到的是那 种明码比较的软件,这会是一件非常另人愉快的事情的 软件会先计算出正确的注册码然后再与你输入的那个进行比较,也就是说正确的注册码会被软件自己算 出来!嘿嘿,搜身你会吗?虽然法律以及道德不允许我们去搜身,但… 我接着说,虽然现在的软件已经比以前要厉害上许多,但,那种用明码比较的,还是大有人在的。所谓 明码比较,就是说软件先算出正确的注册码,然后放到内存或你家的沙发下面,之后再得到你输入的那 个注册码,接着就比较了。呵呵,好理解吧,我们只要找到那个比较的地方,看一下软件把注册码放到 内存的哪里了,再到相应的内存处瞧一瞧,就万事OK了! 还记的对你说过的那些常见的(也是最菜的)比较吗?我捡其中最简单的一个来给你再解释一下: mov eax [ ] 这里可以是地址,也可以是其它寄存器 该条指令也可以是mov eax [ ] mov edx [ ] 同上 通常这两个地址就储存着重要信息 该指令也可以是 pop edx call 00?????? 关键call jz(jnz)或 jne(je) 关键跳转 第一条mov eax [ ]指令是将一个内存地址或另外一个寄存器(该寄存器中装的是内存地址)装入eax中 。第二条指令与其相同,是将一个内存地址或另外一个寄存器中的内存地址装入edx中。而这两条指令是 干什么的呢?嘿嘿嘿嘿… 这两条指令就是用来存放真假两个注册码的地址的,也就是说eax和edx这两个寄存器中此时一个装的是 正确的注册码的内存地址,一个是你输入的那个错误的注册码的内存地址。软件在比较注册码前将两个 注册码的内存地址分别装入到两个寄存器中,然后就是关键Call出场。在这个关键Call中对注册码进行 比较时,软件会从相应的寄存器中取出两个注册码来比较,接着出来就是一个关键跳转,通过上面Call 中的比较结果来做相应的跳转… 你应该已经想到什么了吧!没错,我们只要找到软件的关键Call,然后在关键Call处来查看相应的内存 地址就可以找到正确的注册码了 而这一切,都可以通过调试器来完成。从某种意义上来说,如果你能自 己一个人把你家的微波炉修好,那你就绝对会用调试器 我们在调试器中,只要一步一步执行到关键Call 处,然后用d eax和d edx就可以查看两个地址中放的两个注册码,如果你发现其中的一个是你自己刚才 输入的,那么另一条就是正确的 而所谓的内存注册机呢?我这里就不再多说了,它的原理就是自动在软件注册的时候中断到相应的地方, 并显示相应内存处的值,当然它是需要配置的... 此类软件有CRACKCODE2000和注册机编写器keymake, 具体用法你可以参考软件的联机帮助^_^ 我们剩下的问题就是如何来找个这关键Call了,基本上来说你就用前边给你讲爆破时的那种方法就可以 了,很简单的 但是就像你家后门的玻璃可能永远擦不干净一样,我们家后门的玻璃也从来没擦干净过 导演:NG!重说, 就像所有事情都有例外一样,有些软件的关键Call会比较难找一点,但如果你掌握了适当的方法,同样 也会很好找的... 我们就来玩玩吧: 首先,我们还来用CHINAZIP这个软件上上手^_^ 它已经是我们的老朋友了,所以就不用再介绍它了吧 好的,我们先装上它(嘿嘿,偶就是喜欢说废话,你打偶偶也要说^_^)接着我们点帮助-注册,输入 Name:Suunb[CCG],Code:19870219 然后请出我们的老伙计TRW2000,下bpx hmemcpy 按F5点确定被拦: KERNEL?HMEMCPY 0147:9e62 push bp 0147:9e63 mov bp,sp 0147:9e65 push ds 0147:9e66 push edi 0147:9e68 push esi 0147:9e6a cld 0147:9e6b mov ecx,[bp+06] 0147:9e6f jcxz 9ee9 ...省略N多代码... 输入bc *,删除断点。pmodule ,直接跳到程序领空: 0167:00436d13 mov [ebx+0c],eax 0167:00436d16 mov eax,[ebx] 0167:00436d18 cmp eax,byte +0c 0167:00436d1b jnz 00436d38 0167:00436d1d mov edx,[ebx+08] 0167:00436d20 push edx 0167:00436d21 mov ecx,[ebx+04] 0167:00436d24 mov edx,eax 0167:00436d26 mov eax,esi 0167:00436d28 call 00432b24 ...省略N多代码... 按8下F12就会提示出错,我们第二次就按7次 接着我们再来按F10,按16下就会报错,好的,我们再来: 这一次我们按F10的时候,就按我前边说过的方法,到与上次按的次数相差五六次的时候就慢下来。 好的,我们按十来下的时候就慢下来仔细瞅瞅,呵呵,一下子就看到004f4dec处的那个跳转以及它上面 的关键CALL了 我们按F10单步执行到004f4de7处(即关键CALL处)后下指令d edx就可看到真正的注册码, 而d eax则可以看到我刚才输入的19870219 代码给你: 0167:004f4dc4 mov eax,[ebp-08] <---7下F12,1下F10就来到这里(此时ebp-08处放的是刚才输入的注 册码19870219) 0167:004f4dc7 push eax <---将EAX压栈; 0167:004f4dc8 lea edx,[ebp-10] 0167:004f4dcb mov eax,[ebx+02e0] 0167:004f4dd1 call 00432f24 <---该CALL用来得到用户输入的用户名,其实就是某个API函数,嘿嘿, 好奇的话可以追进去看看 0167:004f4dd6 mov edx,[ebp-10] <---将得到的用户名放入EDX; 0167:004f4dd9 lea ecx,[ebp-0c] 0167:004f4ddc mov eax,ebx 0167:004f4dde call 004f4fac <---该CALL用来计算出真正的注册码; 0167:004f4de3 mov edx,[ebp-0c] <---将计算出的真.注册码放入EDX,在下条指令时可用D EDX查看; 0167:004f4de6 pop eax <---先前压入的注册码出栈; 0167:004f4de7 call 0040411c <---该CALL用来比较两个注册码,罪魁祸首啊!; 0167:004f4dec jnz 004f4e64 <---不相等则跳,跳必死,暴破将75改为74或EB,当然90也行; 0167:004f4dee mov dl,01 0167:004f4df0 mov eax,[00452558] 0167:004f4df5 call 00452658 0167:004f4dfa mov [ebp-04],eax 0167:004f4dfd xor eax,eax 0167:004f4dff push ebp 0167:004f4e00 push dword 004f4e5d 0167:004f4e05 push dword [fs:eax] 0167:004f4e08 mov [fs:eax],esp 0167:004f4e0b mov cl,01 0167:004f4e0d mov edx,004f4ea8 0167:004f4e12 mov eax,[ebp-04] 0167:004f4e15 call 0045283c 0167:004f4e1a mov ecx,004f4ecc 0167:004f4e1f mov edx,004f4ef4 0167:004f4e24 mov eax,[ebp-04] 0167:004f4e27 call 00452c80 0167:004f4e2c mov eax,004f4f00 0167:004f4e31 call 00458b8c 0167:004f4e36 mov eax,[0050306c] 0167:004f4e3b mov eax,[eax] 0167:004f4e3d mov edx,004f4f24 0167:004f4e42 call 00432f54 0167:004f4e47 xor eax,eax 0167:004f4e49 pop edx 0167:004f4e4a pop ecx 0167:004f4e4b pop ecx 0167:004f4e4c mov [fs:eax],edx 0167:004f4e4f push dword 004f4e6e 0167:004f4e54 mov eax,[ebp-04] 0167:004f4e57 call 004030c4 0167:004f4e5c ret 0167:004f4e5d jmp 00403824 0167:004f4e62 jmp short 004f4e54 0167:004f4e64 mov eax,004f4f48 <---由上面的0167:004f4dec处跳来,挂!; 0167:004f4e69 call 00458b8c 0167:004f4e6e xor eax,eax 整理: Name:Suunb[CCG] Code:SCCG5296 可以真接在TRW2000中下断点bpx 004f4de6,中断后用D EDX来查看真.注册码。 另附:CRACKCODE2000的CRACKCODE.INI [Options] CommandLine=CHINAZIP.exe Mode=2 First_Break_Address=4f4de7 First_Break_Address_Code=E8 First_Break_Address_Code_Lenth=5 Second_Break_Address=404123 Second_Break_Address_Code_Lenth=2 Save_Code_Address=EDX 呵呵,是不是很简单?我说过了嘛,其实并不难的 我不知道你有没有发现,其实上面的软件的关键CALL还是很好找的,相信你用W32Dasm就中以找出来,那 为什么不用呢?对于那些比较简单的软件,何必非请出调试器呢? 给你贴个用W32Dasm找关键CALL的: 【软件名称】e族百变桌面 【软件版本】4.0 【文件大小】1316KB 【适用平台】Win9x/Me/NT/2000 【软件简介】提供25种变换桌面的方式,让你的桌面焕然一新。操作简单,无需费力学习。支持多种 Internet流行图片格式。将壁纸文件打包,方便存储、转发。将壁纸包展开,还原图片文件。 嘿嘿,我也懒的去折腾我的小猫了,咱们就还用电脑报2001年合订本配套光盘上的软件吧 (2002年的 偶没有买) 首先装上它(嘿嘿,你习惯了?为什么不丢东西了? ^_^)运行一下该软件先,该软件自动生成了相应 的机器码,并停留在注册项上,输入注册码19870219,点确定,挂! 用fi检查,该软件为Delphi编译,没加壳。 用W32DASM打开该执行文件,参考-串式参考,在最下边,见到了刚才弹出的\"注册码不正确,请联系作 者\"。 用鼠标双击,发现只有一处调用,在00488E97处,接着在串式参考对话框中在\"注册码不正确,请联系 作者\"处向上找,找到\"感谢您支持国产软件,祝您好运\"(说的我都不好意思了) 用鼠标双击,仍旧只有一处调用,在00488DF7处: * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00488DCD(U) | :00488DD9 8B45FC mov eax, dword ptr [ebp-04] :00488DDC 8B8020040000 mov eax, dword ptr [eax+00000420] :00488DE2 35280BB61E xor eax, 1EB60B28 :00488DE7 3B45F8 cmp eax, dword ptr [ebp-08] <---关键比较,? EAX来查看软件正确的注册码; :00488DEA 0F85A0000000 jne 00488E90 <---关键跳转,不相等就跳,跳必挂! :00488DF0 6A40 push 00000040 * Possible StringData Ref from Code Obj ->\"注册成功\" | :00488DF2 68D48E4800 push 00488ED4 * Possible StringData Ref from Code Obj ->\"感谢您支持国产软件,祝您好运!\" | :00488DF7 68E08E4800 push 00488EE0 <---双击串式参考便跳到此行,我们向上找第一个跳转处就是 关键跳转,关键跳转上面就是关键比较; :00488DFC 8B45FC mov eax, dword ptr [ebp-04] :00488DFF E81CD2FBFF call 00446020 :00488E04 50 push eax ...省略代码若干... 向上看,00488DEA处有一跳转,不相等便跳到00488E90处,跳必挂!还记的00488E97处的出错对话框吧! 罪魁祸首啊! 在向上一行,看00488DE7处:cmp eax, dword ptr [ebp-08],此为关键比较。可用? EAX查看软件正确的 注册码。 整理: 打开该软件,在注册码处输入19870219,打开TRW2000,下断点bpx 00488DE7,点注册被拦。输入? EAX得 到软件正确的注册码。 机器码:533226313 注册码:25061473 用注册机编写器keymake编写该软件的注册机: 点其它-另类注册机(F8),软件名称输入ePaper.exe,注册码选寄存器方式 EAX 十进制。 添加断点,中断地址:00488DE7,中断次数:1,第一字节:3B,指令长度:3。 生成注册机后完工,万事OK! 嘿嘿,现在是不是觉的找软件的注册码越来越像小时候玩的躲猫猫了? 可惜偶小时候没有青梅竹马那 种类型的伙伴... 好的,我们这次讲个有点儿名气的软件,WinZIP8.1,这个软件相信大家都用过吧,反正偶是喜欢用RAR, 不过也多少用过几天这玩意儿... 如果你没听说过,那看介绍好了 【软件名称】WinZIP 【软件版本】8.1 Beta 2 【文件大小】1757KB 【适用平台】Win9x/Me/NT/2000 【软件简介】一个强大并且易用的压缩实用程序,支持ZIP、CAB、TAR、GZIP、MIME,以及更多格式的 压缩文件。其特点是紧密地与Windows资源管理器拖放集成,不用离开资源管理器而进行压缩、解压缩。 不用我说了吧,出处仍旧是电脑报2001年合订本的配套光盘 我之所以先择它,是因为觉得它的关键CALL没有前边那两个那样好找(其实也就那样了^_^)极具代表性, 而且通过它可以让你感受一下Ollydbg这个魅力比你家的荼几还大的调试器 这里之所以提到Ollydbg,是觉的它真是一个非常非常棒的调试器...强烈建议你多玩几次...(MP3好听 吗? ^_^) 我们来吧,首先当然还是要装上它(左闪术,右闪术),然后用Ollydbg来载入,此时界面会被分成四个部 分,左上方是软件反汇编后的代码,右上方是寄存器开会的地方,左下方是内存区,右下方显示的则是 堆栈的信息。 我们来下断点,按Alt+F4,之后选USER32,然后再鼠标右键-->搜索-->当前模块中的名称,然后在那一 大堆函数中找到GetDlgItemTextA,按F2来下断点,它会提示你错误,并说无法设置中断点,是不是很 过瘾?(呜呜呜...大哥,我错了,再也不敢了...) 呵呵,这个我也不知道什么原因,明明是用了这个函数嘛,就是不让断,其实我对Ollydbg也不是太那 个(关键是讨厌它的下断方式)看来还是用我们的万能断点吧,输入注册名Suunb[CCG],输入注册码 19870219,然后用TRW2000下断bpx hmemcpy,断到之后,pmodule返回领空后一次F12就会出错,看来所 有的东东就在这里了... 我们用TRW2000再断一下,返回领空之后记着第一条指令的地址0040bd5f,呜呜呜...上条指令明明是 调用GetDlgItemTextA,为什么在Ollydbg中不让下呢? 没关系,我们记下这个地址后仍旧用Ollydbg来加载程序,之后在反汇编窗口中找到0040bd5f处,然后 按下F2来下断(会变为红色),下断之后便按F9来运行程序,接着输入注册名Suunb[CCG],注册码 19870219后按确定,程序会被Ollydbg给断到: 0040BD5F |. 57 PUSH EDI 0040BD60 |. E8 F34A0500 CALL WINZIP32.00460858 0040BD65 |. 57 PUSH EDI ; /Arg1 0040BD66 |. E8 164B0500 CALL WINZIP32.00460881 ; \\WINZIP32.00460881 0040BD6B |. 59 POP ECX 0040BD6C |. BE 1CCA4C00 MOV ESI,WINZIP32.004CCA1C 0040BD71 |. 59 POP ECX 0040BD72 |. 6A 0B PUSH 0B ; /Count = B (11.) 0040BD74 |. 56 PUSH ESI ; |Buffer => WINZIP32.004CCA1C 0040BD75 |. 68 810C0000 PUSH 0C81 ; |ControlID = C81 (3201.) 0040BD7A |. 53 PUSH EBX ; |hWnd 0040BD7B |. FF15 F4C54A00 CALL DWORD PTR DS:[<&USER32.GetDlgItemTe>; \\GetDlgItemTextA 0040BD81 |. 56 PUSH ESI 0040BD82 |. E8 D14A0500 CALL WINZIP32.00460858 0040BD87 |. 56 PUSH ESI 0040BD88 |. E8 F44A0500 CALL WINZIP32.00460881 0040BD8D |. 803D F0C94C00 >CMP BYTE PTR DS:[4CC9F0],0 0040BD94 |. 59 POP ECX 0040BD95 |. 59 POP ECX 0040BD96 |. 74 5F JE SHORT WINZIP32.0040BDF7 0040BD98 |. 803D 1CCA4C00 >CMP BYTE PTR DS:[4CCA1C],0 0040BD9F |. 74 56 JE SHORT WINZIP32.0040BDF7 0040BDA1 |. E8 31F9FFFF CALL WINZIP32.0040B6D7 <--关键CALL,等会儿进去玩玩 0040BDA6 |. 84C0 TEST AL,AL <--根据关键CALL中比较的结果来做相应的测试 0040BDA8 |. 74 4D JE SHORT WINZIP32.0040BDF7 <--跳走就没戏! 0040BDAA |. 57 PUSH EDI 0040BDAB |. 68 08DE4B00 PUSH WINZIP32.004BDE08 ; ASCII \"Name\" 0040BDB0 |. FF35 1CC74A00 PUSH DWORD PTR DS:[4AC71C] ; WINZIP32.004BDDEC 0040BDB6 |. E8 8AFA0400 CALL WINZIP32.0045B845 0040BDBB |. 56 PUSH ESI 0040BDBC |. 68 C8EB4B00 PUSH WINZIP32.004BEBC8 ; ASCII \"SN\" 0040BDC1 |. FF35 1CC74A00 PUSH DWORD PTR DS:[4AC71C] ; WINZIP32.004BDDEC 0040BDC7 |. E8 79FA0400 CALL WINZIP32.0045B845 0040BDCC |. FF35 18C74A00 PUSH DWORD PTR DS:[4AC718] ; |Arg4 = 004BDDF4 ASCII \"winzip32.ini\" 0040BDD2 |. 6A 00 PUSH 0 ; |Arg3 = 00000000 0040BDD4 |. 6A 00 PUSH 0 ; |Arg2 = 00000000 0040BDD6 |. 68 14DE4B00 PUSH WINZIP32.004BDE14 ; |Arg1 = 004BDE14 ASCII \"rrs\" 0040BDDB |. E8 4CFA0400 CALL WINZIP32.0045B82C ; \\WINZIP32.0045B82C 0040BDE0 |. A1 A8914C00 MOV EAX,DWORD PTR DS:[4C91A8] 0040BDE5 |. 83C4 28 ADD ESP,28 0040BDE8 |. 85C0 TEST EAX,EAX 0040BDEA |. 74 07 JE SHORT WINZIP32.0040BDF3 0040BDEC |. 50 PUSH EAX ; /hObject => 000013F4 (font) 0040BDED |. FF15 80C04A00 CALL DWORD PTR DS:[<&GDI32.DeleteObject>>; \\DeleteObject 0040BDF3 |> 6A 01 PUSH 1 0040BDF5 |. EB 30 JMP SHORT WINZIP32.0040BE27 0040BDF7 |> E8 C3020000 CALL WINZIP32.0040C0BF 0040BDFC |. 68 8E020000 PUSH 28E 0040BE01 |. E8 61470500 CALL WINZIP32.00460567 0040BE06 |. 50 PUSH EAX ; |Arg3 0040BE07 |. 53 PUSH EBX ; |Arg2 0040BE08 |. 6A 3D PUSH 3D ; |Arg1 = 0000003D 0040BE0A |. E8 C8050400 CALL WINZIP32.0044C3D7 ; \\WINZIP32.0044C3D7 我们用Ollydbg断到之后,可以像在TRW2000中一样通过F8(这个调试器跟我一样,也不喜欢F4^_^)来单 步执行程序,我们按32下F8后程序就会出错,那我们在第二遍载入时按F8按到20多下时就仔细看看有没 有可疑的地方,你一眼就可以看到0040BDA1处的这个关键CALL,我们只要追到这里时追进去就有可能看 到软件正确的注册码 那还等什么呢?我们就进去吧... 按F7跟进后你会看的眼花眼花缭乱,到处都是PUSH跟POP,到底哪个才是呢?现在知道我为什么让你用 Ollydbg了吧(偶起初也是要用TRW2000的,但临时改变主意 ^_^)用Ollydbg的一个最大好处就是可以真 接看到寄存器中的值,特别是你通过F8来单步执行的时候,在反汇编代码的下边,会有一个小窗体, 在那里可以显示相关指令中所使用的寄存器的值,爽吧! 我们按76下F8之后,在0040B803处就可以第一次看到正确的注册码了,呵呵,我这边儿是71C20EDC,然 后你还会再陆续看到几次,爽? 另外我还发现一个有趣的事情,在WinZIP8.1中,一个注册名可以有两个注册码,呵呵,不知道是不是 还有为特别用户准备的特别注册码以用来和普通的做区别 当程序通过比较,发现你输入的注册码不正 确后竟然会再次算出另一个注册码来再比较一次,嘿嘿,我的第二个注册码是25170288 追入关键CALL里的代码: 0040B6D7 /$ 55 PUSH EBP 0040B6D8 |. 8BEC MOV EBP,ESP 0040B6DA |. 81EC 0C020000 SUB ESP,20C 0040B6E0 |. 8065 FF 00 AND BYTE PTR SS:[EBP-1],0 0040B6E4 |. 803D F0C94C00 >CMP BYTE PTR DS:[4CC9F0],0 0040B6EB |. 53 PUSH EBX 0040B6EC |. 56 PUSH ESI 0040B6ED |. 57 PUSH EDI 0040B6EE |. 0F84 FB000000 JE WINZIP32.0040B7EF 0040B6F4 |. 8D45 E8 LEA EAX,DWORD PTR SS:[EBP-18] 0040B6F7 |. 50 PUSH EAX 0040B6F8 |. 68 C0E84B00 PUSH WINZIP32.004BE8C0 0040B6FD |. E8 DE61FFFF CALL WINZIP32.004018E0 0040B702 |. 8D45 E8 LEA EAX,DWORD PTR SS:[EBP-18] 0040B705 |. 50 PUSH EAX 0040B706 |. E8 F57C0800 CALL WINZIP32.00493400 0040B70B |. 83C4 0C ADD ESP,0C 0040B70E |. 83F8 14 CMP EAX,14 0040B711 |. 72 11 JB SHORT WINZIP32.0040B724 0040B713 |. BF 20C74A00 MOV EDI,WINZIP32.004AC720 ; ASCII \"auth.c\" 0040B718 |. 6A 21 PUSH 21 0040B71A |. 57 PUSH EDI 0040B71B |. E8 86F60000 CALL WINZIP32.0041ADA6 0040B720 |. 59 POP ECX 0040B721 |. 59 POP ECX 0040B722 |. EB 05 JMP SHORT WINZIP32.0040B729 0040B724 |> BF 20C74A00 MOV EDI,WINZIP32.004AC720 ; ASCII \"auth.c\" 0040B729 |> 8D85 F4FDFFFF LEA EAX,DWORD PTR SS:[EBP-20C] 0040B72F |. BB F0C94C00 MOV EBX,WINZIP32.004CC9F0 ; ASCII \"Suunb[CCG]\" 0040B734 |. 50 PUSH EAX 0040B735 |. 53 PUSH EBX 0040B736 |. E8 50030000 CALL WINZIP32.0040BA8B 0040B73B |. 8D85 F4FDFFFF LEA EAX,DWORD PTR SS:[EBP-20C] 0040B741 |. 50 PUSH EAX 0040B742 |. E8 B97C0800 CALL WINZIP32.00493400 0040B747 |. BE C8000000 MOV ESI,0C8 0040B74C |. 83C4 0C ADD ESP,0C 0040B74F |. 3BC6 CMP EAX,ESI 0040B751 |. 72 0A JB SHORT WINZIP32.0040B75D 0040B753 |. 6A 23 PUSH 23 0040B755 |. 57 PUSH EDI 0040B756 |. E8 4BF60000 CALL WINZIP32.0041ADA6 0040B75B |. 59 POP ECX 0040B75C |. 59 POP ECX 0040B75D |> 8D85 F4FDFFFF LEA EAX,DWORD PTR SS:[EBP-20C] 0040B763 |. 50 PUSH EAX 0040B764 |. 8D45 E8 LEA EAX,DWORD PTR SS:[EBP-18] 0040B767 |. 50 PUSH EAX 0040B768 |. E8 03300900 CALL WINZIP32.0049E770 0040B76D |. 59 POP ECX 0040B76E |. 85C0 TEST EAX,EAX 0040B770 |. 59 POP ECX 0040B771 |. 75 04 JNZ SHORT WINZIP32.0040B777 0040B773 |. C645 FF 01 MOV BYTE PTR SS:[EBP-1],1 0040B777 |> 8D45 E8 LEA EAX,DWORD PTR SS:[EBP-18] 0040B77A |. 50 PUSH EAX 0040B77B |. 68 D0E84B00 PUSH WINZIP32.004BE8D0 0040B780 |. E8 5B61FFFF CALL WINZIP32.004018E0 0040B785 |. 8D45 E8 LEA EAX,DWORD PTR SS:[EBP-18] 0040B788 |. 50 PUSH EAX 0040B789 |. E8 727C0800 CALL WINZIP32.00493400 0040B78E |. 83C4 0C ADD ESP,0C 0040B791 |. 83F8 14 CMP EAX,14 0040B794 |. 72 0A JB SHORT WINZIP32.0040B7A0 0040B796 |. 6A 27 PUSH 27 0040B798 |. 57 PUSH EDI 0040B799 |. E8 08F60000 CALL WINZIP32.0041ADA6 0040B79E |. 59 POP ECX 0040B79F |. 59 POP ECX 0040B7A0 |> 8D45 E8 LEA EAX,DWORD PTR SS:[EBP-18] 0040B7A3 |. 50 PUSH EAX 0040B7A4 |. 53 PUSH EBX 0040B7A5 |. E8 C62F0900 CALL WINZIP32.0049E770 0040B7AA |. 59 POP ECX 0040B7AB |. 85C0 TEST EAX,EAX 0040B7AD |. 59 POP ECX 0040B7AE |. 75 0E JNZ SHORT WINZIP32.0040B7BE 0040B7B0 |. FF15 F0C14A00 CALL DWORD PTR DS:[<&KERNEL32.GetTickCou>; [GetTickCount 0040B7B6 |. A8 01 TEST AL,1 0040B7B8 |. 74 04 JE SHORT WINZIP32.0040B7BE 0040B7BA |. C645 FF 01 MOV BYTE PTR SS:[EBP-1],1 0040B7BE |> 6A 14 PUSH 14 0040B7C0 |. 8D45 E8 LEA EAX,DWORD PTR SS:[EBP-18] 0040B7C3 |. 6A 00 PUSH 0 0040B7C5 |. 50 PUSH EAX 0040B7C6 |. E8 75820800 CALL WINZIP32.00493A40 0040B7CB |. 56 PUSH ESI 0040B7CC |. 8D85 F4FDFFFF LEA EAX,DWORD PTR SS:[EBP-20C] 0040B7D2 |. 6A 00 PUSH 0 0040B7D4 |. 50 PUSH EAX 0040B7D5 |. E8 66820800 CALL WINZIP32.00493A40 0040B7DA |. 83C4 18 ADD ESP,18 0040B7DD |. 807D FF 00 CMP BYTE PTR SS:[EBP-1],0 0040B7E1 |. 74 13 JE SHORT WINZIP32.0040B7F6 0040B7E3 |. E8 D7080000 CALL WINZIP32.0040C0BF 0040B7E8 |. 8025 EDBF4C00 >AND BYTE PTR DS:[4CBFED],0 0040B7EF |> 32C0 XOR AL,AL 0040B7F1 |. E9 F5000000 JMP WINZIP32.0040B8EB 0040B7F6 |> 8D85 BCFEFFFF LEA EAX,DWORD PTR SS:[EBP-144] 0040B7FC |. 50 PUSH EAX 0040B7FD |. 53 PUSH EBX 0040B7FE |. E8 ED000000 CALL WINZIP32.0040B8F0 <--参与计算软正确的注册码 0040B803 |. 8D85 BCFEFFFF LEA EAX,DWORD PTR SS:[EBP-144] <--在这里第一次发现软件正确的注 册码 0040B809 |. 50 PUSH EAX 0040B80A |. E8 F17B0800 CALL WINZIP32.00493400 0040B80F |. BE 2C010000 MOV ESI,12C 0040B814 |. 83C4 0C ADD ESP,0C 0040B817 |. 3BC6 CMP EAX,ESI 0040B819 |. 72 0A JB SHORT WINZIP32.0040B825 0040B81B |. 6A 39 PUSH 39 0040B81D |. 57 PUSH EDI 0040B81E |. E8 83F50000 CALL WINZIP32.0041ADA6 0040B823 |. 59 POP ECX 0040B824 |. 59 POP ECX 0040B825 |> BF 1CCA4C00 MOV EDI,WINZIP32.004CCA1C ; ASCII \"19870219\" <--将刚才输入的错误 的注册码放入EDI 0040B82A |. 8D85 BCFEFFFF LEA EAX,DWORD PTR SS:[EBP-144] <--EAX中装入正确的注册码所在的地址 0040B830 |. 57 PUSH EDI <--用户输入的注册码入栈 0040B831 |. 50 PUSH EAX <--软件计算出的正确的注册码入栈 0040B832 |. E8 392F0900 CALL WINZIP32.0049E770 <--关键CALL,用于比较用户输入的注册码 0040B837 |. F7D8 NEG EAX 0040B839 |. 1AC0 SBB AL,AL 0040B83B |. 59 POP ECX 0040B83C |. FEC0 INC AL 0040B83E |. 59 POP ECX 0040B83F |. A2 EDBF4C00 MOV BYTE PTR DS:[4CBFED],AL 0040B844 |. 0F85 8A000000 JNZ WINZIP32.0040B8D4 0040B84A |. 8D85 BCFEFFFF LEA EAX,DWORD PTR SS:[EBP-144] 0040B850 |. 50 PUSH EAX 0040B851 |. 53 PUSH EBX 0040B852 |. E8 33010000 CALL WINZIP32.0040B98A <--参与计算软件的第二个注册码 0040B857 |. 8D85 BCFEFFFF LEA EAX,DWORD PTR SS:[EBP-144] <--此时软件会再算出另外一个注册码 0040B85D |. 50 PUSH EAX 0040B85E |. E8 9D7B0800 CALL WINZIP32.00493400 0040B863 |. 83C4 0C ADD ESP,0C 0040B866 |. 3BC6 CMP EAX,ESI 0040B868 |. 72 0E JB SHORT WINZIP32.0040B878 0040B86A |. 6A 3E PUSH 3E 0040B86C |. 68 20C74A00 PUSH WINZIP32.004AC720 ; ASCII \"auth.c\" 0040B871 |. E8 30F50000 CALL WINZIP32.0041ADA6 0040B876 |. 59 POP ECX 0040B877 |. 59 POP ECX 0040B878 |> 8D85 BCFEFFFF LEA EAX,DWORD PTR SS:[EBP-144] <--软件计算出的第二个注册码装入 EAX中 0040B87E |. 57 PUSH EDI <--用户输入的注册码入栈 0040B87F |. 50 PUSH EAX <--软件计算出的第二个注册码入栈 0040B880 |. E8 EB2E0900 CALL WINZIP32.0049E770 <--另一个关键CALL,用于比较第二次生成的 注册码 0040B885 |. F7D8 NEG EAX 0040B887 |. 1AC0 SBB AL,AL 0040B889 |. 59 POP ECX 0040B88A |. FEC0 INC AL 0040B88C |. 59 POP ECX 0040B88D |. A2 EDBF4C00 MOV BYTE PTR DS:[4CBFED],AL 0040B892 |. 75 40 JNZ SHORT WINZIP32.0040B8D4 0040B894 |. 8D85 C0FEFFFF LEA EAX,DWORD PTR SS:[EBP-140] 0040B89A |. 6A 04 PUSH 4 0040B89C |. 50 PUSH EAX 0040B89D |. 57 PUSH EDI 0040B89E |. E8 DD690900 CALL WINZIP32.004A2280 0040B8A3 |. 83C4 0C ADD ESP,0C 0040B8A6 |. 85C0 TEST EAX,EAX 0040B8A8 |. 75 23 JNZ SHORT WINZIP32.0040B8CD 0040B8AA |. 8D85 BCFEFFFF LEA EAX,DWORD PTR SS:[EBP-144] 0040B8B0 |. 6A 04 PUSH 4 0040B8B2 |. 50 PUSH EAX 0040B8B3 |. 68 20CA4C00 PUSH WINZIP32.004CCA20 ; ASCII \"0219\" 0040B8B8 |. E8 C3690900 CALL WINZIP32.004A2280 0040B8BD |. 83C4 0C ADD ESP,0C 0040B8C0 |. 85C0 TEST EAX,EAX 0040B8C2 |. 75 09 JNZ SHORT WINZIP32.0040B8CD 0040B8C4 |. C605 EDBF4C00 >MOV BYTE PTR DS:[4CBFED],1 0040B8CB |. EB 07 JMP SHORT WINZIP32.0040B8D4 0040B8CD |> 8025 EDBF4C00 >AND BYTE PTR DS:[4CBFED],0 0040B8D4 |> 56 PUSH ESI 0040B8D5 |. 8D85 BCFEFFFF LEA EAX,DWORD PTR SS:[EBP-144] 0040B8DB |. 6A 00 PUSH 0 0040B8DD |. 50 PUSH EAX 0040B8DE |. E8 5D810800 CALL WINZIP32.00493A40 0040B8E3 |. A0 EDBF4C00 MOV AL,BYTE PTR DS:[4CBFED] 0040B8E8 |. 83C4 0C ADD ESP,0C 0040B8EB |> 5F POP EDI 0040B8EC |. 5E POP ESI 0040B8ED |. 5B POP EBX 0040B8EE |. C9 LEAVE 0040B8EF \\. C3 RETN 整理一下: 注册名:Suunb[CCG] 注册码:71C20EDC or 25170288 其实如果你坐在那里肯花上一杯茶的功夫来仔细想一下,就会知道,其实一点儿也不难,只是有一点 点麻烦而以 这一章也就到这里吧,我现在巨困无比... 最后说一下的是,现在有仍有N多的软件用的是明码的比较方法,所以,要想找一两个软件练练手还是 挺容易的 这一章本来还打算讲一下那些非明码比较的软件的,但忽然发现,如果通过非明码比较的软件能找到 注册码的话,那应该也就把它的算法给搞的差不多了,所以,到下一章,分析软件的注册算法时再讲 吧... chensu198 2005-7-19 03:56 注册码是怎样炼成的 第八章--注册码是怎样炼成的 你应该明白的是,并不是所有的软件作者都像你想象并希望的那笨 没有人愿意自己的软件被别人在调 试器中用一条d指令就能找到正确的注册码...要是那样的话还出来搞什么? 前边儿我们讲的查找软件注册码的方法是有针对性的,必须保证的是该软件使用的是明码比较,这样的 话,我们只需找对地方,一个d指令就成了。那既然有明码比较这个词,就不难猜出还有相应的非明码 比较...非明码比较也比较容易理解,就是软件比较两个注册码的方法不同而以,并不是计算出正确的 注册码后就与用户输入的进行比较,它可能会采用每计算出一位就与注码中的相应位比较一次,一但发 现与用户输入的不同,就提示出错等等等等... 遇到这样的软件,我们其实也可以找到其相应的注册码,但有点儿惨,要一位一位的计下来...但是如 果人家不给你面子,一但计算出某位不正确就跳走的话,那你怎么办?所以,国民想致富,种树是根 本...NG!所以遇到这种软件,我们就只有对其算法进行分析,并做出注册机才是唯一的方法(如果你 想写注册机的话)... 你要明白,就算我们能找到那些采用明码比较的软件的注册码,原因也仅仅是因为其采用的是明码比 较,所以我们没有什么值的高兴的地方,我们真正要做的,并不是找到一个注册码而以...当然如果你 刚入门,那对你的提高还是很有帮助的。我们Crack一个软件的最终目的,是对其进行相应的分析, 搞懂它的注册算法并写出注册机,这样才算是成功的Crack了一个软件,成功后的心情是难以表达的! 就像你便秘了多天后一下子排了出来一样 ^_^,呵呵这个比喻虽然粗俗,但是你可以想象一下,对一 个软件进行仔细的分析,最后一下把它的算法给搞明白了,那种感觉...我深信不疑的认为有一天你也 能体会的到,偶等你 相信你以前看过那些高人大虾的关于软件注册算法分析的文章,同时也相信你有过试图跟踪分析某软 件的举动,虽然后来的结果另人不太满意 其实分析一个软件的注册算法,这其中包括了一些技巧性方面的东西以及必要的经验,很难想象一个 连调试器的使用都还没掌握的人试图去分析一个软件会是怎样一个场面...嘿嘿,偶是见过的 使用调 试器并不难,但那并不意味着你就能去分析一个软件了,见CALL就追这样的举动可不是偶一个人有过的 经历,本章我尽量给你说明适当的分析方法。 相信大家都有不在父母陪同下独自使用调试器的能力以及看懂大部分汇编指令的能力了吧,那就够了! 我们开始... 正式开始今天的正题,我来举两个例子,相信这两个例子都有足够的表达能力,最起码比我们家楼下那 个卖油条的表达能力要强多了... 好的,首先,我们还是请出我们的那位老朋友吧 嘿嘿,在此,偶向CHINAZIP(中华压缩)v7.0的作者 表示我内心最真诚的歉意!相信我用这个老版本的中华压缩不会给您带来经济上的麻烦... 通过前边儿两章的讲解,我们已经把这个软件大体上给搞明白了,并且也追出了其相应的注册码。而我 们今天的目的是对其注册算法进行分析,并写出注册机!这个软件的注册算法其实也比较简(并且存 在Bug)用它来当例子,很能说明情况... 好的,我们开始,前边儿追注册码的时候我们就已经知道了其用于计算正确注册码的关键CALL的所在 位置为004f4dde,我们用TRW2000来对其进行分析!(鉴于目前大部分教程中仍以TRW2000为主,而且这 个是大多数菜鸟都会用的调试器,偶就用这个调试器来做具体讲解) 先启动CHINAZIP,帮助--注册(所以我才说这个软件非常适合写教程用嘛,注册后仍然中以再次注册 )输入注册名Suunb[CCG],注册码19870219。之看按Ctrl+N呼出TRW2000,下断点bpx 004f4dde,F5返 回。 接着就按确定吧,呵呵,被TRW2000拦到了。通过前边两章的分析,我们以经知道了004f4dde处的这个 CALL用于计算正确的注册码,所以我们直接按F8跟进吧!注册码的算法,就包涵在这个CALL中,把它 给分析透了,我们也就能弄明白软件的注册码是怎样生成的了。但是要怎么分析呢?这是一个比较严肃 的问题,面对那一堆堆的指令,我不知道你是怎么想的,反正我第一次时是觉的找不着北,我怎么哪些 重要哪些不重要呢?再说了,里面又包涵了那么多CALL,我还要一个一个地追进去看看? 呵呵,这就是我说的技巧所在了。其实也没什么可怕的,只要你汇编不是问题,就行了。我们首先可以 先把这个计算注册码的CALL从头到尾执行一遍,搞明白其中大概的跳转以及其中某些CALL的作用, hehe~~你可以执行过一个CALL后就看一下各个寄存器的变化情况(如果寄存器中的值改变了,颜色就会 变)如果某寄存器的值在CALL过之后改变了,我们就可以看一下其包含的值是何类型,如是内存地址 就用d指令看一下,如是数值就看一下是不是得到你输入注册名或注册码的位数等等,这样的话就可以 淘汰下来一大部分的CALL,因为有许多CALL的作用只是把注册名或注册码装入到内存中的某个地址或 者得到注册名(注册码)的位数或注册码某一位的ASCII码,对与这些,我们不必深究。还是推荐你用 Ollydbg,执行过一条指令后很多信息都可以看到 好的,我接着说,按F8追入CALL之后先大概走一遍 ...我给出追入后的反汇编代码,并给出注释,相应的分析看后面... 0167:004f4fac push ebp <--F8跟入后的第一条指令 0167:004f4fad mov ebp,esp 0167:004f4faf push byte +00 0167:004f4fb1 push byte +00 0167:004f4fb3 push byte +00 0167:004f4fb5 push byte +00 0167:004f4fb7 push byte +00 0167:004f4fb9 push byte +00 0167:004f4fbb push byte +00 0167:004f4fbd push ebx 0167:004f4fbe push esi 0167:004f4fbf push edi 0167:004f4fc0 mov [ebp-08],ecx 0167:004f4fc3 mov [ebp-04],edx 0167:004f4fc6 mov eax,[ebp-04] 0167:004f4fc9 call 004041c0 0167:004f4fce xor eax,eax 0167:004f4fd0 push ebp 0167:004f4fd1 push dword 004f5097 0167:004f4fd6 push dword [fs:eax] 0167:004f4fd9 mov [fs:eax],esp 0167:004f4fdc xor esi,esi 0167:004f4fde lea eax,[ebp-0c] 0167:004f4fe1 mov edx,[ebp-04] 0167:004f4fe4 call 00403e24 <--此CALL过后用于得到用户输入的注册名 0167:004f4fe9 mov eax,[ebp-0c] <--将得到的注册名的地址装用eax寄存器 0167:004f4fec call 0040400c <--此CALL用于得到用户输入的注册名的位数,并将其放入eax中 0167:004f4ff1 mov edi,eax <--将注册名的位数装入edi中 0167:004f4ff3 test edi,edi <--对edi进行测试 0167:004f4ff5 jng 004f5051 <--如果edi中的值为0就会跳走 0167:004f4ff7 mov ebx,01 <--ebx置1,用于后面的运算 0167:004f4ffc mov eax,[ebp-0c] <--ebp-0c中装的是注册名的内存地址,此时将其付于eax 0167:004f4fff mov al,[eax+ebx-01] <--eax中此时装的是注册名的内存地址,加上ebx中的值再减 去01,用于得到注册码中的相应位的字符,比如说我们第一次执行到这里的时候ebx中装入的是01,再 减去01后得到的值其实还是eax本身,这样就能得到注册名中的第一个字符了,而执行到后边再跳回来时 ebx会加上1,所以就能得到下一个字符了... 0167:004f5003 call 004f4f60 <--这个CALL很重要,后面会说明我们是怎样知道它很重要的 0167:004f5008 test al,al <--在这里我们会发现一个测试运算,对象是al,而al在前边CALL之前刚装 入了注册名中的某一个字符,所以我们可以断定上面的那个CALL会对得到的字符做上一些手脚,待会儿 我们再跟入... 0167:004f500a jz 004f5031 <--如果al中装的是0就跳到004f5031处,而al中的值会被004f5003处的那 个CALL所改变 0167:004f500c lea eax,[ebp-18] 0167:004f500f mov edx,[ebp-0c] <--ebp-0c中装的是注册名的内存地址,此时装入edx中 0167:004f5012 mov dl,[edx+ebx-01] <--跟前边儿004f4fff处的指令道理相同,得到注册码中的当前 参加运算的字符 0167:004f5016 call 00403f34 <--不重要!! 0167:004f501b mov eax,[ebp-18] 0167:004f501e lea edx,[ebp-14] 0167:004f5021 call 004088ac <--不重要!! 0167:004f5026 mov edx,[ebp-14] 0167:004f5029 lea eax,[ebp-10] 0167:004f502c call 00404014 <--该CALL同样比较重要,其作用是这样的,如果当前参加运算的字符 在前边004f5003的CALL里进行运算之后符合了要求(符合要求后al会被置非0值)那么在004f500a处的 跳转将会失去作用,而执行到这里后该CALL会将当前的这个符合要求的字符保存到00D3B3C4处(内存) !!后边儿会再详细说明 0167:004f5031 cmp ebx,byte +01 <--用此时ebx中装的值减去1 0167:004f5034 jz 004f5040 <--如果为零,也就是说此时计算的是注册名中的第一个字符的话就跳到 004f5040处 0167:004f5036 mov eax,[ebp-0c] <--ebp-0c中装的是注册名的内存地址,该指令将注册名的内存地址 装入eax中 0167:004f5039 movzx eax,byte [eax+ebx-02] <--用于得到上一个参加运算的字符 0167:004f503e jmp short 004f5046 <--无条件跳转到004f5046处 0167:004f5040 mov eax,[ebp-0c] <--ebp-0c中装的是注册名的内存地址 0167:004f5043 movzx eax,byte [eax] <--得到注册名的第一个字符 0167:004f5046 lea esi,[esi+eax*4+a8] <--!!!这一条指令就是关键所在,后面会说明的!!!此指令先 得到本轮参加运算的字符的ASCII码,然后乘以6,之后再加上a8(即十进制数168,呵呵,可以理解) 同时再将这个字符计算得到的值与前面已经运算过的字符的值的和相加! 0167:004f504d inc ebx <--ebx加1,用于得到注册码的下一个字符 0167:004f504e dec edi <--edi减1,edi中装的是注册码的位数 0167:004f504f jnz 004f4ffc <--不为零就跳到004f4ffc处开始对下一个字符进行运算...也就是说每 计算完一个字符就将edi减去1,直到其为0也就是所有的字符全参加过运算为止。 0167:004f5051 lea edx,[ebp-1c] <--把装注册码后半部分的地址装入edx,传给下面的CALL 0167:004f5054 mov eax,esi <--将前面计算的注册码的后半部分的值装入eax中 0167:004f5056 call 00408c70 <--将前面计算得到的注册码后半部分的值转换为十进制,并装入 ebp-1c中 0167:004f505b mov ecx,[ebp-1c] <--epb-1c中装的是注册码的后半部分 0167:004f505e lea eax,[ebp-0c] 0167:004f5061 mov edx,[ebp-10] <--ebp-10中装的是注册码的前半部分 0167:004f5064 call 00404058 <--该CALL用于将前后两部分注册码合并置一起,合并后的注册码会存 放置ebp-0c处 0167:004f5069 mov eax,[ebp-08] 0167:004f506c mov edx,[ebp-0c] 0167:004f506f call 00403de0 0167:004f5074 xor eax,eax 0167:004f5076 pop edx 0167:004f5077 pop ecx 0167:004f5078 pop ecx 0167:004f5079 mov [fs:eax],edx 0167:004f507c push dword 004f509e 0167:004f5081 lea eax,[ebp-1c] 0167:004f5084 mov edx,05 0167:004f5089 call 00403db0 0167:004f508e lea eax,[ebp-04] 0167:004f5091 call 00403d8c 呵呵,看了我加了注释后的代码是不是好理解多了?你也许会问,你怎么知道那些CALL是做什么的? 我前边儿不是说过方法了吗?我们先大概地过上一遍,看一下各个跳转,然后再大大概的看一下各个 CALL的作用...你以为上面这些注释是我过一遍之后就能写出来的?你多过几遍,心中就会有了个大 概... 你现在在想些什么?众人:站着说话不腰痛...我晕~~ 呵呵,我尽量说的仔细一些: 其实很好理解的,我们追了进来,之后大概的看一下那些个CALL,其中一些稍有经验的一看就知道是 用来得到注册名或长度什么的...之后我们再从头跟一遍...跟到004f4ff3处,会发现其会对注册名的 位数进行一个比较,看用户是否输入了注册名...(也就是说如果edi中装的注册名的位数不大于0,即 没输入就跳走,一会儿我会在后面说一下关于这点儿的Bug)而后在004f4ffc处我们会发现软件会得到 注册名的内存地址,接下来的一条指令一看就知道是用来得到注册名中的各个字符的,嘿嘿,见到这类 指令,马上就向下看吧,找一下下边儿哪条指令会再跳回到004f4ffc处...呵呵,我们会在004f504f处 发现目标,好了,现在我们就知道了从004f4ffc到004f504f之间的那些个指令会对注册名中的每一个 字符进行计算... 呵呵,也就是说软件从004f4ffc处开始先是得到注册名中的第N位字符,然后进行一系列的运算,之后 执行到了004f504e处时把先前先到的注册名的位数减去1然后看其是否为0,不为0就再跳到004f4ffc处, 然后得以注册名的N+1位再来进行计算。此举的目的就是为了看注册名的各位是否都被计算过了,如果 不为0就说明还没有计算完,呵呵,很简单的道理嘛,edi中装的是注册名的位数,第计算过一位后就将 其减1,减完了,注册名的各位也就都参加了运算... 好的,我们再来