问题: “变速齿轮”再研究 (转贴)(含源代码) ( 积分: 1 )
分类: 系统相关
来自: Bahl, 时间: 2002-08-16 10:29:00, ID: 1268252
“变速齿轮”再研究
提起“变速齿轮”(以下简称“齿轮”)这个软件,大家应该都知道吧,该软件号称
是全球第一款能改变游戏速度的程序。我起初用时觉得很神奇,久而久之就不禁思考其实现原理了,但苦于个人水平有限,始终不得其解,成了长驻于脑中挥散不去的大问号。
偶然一天在BBS上看到了一篇名为《“变速齿轮”研究手记》(以下简称《手记》)的文章,我如获至宝,耐着性子把文章看完了,但之后还是有很多地方不解,不过还是有了比较模糊的认识:原来齿轮是通过截获游戏程序对时间相关函数的调用并修改返回结果实现的呀。
为了彻彻底底地弄清齿轮的原理,我这次打算豁出去了。考虑到《手记》的作者从是研究的“齿轮”的反汇编代码的,那我也照样从反汇编代码开始。不过自认为汇编功底不够,又从图书馆借了几本关于Windows底层机制和386汇编的书,在经过差不多两周的“修行”之后,自我感觉有点好啦,哈哈,我也有点要迫不及待地把“齿轮”大卸八块了!
在动手之前,我又把《手记》看了一遍,这次可就清楚多了:通过调用门跳到Ring0级代码段,修改各系统时间相关函数的前8个字节为jmp指令,转跳到“齿轮”映射到2G之上的代码,达到截获对各系统时间相关函数的调用的目的。但同时我的疑惑也更明确了:
1.“齿轮”怎样建立指向自己映射到2G以上内存的代码的调用门描述符的;
2.“齿轮”怎样将自己的代码映射到2G以上线性地址的;
3.映射到2G之上的代码是怎样做到在代码基址更改的情况仍能正确运行的
带着这样的疑问,我正式开始了对“齿轮”反汇编代码的分析。工具嘛,不用说当
然是Softice for Windows98、W32Dasm,OK,出发啦!
我的“齿轮”版本是0.221 for win98和winme的,内含有两个文件(变速齿轮.exe
和Hook.dll)。先看看Hook.dll里面有些什么,用W32Dasm将Hook.dll反汇编,看看它的输出函数:
?ghWnd@@3PAUHWND__@@A
?gnHotKey1@@3KA
?gnHotKey2@@3KA
?gnHotKey3@@3KA
?gnHotKey4@@3KA
?nHook@@3HA
?SetHook@@YAHPAUHWND__@@@Z
?UnHook@@YAHXZ
看函数名好象该dll只是安装钩子捕获变速热键的,与我的研究目的没太大的关系, 跳过去!
再看看变速齿轮.exe的导入函数,timeGetTim、GetTickCount等时间相关的函数都
在里面。嘿,还有CreateFileMappingA和MapViewOfFileEx,看来“齿轮”是用这两个函
数创建映射文件的。以下列出几个关键的导入函数:
Hook.?gnHotKey1@@3KA
Hook.?gnHotKey2@@3KA
Hook.?gnHotKey3@@3KA
Hook.?gnHotKey4@@3KA
Hook.?SetHook@@YAHPAUHWND__@@@Z
KERNEL32.CreateFileMappingA
KERNEL32.GetModuleFileNameA
KERNEL32.GetModuleHandleA
KERNEL32.GetTickCount
KERNEL32.MapViewOfFileEx
KERNEL32.QueryPerformanceCounte
USER32.KillTimer
USER32.SendMessageA
USER32.SetTimer
WINMM.timeGetTime
WINMM.timeSetEvent
既然“齿轮”截获了timeGetTime,那我就跟踪timeGetTime函数的执行情况。
我先写了个Win32 APP (以下简称APP),当左击客户区时会调用timeGetTime并将返回的结果输出至客户区。运行这个程序,打开“齿轮”,改变当前速度。
Ctrl + D 呼出Softice,bpx timeGetTime ,退出,再左击APP客户区,Softice跳出。哈,果然timeGetTime函数的首指令成了jmp 8xxx 002A ,好F8继续执行,进入了“ 齿轮”映射到2G线性地址之上的代码。一路F8下去,发现接着“齿轮”把timeGetTime 首指令恢复,并再次调用timeGetTime,这样就得到了timeGetTime的正确结果,保存结果。“齿轮”再把timeGetTime首指令又改为jmp 8xxx 002A 。接下来都猜得到“齿轮”要干什么了!没错,将得到的返回值修改后返回至调用timeGetTime的程序APP。
我仔细分析了一下,“齿轮”修改返回值的公式如下:
倍数*(返回值-第一次调用timeGetTime的返回值)
修改后的返回值=---------------------------------------------------+上一次修改后的返回值
100000
公式中“上次修改后的返回值”是自己猜测的未经证实,仅供参考。
代码分析已经进行一部分了,可我之前的疑问仍未解决,“齿轮”是怎么将代码映
射的?又是怎么得到修改代码的权限的?
既然“齿轮”中调用了CreateFileMappingA,我想其安装调用门,映射代码的初始化部分应该就在调用该函数代码的附近。好,沿着这个思路,呼出Softice,在CreateF ileMappingA处设置断点,将“齿轮”关闭后再运行。Softice跳出,停在了CreateFile MappingA处,F11回到“齿轮”的代码。看到了“齿轮”调用CreateFileMappingA的形式如下:
CreateFileMappingA(FF,0,4,0,10000,0);
可见
来自: Bahl, 时间: 2002-08-16 10:30:00, ID: 1268257
由此可见,变速齿轮是通过拦截TimeGetTimeAPI函数,修改该函数的返回值实现的。拦截该API函数大家已经会了,但是如何修改TimeGetTime的返回值呢?
可能要用到汇编。诸位有什么办法?
来自: wsn, 时间: 2002-08-16 10:31:00, ID: 1268260
顶一下
来自: flb_delphibbs, 时间: 2002-08-17 8:03:00, ID: 1270195
强烈关注!!
学习一下。
来自: Bahl, 时间: 2002-08-18 11:48:00, ID: 1272010
变速齿轮源代码:
// File name : SetClock.cpp
// Function1 : SetClock9x(int)
// Function2 : SetClockNT(int)
// Chu Rui 2001.3.1
#include "stdafx.h"
#include "ntport.h"
#define FREE_INT_NO 5
void Ring0()
{ //在Windows9x下进入ring0后进行的操作
__asm
{
cli
mov al,34h
out 43h,al //写入8253控制寄存器,设置写0号定时器
mov ax,bx
out 40h,al //写定时值低位
mov al,ah
out 40h,al //写定时值高位
sti
iretd;
}
}
void SetClockNT(int freq)
{ //NT下的操作
//这里使用了NT Port库
Outport(0x43,0x34); //写入8253控制寄存器,设置写0号定时器
Outport(0x40,freq&0xff); //写定时值低位
Outport(0x40,(freq>>8)&0xff); //写定时值高位
}
void SetClock9x(int freq)
{
union Function_Pointer
{
void (*pointer)();
char bytes[sizeof(void *)];
}OldIntAddress,NewIntAddress;
int IDTAddress; //IDT表基地址
int IDTItemAddress; //要修改的中断门所在地址
char *Pointer; //要修改的中断门所在地址,指针形式
__asm
{
push eax
sidt [esp-2]
pop eax
mov IDTAddress,eax //得到IDT表基地址
}
IDTItemAddress=FREE_INT_NO*8+IDTAddress;
Pointer=(char *)IDTItemAddress;
NewIntAddress.pointer=Ring0;
OldIntAddress.bytes[0]=Pointer[0];
OldIntAddress.bytes[1]=Pointer[1];
OldIntAddress.bytes[2]=Pointer[6];
OldIntAddress.bytes[3]=Pointer[7]; //保存旧的中断门
Pointer[0]=NewIntAddress.bytes[0];
Pointer[1]=NewIntAddress.bytes[1];
Pointer[6]=NewIntAddress.bytes[2];
Pointer[7]=NewIntAddress.bytes[3]; //设置新的中断门
__asm
{
mov ebx,freq
int FREE_INT_NO //产生中断,进入ring0
}
Pointer[0]=OldIntAddress.bytes[0];
Pointer[1]=OldIntAddress.bytes[1];
Pointer[6]=OldIntAddress.bytes[2];
Pointer[7]=OldIntAddress.bytes[3]; //恢复旧的中断门
}
来自: vecm, 时间: 2002-08-18 18:38:00, ID: 1272485
好,学习学习!
感谢Bahl[
]
来自: 热血, 时间: 2002-08-18 20:09:00, ID: 1272604
现在变带齿轮有两种方法
一是改系统时间api
二是改时钟中断
第二种方法不好,因为加速的时候把windows的钟也加快了
一般第一种好点.
一般就是截几个api,然后修改返回值
来自: Bahl, 时间: 2002-08-18 21:17:00, ID: 1272723
>>一般就是截几个api,然后修改返回值
要拦截TimeGetTimeAPI函数,怎么修改它的返回值呢?[
][
][?][?]
来自: 热血, 时间: 2002-08-18 23:19:00, ID: 1272875
例如:
DWORD MyGetTickCount(void)
{
dwRetCode = OrnGetTickCount();
dwRetCode ++;
return dwRetCode;
}
来自: samboy111, 时间: 2002-08-19 1:16:00, ID: 1272966
高手啊,厉害!
来自: Writer, 时间: 2002-08-19 3:03:00, ID: 1273005
高手的文章,虽然看不懂,但也收藏先。[
][
][8D]
来自: Bahl, 时间: 2002-08-19 9:43:00, ID: 1273227
To 热血:
你的方法好象不行,游戏速度没有加快。
来自: 热血, 时间: 2002-08-21 21:08:00, ID: 1279220
首先所有与时间的api都要接拦下来的,光一个timeGetTime是没有用的
我做过的程序一共截了如下几个timeGetTime,GetTickCount,
GetMessageTime,QueryPerformanceCounter,timeSetEvent,SetTimer
另外要保证游戏进程的api已经被拦下.最后就是返回值要修改的准确.
来自: chi8, 时间: 2002-08-22 8:34:00, ID: 1279700
学习![
]
来自: Bahl, 时间: 2002-08-22 12:28:00, ID: 1280265
To 热血:
能把你的源代码贴出来给大家看看吗?
来自: creation-zy, 时间: 2002-08-22 12:33:00, ID: 1280275
dwRetCode=dwRetCode<<2; 可以加快吗?
游戏中使用GetTickCount之类的API的目的无非是:当前时间=>OldTime,循环并判断
NowTime-OldTime是否达到指定值。因此,单纯进行加减操作是无效的,因为在比较的过程
中会抵消,一定要进行乘除运算。
来自: 刘松ls, 时间: 2002-08-22 12:49:00, ID: 1280315
看不懂
来自: 热血, 时间: 2002-08-22 13:40:00, ID: 1280442
源码不能贴的
上面加减只是一个例子
实际上是 / *才行
来自: 星际浪人, 时间: 2002-08-22 13:41:00, ID: 1280446
我没有见过那个游戏,不过按照推测,应该是拦截 Windows 系统中所有与时间相关的 API 函数了。
来自: itren, 时间: 2002-08-22 14:29:00, ID: 1280593
关注
似乎就象Ms proxy Client 的实现 微软自己加入了一个拦截 在发送数据直接发送到服务器
然后..服务器返回后 客户端直接送给请求的application,于是丝毫没有痕迹 就象自己在
网上一样!
所以如果这些东西微软自己做的话 轻而易举 但微软自己不做 也不会给别人机会做。
你自己要做就很麻烦了!。。。。
唉!
来自: baifeng, 时间: 2002-08-22 16:33:00, ID: 1280941
g z
来自: beta, 时间: 2002-08-29 22:44:00, ID: 1295604
我觉得截获 GetTickCount 没什么用,你会用他来计时吗?
应该截获其他的时间函数。
来自: 白河愁, 时间: 2002-11-24 12:18:00, ID: 1455242
有必要这么麻烦吗?
来自: Bahl, 时间: 2002-11-25 7:16:00, ID: 1456467
白河愁兄,你有什么好办法吗?
来自: ljy_17, 时间: 2002-11-25 17:17:00, ID: 1458528
gZ!
来自: leezero, 时间: 2002-11-25 17:57:00, ID: 1458699
学习
来自: LovingTse, 时间: 2003-02-13 20:03:00, ID: 1620579
to Bahl
老大,你那是兄弟齿轮,不是变速齿轮,那会连Windows的速度一起改变的
我这也有啊,还有已经编译好的dll文件呢
来自: 我爱黄黄, 时间: 2003-04-11 14:46:00, ID: 1759587
[
]UP!
来自: ypy, 时间: 2004-02-10 11:26:00, ID: 2444843
如何拦截SetTimer 产生的定时器??
来自: jfyes, 时间: 2005-03-01 11:01:18, ID: 3000851
收藏
问题讨论没有结束 ...