“变速齿轮”研究手记

注意:如果你看了本文,对我们这个软件有兴趣,请到 [url]www.biansuchilun.net.cn[/url] 下载。
注:为节省篇幅,本文对一些计算机术语直接使用而没有作详细的解释,读者若有不熟悉之处,建议参考清华大学出版社出版,周明德编著的《微型计算机系统原理及应用》一书中关于 8253/8254 定时器和 x86 保护模式的相应章节。
也许是我孤陋寡闻吧,说出来不怕您笑话,对于“变速齿轮”这样著名的软件,我一直到五天前,也就是 2001 2 28 号才第一次听说。我有几个同学很喜欢玩图形 MUD ,整天见了面就在一起切磋“泥”技。我对 MUD 本身并没有多大兴趣,但是那天早上偶尔听他们说某个 MUD 站点明文规定严禁使用“齿轮”,这才好奇地问他们什么是“齿轮”。别人告诉我,“齿轮”是一个软件,能对 Windows 下的游戏加速类 游戏外挂 ,他们在玩 MUD 时就依靠这个软件作弊。这不禁令我一头雾水,能让 Windows 游戏改变速度,太神奇了!
我一贯对技术很有兴趣,听说有这么一个神奇的软件,当然要想想它是怎么实现的。这个软件看起来并不复杂,我原以为一个早自习好好琢磨琢磨就行,可是我想了好几节课,始终不得其要领。说来也巧,我们这学期有一面必修课是 Linux 内核原理分析,这几天正好学到了进程调度,老师说,当一个时钟中断发生的时候,操作系统要做很多事情,比如必要时要重新调度进程从而实现抢先式多任务,还要更新系统时钟 ...... 慢着,我突发奇想,如果让时钟中断产生的更快,会发生什么事情呢?
我们已经学过“微机原理”这门课程,我知道让时钟中断产生的更快不是难事,以前我就用 DOS 下的汇编语言写过这样的程序,这是我们当时的作业。可是我以前的程序在 Windows 下虽然可以运行,但并不能对 Windows系统加速 ,道理很显然: Windows9x 是使用 x86 虚拟机的机制来兼容 DOS 程序的,我的程序只能改变虚拟机,就是那个黑窗口的时钟中断。
于是我试图把以前的 DOS 程序搬到 32 位环境中。用 VC 内嵌汇编做这件事再合适不过了,在一个 VC 程序框架中加上一个 __asm ,然后只管把以前的汇编程序往里贴就行。我满怀希望地运行这样一个拼凑出来的怪物,结果,出现了一个大家都很熟悉的“该程序执行了非法操作”,我的试验以失败告终。
后来冷静下来仔细想想,这次失败的原因是显然的。 Windows 作为一个复杂的 32 位操作系统,如果能让你随便对硬件进行操作,那也许运行不了几个程序就崩溃了。但是如何绕过操作系统去操作硬件呢?我首先想到了 vxd ,编写一个驱动程序肯定可以操作硬件,但是,很可惜,我不会设计驱动程序。于是我想到了以前看到的 CIH 的源码, CIH 没有写 vxd ,却能操作硬件去烧毁 BIOS ,陈盈豪真是太伟大了,他的程序精巧之处我至今记忆犹新。于是我模仿他的技术,修改 IDT 表,创建一个中断门,然后发生中断,进入 ring0 ,现在我可以做任何事情了,按照以前的 DOS 程序那样,往 8253 定时器里写一个控制字,再分两次写入新的时钟中断发生频率,一切顺利!(详细技术请您参考我的“ 兄弟变速器 ”源码)我看到 VC 编辑区的光标疯狂的闪烁;双击已经失效了,因为 Windows 认为我双击的时间间隔太长; Windows 任务栏右方的时间飞快跳动,应该说,我已经成功了。
当时我想当然的以为“变速齿轮”的原理也是如此,可是当我从同学那里把“齿轮”拷来并研究时,发现 Windows 的时钟并不变快,而游戏速度照样可以加上去,也就是说,“齿轮”采用了与我的程序不同的技术,是什么技术呢?我决定继续研究。
我访问了“变速齿轮”的主页,这个主页上有一个“你问我答”的栏目,由“齿轮”的作者王荣先生进行技术支持。我试图在这里找到一些关于“齿轮”的技术细节,但是很可惜,没有找到,王荣先生只是告诉大家这个程序不能用 VB 编写等等根本连皮毛也不涉及的问题,好不容易见到一个外国人问能不能公布源代码,其实这也是我想问的,但是王荣先生明确表示不行,这不禁令我感到非常失望。
我也想过写信去索取原码,也许他不向外国人公布,中国人可不一定。但是咱们“臭老九”最爱一个面子,我实在拉不下脸去问。这时已经是晚上 10 点了,我决定祭出 SoftIce ,用一夜时间去研究他的程序。
当时使用的工具是 SoftIce WD32ASM VC ,手边两本参考书是《微型计算机系统原理及应用》和《 Linux 操作系统内核分析》(都是我们的课本,呵呵)。
起初,“变速齿轮” 0.2 版的一个叫 hook.dll 的文件很大程度上吸引了我的注意力,我怀疑他使用 Windows 消息钩子实现变速,消息钩子我很熟悉,但我把 MSDN 上面关于钩子的介绍看了好久,也没有想出它和变速有什么联系,这时偶然看了一下在王荣先生的主页上得到的“ 变速齿轮 0.1 版,才发现老版本中并没有这个文件,也就是说,我只需要反汇编他的主程序就够了,于是,二话不说,用 WD32ASM 先把 0.1 版的“齿轮”给拆了,汇编代码 5000 多行,并不算多。
我是从这个程序的导入函数着手的,以前编程时用于定时的 SetTimer timeGetTime timeSetEvent 等等这里都导入了,看看它们被引用的地方,我发现这些函数都是集中出现的,而且大都以这样的形式出现:
* Reference To: WINMM.timeGetTime, Ord:0098h
:00401F3E 8B0D64424000 mov ecx, dword ptr [00404264]
:00401F44 8B11 mov edx, dword ptr [ecx]
也就是说,他并没有调用这些函数,只是取得了函数的入口地址,保存在 ecx 中,然后又根据这个入口地址得到了函数的前面几个字节,保存在 edx 中。
这让我想到了前些日子在 CSDN 上面和别人讨论的 Hook API 的原理,当时我还索取了一份 Hook API 的例程,如果我要 Hook 这里的函数 timeGetTime ,修改 ecx 中的地址或者修改 edx 处的头几条指令就行,用汇编语言写,与上面看到的这段代码类似。
为了测试“齿轮”是不是要 Hook 这里的 timeGetTime ,我自己编写了一个很简单的小程序,调用 timeGetTime ,每秒钟显示一个数字。用“齿轮”进行加速后,果然显示的速度快多了。再用 SoftIce 跟进这个 timeGetTime 函数,第一条指令变成一个跳转,这充分说明“齿轮”确实 Hook 了这几个 API ,不难猜测,他要改变函数的返回值,也就是说在 timeGetTime 结束时还要再跳入“齿轮”自身的代码,耐心跟下去,我发现回到 timeGetTime 时栈里多压了一个地址,这样,当 timeGetTime ret 指令返回时,先返回“齿轮”的代码(这个思想确实很巧),返回值经过处理后,才跳回我的应用程序。至于怎么处理这个返回值就简单了,改到原先的 2 倍,应用程序速度也就提高了 2 倍。
回头再看 WD32ASM 反汇编的代码,我又发现在 Hook API 前面的不远处使用了一次 SGDT 指令和两次 SLDT 指令,这是 x86 保护方式的特有指令,用于获得全局描述符表,进一步得到局部描述符表,这段代码引起了我的兴趣,用 SoftIce 跟进去,往下走几步,一边跟一边猜,大致整理出了这样的思路:
1.
创建一个内存映射,把自己的代码映射到 0x80000000 以上的地方,在 Win9x 下,这块虚存是所有进程共享的。
2.
先得到局部描述符表的地址,然后利用这张表修改代码段的特权级。
3.
用局部描述符表创建一个调用门,在 x86 的保护模式下要进入 ring0 必须通过门来进行, CIH 是用中断门完成的,这里用调用门完成,异曲同工。
4.
保存几个关键函数前六个字节,改为一条跳转指令,跳到自己已经映射到高端的代码。
5.
发生函数调用时进入自己的代码,通过调用门进入 ring0 ,恢复函数开头的几个字节,修改返回值。
这时已经是凌晨 5 点了,既然主要思想已经掌握,我也就没有细看这段代码, 8 点钟还要上课,睡觉去也。
回头想想,我认为王荣先生的代码还有几点值得推敲之处:
1.
如果要 Hook API ,一定要改变函数的第一条指令吗?如果仅仅改变函数的入口地址,不是既容易编也容易调试吗?
2.
即使要改变函数第一条指令,一定要进入 ring0 吗?
3.
即使要进入 ring0 ,使用中断门不是比用调用门更方便吗?
当然,按照王荣先生在他的主页上的说法,“变速齿轮” 0.1 版是他在三年前即 1997 年写的,那时 Windows95 刚刚出来两年,能有这样的技术已经难能可贵了,这里对王荣先生的钻研精神表示由衷的敬佩。
在我研究出“变速齿轮”的原理后三天,我以自己原先的研究结果为核心,编写出了“兄弟变速器”的最初版本,不用“变速齿轮”的技术是因为我认为我的技术更优越,何况也没有拾人牙慧之嫌了 ^_^
最后再次对王荣先生表示感谢,这样精彩的创意值得我们敬佩。   

你可能感兴趣的:(职场,休闲,变速齿轮)