关于 WinRAR 的介绍在这里就不多说了。其早前推出了专门面向国内用户的“免费版本”,但每次开启时,弹出的大幅广告挺影响使用体验的。没办法,不愿意花钱买正版,也不想每次打开时都被讨厌的广告烦一次,就自己想办法解决它。

0x0 准备

首先在 WinRAR 中国官网下载其简体中文个人版并进行安装。在这里我下载的是 WinRAR 32位版。其64位版同理可破。需要准备的工具有:

  1. PCHunter:用于获取窗口句柄和类名。
  2. WinDbg:用于获取调用地址。
  3. IDA:用于寻找调用函数。
  4. 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;
  } 
} "
  1. r $t1=poi(esp+8)

poi(esp+8) 取地址的值,并赋给伪寄存器 $t1;

  1. as /mu $FileName $t1

定义 $t1 所指地址一个别名 $FileName,用来在下面的 $spat 中使用,别名会在脚本加载时被解析程序替换一次;

  1. .block {}

语句块,当进入每个语句块时,所有块中的别名都被重新计算;

  1. $spat(\"${$FileName}","Rar*")

$spat 是模式匹配函数,通过参数2的通配符规则在参数1中进行匹配,匹配成功则返回 TRUE;

  1. ad ${/v:$FileName}

删除别名,用 /v 选项阻止对该别名的替换, 保留它原来的字面值;

关于 WinDbg 条件断点的用法和解释,参见文章:http://blog.csdn.net/killcpp/article/details/7666071

最后再提醒一句:盗版有风险,破解需谨慎!在这里讲的这个方法,只作为对相关技术的学习使用,请勿使用在商业用途……

最后的最后,请支持正版:http://www.winrar.com.cn/download.htm

- THE END -

文章链接: https://xiaodaozhi.com/analysis/13.html