📄 dfcg破解入门.txt
字号:
例如:u 4417f8,441806 >c:\dfcg.txt
截取的汇编代码保存在dfcg.txt中
DFCG破解入门第八课
日期:2003年9月9日 作者: 人气:2735 出处:赢政天下整理收藏
--------------------------------------------------------------------------------
暴力破解基础知识
所谓“暴力”破解,指的是在不能通过注册方式正常破解程序时,通过“暴力”-- 即直接修改欲破解程序的关键部分可执行代码,屏蔽或使欲程序的保护方式失效,从而达到破解软件目的的一种破解方式。
相对而言,我们可以把软件破解分成三种形式:暴力破解、注册破解和注册机破解。其中暴力破解包含手动暴力破解和补丁破解,手动暴力破解即破解者自己动手修改原程序文件代码、SMC补丁(Self Modified Code -- 自修改代码)等,补丁破解即通过专门针对特定版本程序写出来的补丁程序自动为原程序修改代码的方式,包括文件补丁程序、内存补丁程序、等等;注册破解是通过对程序的跟踪获得正确的注册码、序列号、密码、CD KEY、钥匙文件。。。等等,能够通过软件“正版”用户方式注册软件的方式;注册机破解是在注册破解的基础上通过研究原程序的加密算法,然后逆向恢复算法过程,并通过写程序的方式得到一个通用的注册机,这种方式下破解者已经达到和软件公司相同的地位,不但具有“正版”用户注册的能力,更是和软件公司一样具有发布、许可他人“正常”注册的能力(注意:这里指的是真正意义上的注册机,而不是CrackCode、KeyMaker等程序生成的“注册码截取器”)。
为什么要使用暴力破解?如果每个软件都能通过注册的方式破解岂不是更好,这样就不会存在“破解软件”不稳定的问题了?不错,谁都希望能够以注册的方式来破解软件,可是有很多原因会使得我们的期望落空,从而不得不借助于“暴力的手段”来达到自己的目的。通常情况下,程序的作者总会以各种各样的手段来保护自己,所谓要获得正确的注册信息并不容易,而暴力破解的好处在于我们可以不用去关心程序的具体加密算法程序或步骤,而只需要找到关键的比较指令代码出,改变程序的运行轨迹,使程序的验证机制失效,成为没有任何保护的“免费软件”。
那么,都有些什么样的情况使得我们必须通过暴力手段来破解:
一、每个人的破解技术、经验各不一样,所以必然有些软件的保护技术会超出自己的能力范围,无法获得正确的注册信息;
二、由于自己的时间、精力有现,虽然有把握获得注册信息,但是需要尽快结束战斗;
三、完全能够获得正确的注册信息,但是程序的注册信息最终需要通过网络在软件公司的服务器上进行验证;
四、原程序仅仅只是“试用版”而已,根本就没有提供任何注册的方式,若要继续使用必须先注册,然后才能获得可以永久使用的版本;
五、原程序通过硬件方式加密,比如加密狗、钥匙软盘等等,这种情况下因为无法“造出”所需之硬件,必须使用暴力破解;
六、你是破解初学者,使用暴力破解能够让自己快速体验破解的快感,借此作为踏向破解之门的跳板,哈哈。。。!^_^
说了这么多废话,也许你最关心的是如何进行暴力破解。首先我们需要对进行暴力破解的程序分类,一种是普通的程序,文件代码本身就是有效的可执行代码,没有经过任何形式的加密变换,对其用SOFTICE进行动态跟踪和用W32Dasm进行静态分析时看到的代码一样,这类程序的暴力破解使用打文件补丁的方式(手动,或者利用文件补丁工具(比如CodeFusion等)制作文件补丁程序;另外一种程序其文件代码并不是真正的可执行代码,而是进行了加密变换(如用“加壳”软件加密,或者程序对关键部分代码进行边执行边解密的方式),对其使用W32Dasm进行静态分析时看到的代码没有任何实际意义,全是垃圾,只能通过SOFTICE进行动态跟踪才能知道庐山真面目,对付这类程序可以有两种方法:一是打文件补丁,需要用到SMC技术,不过对于初学者或汇编不熟的人来说比较难;另外一种是打内存补丁,借助于专门的内存补丁软件(比如 R!SC's Process Patcher等),通过编写相应的脚本命令文件实现,这种方式运用较为简单,不过并不能保证一定有效,具体和内存补丁软件的实现技术有关系。
下面我们分别来介绍文件补丁和内存补丁两种暴力破解方式:
文件补丁方式暴破方法:
1、设置断点拦截需要修改的对象(比如消息框或对话框之类的),找到关键的比较跳转代码处(可以借助于W32Dasm来定位目标的位置);
2、假设跟踪程序发现以下的代码是关键之处:
:004025E0 8975F8 mov dword ptr [ebp-08], esi
:004025E3 897DFC mov dword ptr [ebp-04], edi <-- 假设这里往前压栈注册验证参数
:004025E6 FF1514E44300 Call dword ptr [0043E414] <-- 假设个CALL是注册码验证的关键处
:004025EC 6685C0 test ax, ax <-- 测试验证程序返回值AX
:004025EF 7507 jne 004025F8 <-- 判断注册码是否正确
:004025F1 68D8184400 push 004418D8
:004025F6 EB2B jmp 00402623
假设我们通过跟踪分析已经知道Call dword ptr [0043E414]是注册码的验证子程序,而jne 004025F8则根据验证程序返回值AX判断注册信息是否正确
3、分析修改方法
a.我们假设当返回值 AX=0 时表示注册码正确,那么我们就必须让程序绕过jne 004025F8继续走到push 004418D8而不论验证子程序返回值AX为多少,所以我们可以将jne 004025F8改成nop,这样程序肯定能走到push 004418D8,从来去到注册程序的地方,同时要注意,修改程序代码时必须保证修改前后的代码长度必须一样,否则整个程序就会乱掉。jne 004025F8的机器码是7507,而nop的机器码是90,为了保持代码长度的一致,我们可以使用两个nop来代替jne 004025F8,修改后的代码应该是下面的样子:
:004025E0 8975F8 mov dword ptr [ebp-08], esi
:004025E3 897DFC mov dword ptr [ebp-04], edi
:004025E6 FF1514E44300 Call dword ptr [0043E414]
:004025EC 6685C0 test ax, ax <-- 返回值 AX = 0 表示注册信息正确,所以必须让程序走到push 004418D8
:004025EF 90 nop <-- 用两个nop代替jne 004025F8
:004025F0 90 nop <-- 现在程序的注册信息判断已经失效,我们肯定能走到“成功之处”了!^_^
:004025F1 68D8184400 push 004418D8
:004025F6 EB2B jmp 00402623
b.我们假设当返回值 AX=0 时表示注册码不正确,那么我们必须让程序走到jne 004025F8去而不论验证子程序返回值AX为多少,这样的话我们可以有两种方法:一是将jne 004025F8改成je 004025F8,由于jne的机器码是75,je的机器码是74,所以只要将:004025EF处的7507改成7407即可;另外一种方法是将jne 004025F8改成jmp 004025F8,由于jne的机器码是75,它所对应的jmp指令的机器码是EB,所以只要将:004025EF处的7507改成EB07即可,将jne改成je的出发点是基于我们输入的注册信息肯定是不正确的,所以只需要将程序原来的注册检验逻辑判断取反即可,而将jne改成jmp则是百分之百的可靠,因为这样修改之后程序已经失去了判断的功能,无论输入正确或是错误的注册信息其结果都是一样,即按照我们希望的方向运行,这两种的修改方式结果分别如下所示:
:004025E0 8975F8 mov dword ptr [ebp-08], esi
:004025E3 897DFC mov dword ptr [ebp-04], edi
:004025E6 FF1514E44300 Call dword ptr [0043E414]
:004025EC 6685C0 test ax, ax
:004025EF 7407 je 004025F8 <-- 将jne 004025F8改成je 004025F8,注意机器码的前后变化
:004025F1 68D8184400 push 004418D8
:004025F6 EB2B jmp 00402623
:004025E0 8975F8 mov dword ptr [ebp-08], esi
:004025E3 897DFC mov dword ptr [ebp-04], edi
:004025E6 FF1514E44300 Call dword ptr [0043E414]
:004025EC 6685C0 test ax, ax
:004025EF EB07 jmp 004025F8 <-- 将jne 004025F8改成jmp 004025F8,注意机器码的前后变化
:004025F1 68D8184400 push 004418D8
:004025F6 EB2B jmp 00402623
4、知道了要如何修改程序代码,接下来就要开始动手用HIEW来修改程序了:首先运行HIEW,打开需要修改的程序文件,然后按F4,选择“DECODE”来到反汇编模式,这样我们就可以看到程序的汇编代码了;
5、接下来我们需要找到上面的代码在哪里?有两种方法:
一、直接搜寻程序的机器码,那么jne 004025F8的机器码是7507,是不是直接搜寻7507就可以了呢?-- 不行! 因为7507就两个字节而已,很可能程序的其它地方也有7507这两个字节,那样的话就不是我们需要的地方了。所以为了保证搜寻结果的唯一行,我们要将jne 004025F8前后的机器码一起作为整体来搜寻,这样就能准确找到jne 004025F8的位置了,在HIEW中按F7键,在弹出的搜寻框种输入需要查找的机器码“66 85 C0 75 07 68 D8 18 44 00 EB 2B”,然后按回车,HIEW将跳到这段机器码的位置,前后打量一下是否正确,如果正确则可以开始修改;
二、直接根据程序在文件中的偏移地址来找到它,一是可以使用W32Dasm反编译程序,然后用鼠标双击jne 004025F8所在的行,将光标移动到那里,此时在W32Dasm的底部可以看到这条语句在程序中的偏移量 “CODE DATA @004025EF @Offset 000025EF in File:程序名”,这里假设004025EF为jne 004025F8的代码地址,000025EF为jne 004025F8对应的文件偏移地址,得到这个偏移之后在HIEW中按F5,输入jne 004025F8的文件偏移25EF,然后回车,这样我们立马就可以来到jne 004025F8所在的地方;还有一种确定代码文件偏移的方法是利用专门的 代码地址<-->文件偏移 转换工具,其结果是一样的;
6、在HIEW中找到程序文件的jne 004025F8代码处之后,按F3进入编辑状态,此时就可以按我们的要求直接修改机器码了,比如要把jne 004025F8改成jmp 004025F8,只要将75改成EB即可,完成所有的修改之后按F9存盘,然后退出HIEW就OK了!
内存补丁方式暴破方法:
1、设置断点拦截需要修改的对象(比如消息框或对话框之类的),找到关键的比较跳转代码处(因为文件代码跟实际的可执行代码不一样,所以我们不能借助于W32Dasm来定位目标位置,除非先“脱壳”);
2、同样的,假设跟踪程序发现以下的代码是关键之处:
:004025E0 8975F8 mov dword ptr [ebp-08], esi
:004025E3 897DFC mov dword ptr [ebp-04], edi <-- 假设这里往前压栈注册验证参数
:004025E6 FF1514E44300 Call dword ptr [0043E414] <-- 假设个CALL是注册码验证的关键处
:004025EC 6685C0 test ax, ax <-- 测试验证程序返回值AX
:004025EF 7507 jne 004025F8 <-- 判断注册码是否正确
:004025F1 68D8184400 push 004418D8
:004025F6 EB2B jmp 00402623
3、分析修改方法:假设当返回值 AX=0 时表示注册码不正确,而我们希望将jne 004025F8改成jmp 004025F8,入如下所示:
:004025E0 8975F8 mov dword ptr [ebp-08], esi
:004025E3 897DFC mov dword ptr [ebp-04], edi
:004025E6 FF1514E44300 Call dword ptr [0043E414]
:004025EC 6685C0 test ax, ax
:004025EF EB07 jmp 004025F8 <-- 将jne 004025F8改成jmp 004025F8,注意机器码的前后变化
:004025F1 68D8184400 push 004418D8
:004025F6 EB2B jmp 00402623
4、对原程序的分析跟踪及解决方法都已确定,那么我们就可以开始编辑相应的脚本命令了,下面以R!SC's Process Patcher内存补丁软件为例,讲解它的脚本命令格式及使用方法:
R!SC's Process Patcher 脚本命令
";" 分号 ;所在行后面的内容为脚本注释 ,不会被解释执行。
"T=" 对内存的检测次数, T=1000: 表示对内存检测 1000 次,在放弃之前会提示应用程序不是正确的版本。
这个参数可以不用设置,脚本中的默认值为 T=8000:
'F=' 需要打补丁的应用程序文件名 。
'O=' 生成的补丁程序文件名 , 如果没有指定,其默认文件名为 O=LOADER.EXE:
'P=' 补丁信息 , 格式:代码地址 / 原代码 / 补丁码 :
'R:' 直到这条命令之前的补丁全部都做好之后再继续下面的命令。
'$' 脚本命令文件结束标志 。
':' 每一行脚本命令的结束标记
注意事项:只有当内存代码地址和机器码同时匹配的条件下才会打补丁;脚本文件命令不能大于40kb,
补丁码最多为75Eh个字节,打补丁的应用程序文件名必须小于30个字符。
脚本文件名后缀必须为RPP,即脚本命令文件名必须形如:*.rpp 的格式,可以在DOS下用“ rpp.exe ”制作补丁程序,也可以在WINDOWS中点击运行rpp.exe,然后选择脚本文件。
5、假设我们需要打补丁的程序名为text.exe,那么其对应的脚本文件script.rpp内容如下:
text.exe 对应的脚本命令文件script.rpp的内容
T=8000: 对内存的检测次数采用默认值 8000
F=text.exe: 需要打补丁的应用程序文件名为 text.exe
O=test_load.exe: 生成的补丁程序文件名为 test_load.exe
P=004025EF/75,EB: 补丁信息 , 将 jne ???????? 改成 jmp ????????
$ 脚本文件到此结束
6、运行rpp.exe,选择制作好的脚本文件script.rpp,然后得到内存补丁程序 test_load.exe;
7、将内存补丁程序 test_load.exe 拷贝到 text.exe 所在目录,然后运行 test_load.exe 即可!
提示:在Softice中如何查看指令机器码? -- 方法:使用 CODE ON / CODE OFF 命令来切换机器码的显示状态
关于暴力破解中所用到的汇编指令机器码知识:
我们在暴力破解中修改的对象基本上都是条件跳转指令(如 JZ、JNZ、JG。。。等等)和无条件跳转指令JMP,对于其它地方的修改多数都是改成NOP,所以这里主要讲一下跳转指令对应的机器码。在80X86体系的CPU中,成对条件跳转指令(指的是判断条件刚好相反)如下所示:
JZ <--> JNZ
JE <--> JNE
JB(JNAE) <--> JNB(JAE)
JC <--> JNC
JA(JNBE) <--> JNA(JBE)
JG(JNLE) <--> JNG(JLE)
JL(JNGE) <--> JNL(JGE)
JS <--> JNS
JP(JPE) <--> JNP(JPO)
JO <--> JNO
80X86体系CPU中的条件跳转指令分为单字节和双字节指令两种,分别对应8BIT和16BIT跳转;而与条件跳转指令相匹配的无条件跳转指令JMP也有单字节和双字节指令两种,分别对应8BIT和16BIT跳转,当我们需要将条件跳转指令改成相应的无条件跳转指令时,因为要保持修改前后机器码长度的一致性,所以要注意被修改的条件跳转指令是单字节还是双字节指令,从而用相应字节的JMP机器码来代替,下表列出了暴力破解中条件跳转指令的修改方法:
8位跳转指令修改方法
汇编指令 机器码 相反汇编指令 机器码 测试标志位 修改后的机器码 对应的汇编指令
JZ ????????
JE ???????? 74 XX JNZ ????????
JNE ???????? 75 XX Z = 0 或 1 EB XX JMP ????????
JB ????????
JNAE ???????? 72 XX JNB ????????
JAE ???????? 73 XX C = 0 或 1
JC ???????? 72 XX JNC ???????? 73 XX C = 0 或 1
JA ????????
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -