关于 WinRAR 的介绍在这里就不多说了。其早前推出了专门面向国内用户的“免费版本”,但每次开启时,弹出的大幅广告挺影响使用体验的。没办法,不愿意花钱买正版,也不想每次打开时都被讨厌的广告烦一次,就自己想办法解决它。
0x0 准备
首先在 WinRAR 中国官网下载其简体中文个人版并进行安装。在这里我下载的是 WinRAR 32位版。其64位版同理可破。需要准备的工具有:
- PCHunter:用于获取窗口句柄和类名。
- WinDbg:用于获取调用地址。
- IDA:用于寻找调用函数。
- Hex Editor Neo:用于修改文件硬编码
这几个工具都可以根据自己的喜好,使用其他能够实现同类功能的软件代替。
本破解过程简述:借助广告对话框的窗口类名对窗口创建函数 CreateWindowExW 下断点,根据其堆栈找到调用语句的下一指令的地址即原 EIP,通过该地址回溯到调用语句所在函数,将该函数首地址修改为 retn 8 直接返回。
0x1 开始
打开 WinRAR,会在主窗口弹出之后创建一个非模态的展示网页的对话框。这个对话框并非采用 DirectUI 等界面库构造,那么获取其类名和句柄等信息应该是比较容易的。现在别关闭对话框,打开 PCHunter,在进程列表中找到 WinRAR.exe 项,右键,查看...,进程窗口。
在弹出的“进程窗口”对话框的列表中,根据“窗口标题”找到这个广告对话框的窗口项,得知其窗口类名为:RarReminder。接下来根据这个类名,在 WinDbg 中定位该窗口的创建。
0x2 调试
关闭之打开的 WinRAR 进程,关闭 PCHunter。打开 WinDbg,用其打开 WinRAR.exe 程序创建新的进程,并记录 WinRAR.exe 模块加载基地址。在 Windows 操作系统中,应用程序创建对话框通常使用 CreateWindowExW 函数,所以接下来使用下面的命令对 CreateWindowExW 创建条件断点:
bp USER32!CreateWindowExW "r $t1=poi(esp+8); as /mu $FileName $t1; .block{ .if ($spat(\"${$FileName}\",\"Rar*\")) {.echo found the pattern; .echo '$FileName'; ad ${/v:$FileName} } .else { .echo not found the pattern; .echo '$FileName'; ad ${/v:$FileName}; gc;} }"
关于这个条件断点的详细解释,参见文后的「0x6 备注」一节。
然后按五次 F5(不同 WinRAR 版本次数可能略有不同)键,直到在寄存器状态信息的前面看到“RarReminder”字样,使用 kv 命令查看堆栈状态,堆栈中最上面的条目是调用 CreateWindowExW 时压栈的下一指令的绝对偏移地址(EIP)。根据截图可知该地址为:0x013fa897,将其减去 WinRAR.exe 模块基地址 01360000,再加上 0x400000,得到 0x49a897。
0x3 定位
在 IDA 中定位到该地址,这个地址是 CreateWindowExW 下一条执行的指令。
向上查找,定位到 CreateWindowExW 所在的函数首地址,得知其所在函数为:sub_49A4E0。定位到 sub_49A4E0 函数返回的位置,其返回指令为 retn 8。
猜测该函数只执行了构建广告对话框的功能,那么只需要在函数首地址的位置执行 retn 8,就可以实现广告屏蔽的目的。根据这个猜想,先通过内存热补丁的形式测试一下。
0x4 测试
Windbg 有实现内存热补丁的命令:a [address]。打开新的 WinDbg 进程挂载 WinRAR.exe 程序,记录 WinRAR.exe 的模块加载基地址:0x01270000。
使用 a 命令修改 0x1270000 + 0x9a4e0 地址(即 sub_49A4E0 在当前进程中的绝对偏移地址首地址)的数据为 retn 8 指令,然后直接 F5 键执行,广告对话框并未弹出,修改成功。
0x5 破解
现在得到的结论是:只要直接对 sub_49A4E0 进行返回,就可以实现屏蔽广告的目的。那么现在要修改 PE 文件中的 sub_49A4E0 函数首地址为 retn 8 指令。计算文件偏移:
FileOffset = VA - ImageBase - VRk = 0049A4E0 - 00400000 - C00 = 998E0
通过 Hex Editor Neo 打开 WinRAR.exe 文件定位到 0x998E0 绝对偏移位置,从该地址开始修改 3 字节数据:C2 08 00 ,保存文件。
接下来运行 WinRAR.exe 程序,广告对话框已不再弹出,破解过程到此已成功。
0x6 备注
首先根据 CreateWindowEx 函数的参数解释,得知其第二个参数 LPCTSTR lpClassName 是窗口类名字符串,根据前面获得的广告对话框窗口类名:“RarReminder”,在这里通过“Rar*”对所有调用的 CreateWindowExW 的第二个参数进行模式匹配,在命中条件的位置中断,即可快速找到我们想要定位的位置。
HWND WINAPI CreateWindowEx(
_In_ DWORD dwExStyle,
_In_opt_ LPCTSTR lpClassName,
_In_opt_ LPCTSTR lpWindowName,
_In_ DWORD dwStyle,
_In_ int x,
_In_ int y,
_In_ int nWidth,
_In_ int nHeight,
_In_opt_ HWND hWndParent,
_In_opt_ HMENU hMenu,
_In_opt_ HINSTANCE hInstance,
_In_opt_ LPVOID lpParam
);
在「0x2 调试」一节中用到的条件断点,将其用分行的形式写出来更明了一些:
bp USER32!CreateWindowExW "
r $t1=poi(esp+8);
as /mu $FileName $t1;
.block {
.if ($spat(\"${$FileName}\",\"Rar*\")) {
.echo found the pattern;
.echo '$FileName';
ad ${/v:$FileName}
} .else {
.echo not found the pattern;
.echo '$FileName';
ad ${/v:$FileName};
gc;
}
} "
- r $t1=poi(esp+8)
poi(esp+8) 取地址的值,并赋给伪寄存器 $t1;
- as /mu $FileName $t1
定义 $t1 所指地址一个别名 $FileName,用来在下面的 $spat 中使用,别名会在脚本加载时被解析程序替换一次;
- .block {}
语句块,当进入每个语句块时,所有块中的别名都被重新计算;
- $spat(\"${$FileName}","Rar*")
$spat 是模式匹配函数,通过参数2的通配符规则在参数1中进行匹配,匹配成功则返回 TRUE;
- ad ${/v:$FileName}
删除别名,用 /v 选项阻止对该别名的替换, 保留它原来的字面值;
关于 WinDbg 条件断点的用法和解释,参见文章:http://blog.csdn.net/killcpp/article/details/7666071
最后再提醒一句:盗版有风险,破解需谨慎!在这里讲的这个方法,只作为对相关技术的学习使用,请勿使用在商业用途……
最后的最后,请支持正版:http://www.winrar.com.cn/download.htm
- THE END -
那这个破解是不是要更新一次,重新再来一遍?
是啊 :razz: