使用 IDA 破解程序自校验
概述
本文记录破解 CCProxy 自校验的过程。背景是,公司配备了两台电脑,一台办公机可访问外网,一台开发机只能访问内网,这两台电脑网络上是通的。所以在办公机上建网络代理,让开发机去使用,这样开发机就可以访问外网了。 为后续称呼方便,称提供代理服务的办公机为 S,使用代理服务的开发机为 C。
问题记录
开发机无外网
设置 C 上的网络代理信息为:S 的局域网 IP 和开启代理的端口。但 C 仍无外网访问。经过排查,发现 C 的 request 到达了 S ,但是 S 没有回包。因此我们可以猜测到是因为 S 没有收到外网的 response 因此也就暂时没有给 C response。为什么 S 不能访问外网呢?突然想到,S 浏览器上设置过公司的网络代理服务器。所以直接把 S 的代理服务器信息设置到 S 的 CCProxy 上。试验成功,S 收到了 response 并且把这个 response 给到了 C。代理成功。这个概念就是多级代理。
CCProxy破解
公司的网络策略本来就是禁止开发机 C 访问外网的。后面公司通过流量监控,发现 S 上名为 "CCProxy" 的进程流量很大,而这个进程名一看就知道是干啥的,所以被警告了。而有时我们的开发机 C 上确实需要访问外网,比如代码编辑器更新插件,下载文件什么的。所以萌生了将 CCProxy 这个程序改名躲避监控运行的想法。 然而将 CCProxy.exe 改名为 firefox.exe 后,发现进程启动不了,没有任何错误信息。这就很奇怪了。一一尝试 CCProxy 安装目录下的配置,mui 文件,均不得解决。于是,我们猜测,是不是 CCProxy.exe 程序中对“本文件”的文件名进行了校验? 这个想法很容易验证:直接使用 exe 编辑器,将 CCProxy.exe 文件中的字符串 "CCProxy" 替换为 firefox。确实可以打开了!(下图展示的是可以将 firefox 替换回 CCProxy, 使用一个名为“软件手术刀的程序”,网上可下载)
然而事情并没有结束,虽然成功运行替换文件名之后的 firefox.exe,但是程序无法代理,因为此时程序的流量监控里面没有请求进来。我们去看它的运行日志,打开后看到有这样的报错:CheckEXE Failed。 那说明程序中不仅校验了程序名字,还使用了其它的校验。我们需要借助更高级的工具,可能需要修改程序的逻辑。如下图所示,我们使用逆向工具 IDA 打开 firefox.exe,并且搜索字符串 CheckEXE Failed:
搜到了!最后两行表示这个字符串有两处定义,开始两行表示这个字符串有两处引用的地方。双击引用的地方,在汇编代码中可以看到 IDA 解析出来的字符串:
对于不熟悉汇编的我,汇编太难看了,还是看图直接:直接按“空格健”进入图表模式,果然好看多了,如下三张图:
图中的红绿线分别表示失败,成功的分支,蓝色线表示不用分支直接往后执行。
我们重点需要看 CheckEXE Failed 往上走,分支的地方,(这是因为,只有在前面校验失败时,才会引用到这个字符串。)我们不断往上看,直到 loc_14007AE24 这个子过程,它调用了 GetModuleFileNameW 函数和 MapFileAndCheckSumW 函数,前面一个函数是用来获得当前进程的文件名,后一个看名字就感觉是进行校验的。
通过查询 MSDN 可知, MapFileAndCheckSumW 是编译器提供的一种手段,用于保护程序不被修改。方式是:开发人员通过设置,告诉编译器需要此支持。那么编译器在编译链接完成后,会生成一个 checksum 放于输出文件(程序文件)某个地方,程序自己可以调用 MapFileAndCheckSumW 函数进行校验。 因此,我们大致可以断定,CCProxy 就是使用了这个手法来完成自校验的。因此,我们可以在上面那个关键过程的上面一个子过程 loc_14007AE24 调用完成后,让它走最右边的绿色分支,则跳过那些校验。 我们直接修改 loc_14007AE24 这个子过程的最后一句代码 jge loc_14007B162。 为了完成修改,我们将鼠标指针放到那一句代码,再转到 HEX 浏览视图,可以定位到相应的机器码 0F 8D 02 03 00 00。
这个页面 比较友好地给出了汇编到机器码的转换。
0F 8D 代表的汇编指令即是 JGE,我们需要将它反转,即:0F 8C。 更改并保存后,启动 firefox.exe 即可正常代理了。 再附上另外一个好资源,可以试着去读懂机器代码:读懂简单的机器代码