0%

软件破解

Windows 程序的调试与破解

OD脱壳方法

单步跟踪法

脱壳的方法有很多,先来讲脱壳方法中最基础的单步跟踪法。单步跟踪法就是利用OD的单条指令执行功能,从壳的入口一直执行到OEP,最终通过这个OEP将原程序dump出来。然当,在单步跟踪的时候需要跳过一些不能执行到的指令。 使用单步跟踪法追踪OEP的常见步骤:

  1. 用OD载入待脱壳文件,如果出现压缩提示,选择“不分析代码”;
  2. 向下单步跟踪,实现向下的跳转;
  3. 遇到程序往上跳转的时候(包括循环),在回跳的下一句代码上单击并按键盘上的“F4”键跳过回跳指令;
  4. OD中的绿色线条表示跳转没有实理,不必理会,红色线条表示跳转已经实现;
  5. 如果刚载入程序的时候,在附近有一个CALL指令,那么就要按键盘上的“F7”键跟进这个CALL内,不然程序很容易运行起来;
  6. 在跟踪的时候,如果执行某个CALL指令后就运行,一定要按键盘上的“F7”键进入这个CALL之内再单步跟踪;
  7. 遇到在popad指令下的远转移指令时,要格处注意,因为这个远转移指令的目的地很可能就是OEP。

ESP定律法

ESP定律法是脱壳的利器,是国外友人发现的。有了ESP定律,可以方便我们脱掉大多数的压缩壳。可谓是本世纪破解界中最伟大的发现之一。这里只简单的看一下狭义ESP定律的原理。 使用ESP定律追踪OEP的常见步骤:

  1. 将待脱壳程序载入到OD中,开始就按键盘上的“F8”键单步跟踪一步,这时如果看到OD右边的寄存器窗口中的ESP寄存器的值有没有变为红色,如果发现ESP寄存器的值变为红色,执行第2步;
  2. 在OD的命令行窗口中执行命令hrXXXXXXXX,xxxxxxxx就是变为红色的ESP寄存器的值,在输入命令之后,一定不要忘记按键盘上的回车键;
  3. 按键盘上的“F9”键让程序运行起来;
  4. 使用单步跟踪的方法跟踪到OEP即可。

二次断点法

二次断点是有技巧的下两个断点,在两个断点之后就可以很轻松的找到OEP。 使用二次断点法追踪OEP的常见步骤:

  1. 将待脱壳程序载入到OD中,单击OD的“选项”菜单下的“调试设置”命令,在弹出的“调试选项”对话框中切换到“异常”选项卡,勾选该选项卡下的所有复选框,也就是忽略所有异常;
  2. 按键盘上的“ALT+M”组合键打开OD的内存窗口;
  3. 在OD的内存窗口中找到“.rsrc”区段,单击该区段后按键盘上的“F2”键在该区段上下一断点;
  4. 按“Shift+F9”让程序运行到断点心处,而后再次打开OD的内存窗口,这次在“.rsrc”区段上面的“.code”区段(有的时候就是“.text”)上下一个断点;
  5. 按“shift+F9”让程序运行到第二次下的断点处,然后单步跟踪既可以来到OEP。

末次异常法

在脱壳方法中,末次异常法又被称为最后一次异常法,这是最基础的脱壳技术之一。末次异常法脱壳很是简单,但就是这简单的脱壳方法可以挑掉曾经风靡一时的强壳。 使用末次异常法追踪OEP的常见步骤:

  1. 将待脱壳程序载入到OD中,单击OD的“选项”菜单,在弹出的菜单中单击“调试设置”命令,在随后弹出的“调试选项”对话框中切换到“异常”选项卡,清除该选项卡下所有复选框,也就是不忽略任何异常;
  2. 连续按键盘上的“Shift+F9”组合键让程序运行起来,记录按键的次数X;
  3. 回到OD中,按键盘上的“Ctrl+F2”组合键重新载入程序,按X-1次“Shift+F9”组合键;
  4. 在OD右下角窗口中找到“SE句柄”或是“SE处理程序”,记录此处的内存地址;
  5. 在OD的反汇编窗口中跟随到上一步记录下的内存地址,并在此内存地址处下一个断点;
  6. 按键盘上的“Shift+F9”组合键让程序运行到上一步下的断点处,按键盘上的“F2”键取消此处的断点;
  7. 使用单步跟踪法追踪到OEP。

模拟跟踪法

在这章中讲到的众多脱壳方法中,我们首先讲了单步跟踪法脱壳,因为单步跟踪脱壳法是脱壳技术中最基础的方法,在后面其它的一些脱壳方法中总会或多或少的配合单步跟踪法才能顺利完成脱壳工作。便是始终是一次次的按“F8”键来单步跟踪程序,偶尔遇到回跳就跳过执行,这样机械性的操作很是烦人,那么能不能让机器来代替人力,让工具帮我们单步跟踪呢?答案是肯定的,这也就是这节讲的内容——模拟跟踪法。模拟脱壳法就是模拟单步跟踪来进行查找OEP。 模拟跟踪法的常见步骤:

  1. 将待脱壳程序载入OD中,先简单的跟踪一下程序,看看有没有SEH暗桩;
  2. 按键盘上的“ALT+F9”打开OD的内存窗口,找到“SFX,输入表,资源”的行,并记录此行的内存地址;
  3. 在OD的命令行窗口执行命令“tc eip<上一步中记录下的地址”,命令执行后就会跟踪到OEP。

SFX自动脱壳法

在上一节,我们使用模拟跟踪法代替手动单步跟踪法进行脱壳。在OD中,不但可以利用模拟跟踪来代替单步跟踪进行脱壳,从而节省劳动力,还有一种SFX自动脱壳的方法也可以节省劳动力,并能快速有效的将程序的壳脱掉。 使用SFX自动脱壳法脱壳的常见步骤:

  1. 将OD设置为忽略所有异常;
  2. 在OD的“调试选项”对话框的“SFX”选项卡中选择“字节模式跟踪实际入口”选项并确定;
  3. 将待脱壳程序载入OD,待程序载入完成后,会直接停在OEP处。

出口标志法

前面几个脱壳方法中有一个共同点,就是在单步跟踪到popad指令后面不远处的jmp指令的时候,就可以大胆的判断这个jmp指令的目的地址就是OEP。原因很简单,popad指令用于将壳运行之前保存的环境恢复,使原程序能正常运行。有些壳的popad指令很少,我们就可以查看被这种壳加壳的程序的所有popad指令,找到后面存在jmp指令的popad指令,然后来到其后的jmp指令的目的地址,这很可能就是OEP,然后就可以进行dump脱壳了。 使用出口标志法脱壳的常见步骤:

  1. 将待脱壳程序载入OD中,在OD的反汇编客人口中单击鼠标右键,在弹出的右键菜单中单击“查找”→“所有命令”,在弹出的输入框中输入“popad”并按“查找”按钮;

  2. 逐一尝试跟踪查找到的所有“popad”指令,最终达到程序的OEP


PECompact高版本-特征码定位法

  1. 下断点bp VirtualFree,中断后取消断点,alt+F9返回程序代码段
  2. ctrl+f 查找push 8000(特征码),下断点
  3. shift+f9 在断点处停止,取消断点
  4. 单步跟踪到OEP

特殊断点

超级断点

原理:在widows 最基础的模块 user32 处下断点,这样就可以做到,你做出任何动作都会发生中断。

  1. 鼠标右键->查看->user32 进入代码段
  2. Ctrl+b 查找 F3 A5 8B C8 83 E1 03 F3 A4 E8,在这里下断点。
  3. shift+f9 返回用户代码
  4. 单步跟踪,观察堆栈及寄存器内容有无特殊字符串

配置文件断点

原理: 在程序读取配置文件的代码段上下断点,来中断程序运行。

  1. 在悬浮窗上有个BP选项卡,点击查看
  2. 找到BP GetPrivateProfileStringA,点击即可下断点
  3. 单步跟踪,观察堆栈及寄存器内容有无特殊字符串

VB专属断点

原理:VB有自己特有的系统调用,所以在系统调用上下断点就可以中断程序。

  1. 在悬浮窗上找到VB选项卡,点击查看
  2. 常用的是 BP rtcMsgBox,消息窗口

软件破解

干掉烦人的窗口

原理:找到系统调用,返回程序领空,通过修改条件跳转实现不弹出窗口的目的。

  1. 运行,窗口弹出后点击暂停键,跳转到窗口弹出的代码段
  2. 点击k 显示调用堆栈,找到本提示窗的调用堆栈,显式调用
  3. 不要nop掉窗口信息,应该找到决定这串信息的关键跳转,向下走
  4. 单步步过,经过return,找回自己的代码段,找出关键跳转
  5. 干掉关键跳转

有壳程序破解

原理:使用内存补丁,在不修改程序结构的前提下实现修改进程内存

  1. 添加程序
  2. 添加补丁地址
  3. 填写原来的机器码
  4. 替换为新的机器码
  5. 点击添加
  6. 点击生成即可

易语言特征

子窗口头尾

Assembly
1
2
3
4
5
6
7
;头部
004010F3 /. 55 push ebp
004010F4 |. 8BEC mov ebp,esp
;尾部
0040115E |. 8BE5 mov esp,ebp
00401160 |. 5D pop ebp
00401161 \. C3 retn

信息框

信息框从mov ebx,0x6开始,到add esp,0x34结束

Assembly
1
2
3
4
5
6
7
8
9
10
11
12
0040104B  |.  BB 06000000   mov ebx,0x6
00401050 |. E8 AFFFFFFF call 弹窗整合.00401004
00401055 |. 68 01030080 push 0x80000301
0040105A |. 6A 00 push 0x0
0040105C |. 68 00000000 push 0x0
00401061 |. 68 04000080 push 0x80000004
00401066 |. 6A 00 push 0x0
00401068 |. 68 ACE64700 push 弹窗整合.0047E6AC ; ASCII "这是一个信息框"
0040106D |. 68 04000000 push 0x4
00401072 |. BB 80124000 mov ebx,弹窗整合.00401280
00401077 |. E8 C3000000 call 弹窗整合.0040113F
0040107C |. 83C4 34 add esp,0x34

窗口

窗口从push 0x80000002开始,到add esp,0x28结束

Assembly
1
2
3
4
5
6
7
8
9
10
11
12
13
0040107F   |.  68 02000080   push 0x80000002
00401084 |. 6A 00 push 0x0
00401086 |. 68 01000000 push 0x1
0040108B |. 68 01000100 push 0x10001
00401090 |. 68 00000106 push 0x6010000
00401095 |. 68 01000152 push 0x52010001
0040109A |. 68 01000100 push 0x10001
0040109F |. 68 0B000106 push 0x601000B
004010A4 |. 68 0C000152 push 0x5201000C
004010A9 |. 68 03000000 push 0x3
004010AE |. BB C0114000 mov ebx,弹窗整合.004011C0
004010B3 |. E8 F7000000 call 弹窗整合.004011AF
004010B8 |. 83C4 28 add esp,0x28

子程序结束

Assembly
1
2
3
004010EF   |.  8BE5          mov esp,ebp
004010F1 |. 5D pop ebp
004010F2 \. C3 retn

注意

粘贴二进制的时候,可能会产生一些错误,例如call后面的地址会发生变化,这样的话,有必要先对原来的窗口信息以文本方式复制下来,在二进制粘贴完之后,进行手动校对。


易语言程序破解

pushd窗体法

  1. ctrl+g跳转到00401000
  2. ctrl+b查找二进制字串 勾选整个块FF 25
  3. 看到一堆的jmp 确定是易语言程序
  4. 在jmp上面的push 0520*窗体就是启动窗体,就是程序进入的第一个窗体
  5. 循环查找所有窗体
    1. 查找命令 勾选整个块 push 10001
    2. 看到push 0520*就是一个窗体
  6. 替换启动窗体

拖放控件的破解

  1. ctrl+B搜索FF 55 FC 5F 5E,这是拖放控件特征码
  2. 下断点,拖放程序
  3. 进入拖放控件的call
  4. 向下运行查找关键call

替换窗体

  1. Ctrl+B搜索FF 25找到易语言特有的一串jump
  2. 向上查找你想替换的窗口与目标窗口
  3. 复制你想复制的窗口在两个mov ebp,esp之间
  4. 复制到剪切板,二进制复制,同时粘贴到记事本里
  5. 找到目标窗口,在第一个mov ebp,esp之后,选择一段区域,可以多选但是不能少选,否则指令地址不够填充
  6. 粘贴到目标窗口的选区,修改call 窗口名称的汇编指令,因为在二进制粘贴时会产生一些错误。这时参考粘贴在记事本中的结构就可以了。
  7. 使用收尾指令二进制指令8B E5 5D C3,粘贴在窗体的结束指令add esp,0x28后面
  8. 复制所有更改到文件即可

替换文字

  1. 先找到字符串常量存储的位置
  2. 向下查找没有使用过的空间,修改成你想变成的字符串
  3. 然后在搜索到的ASCII码处修改你的字符串的位置
  4. ARM Assembly 00401147 |. 68 12F94700 push 弹窗整合.0047F912 ; ASCII "呵呵呵"
  5. 0047F912就是数据地址,修改地址到你的数据的地址即可

游戏破解

HOOK技术

HOOK的用处

  • 挂钩代码,实现直接读取数值
  • 修改数据,不执行某代码
  • 过检测,修改代码

作用方式

  1. 直接修改
  2. 间接修改
    1. 找到空白区域写入自己想要执行的数据
    2. 在原地址上执行跳转指令
    3. 在空白区域自己的指令上写入retn返回到原来的代码区域
  3. 直接读取

修改思路

  1. 当无法直接找到某代码的位置时,要先思考该代码会给游戏带来的影响
  2. 例如你被敌人打到了,你会扣血,你可以在现有血量的位置看,找出时什么访问了这个地址
  3. 当你找到访问血量数量的地址的时候,你就可以找到血量存储的位置
  4. 在数据窗口中跟随,下一个内存写入的断点,当再次触发扣血指令时,就会中断
  5. 点击k,显示调用堆栈,就可以看到有多少地方写入了这里
  6. 排除不是控制血量的代码

就可以找出扣血代码

恰饭,恰饭