用户态完美实现"变速齿轮"
学习各种高级外挂制作技术,马上去百度搜索 "魔鬼作坊",点击第一个站进入,
快速成为做挂达人。
1>变速齿轮原理:
变速齿轮利用 HOOK API 实现针对 Windows 主流应用程序的变速功能,
QueryPerformanceCounter,
GetTickCount,
timeGetTime
3个 API 实现的完美加速。
(有些程序如<扫雷>是通过 timer计时的,Hook 这三个函数还不能实现加速)
为了实现变速效果,按键精灵作者采用公式算法实现了加速减速效果,公式如下:
Result := 上次返回时间 + Round((当前返回时间 - 上次正常时间) * Power(2,倍数));
根据这个分析, 所以我们写变速齿轮的思路就出来了:
挂钩这三个函数, 修改器返回值. 完成~
2>逆向这三个 Api:
1.1.1.1. GetTickCountGetTickCountGetTickCountGetTickCount
代码:
复制代码
1 mov edx,7FFE0000h
2 mov eax,dword ptr ds:[edx]
3 mul dword ptr ds:[edx+4]
4 shrd eax,edx,18h
5 retn
2.2.2.2. timeGetTimetimeGetTimetimeGetTimetimeGetTime
代码:
复制代码
6 cmp dword ptr ds:[76B30014],0
7 jnz GetTickCount
8 call Func_1
9 sub eax,dword ptr ds:[76B30018]
10 push 0
11 sbb edx,dword ptr ds:[76B3001C]
12 push 2710
13 push edx
14 push eax
15 call Func_2
16 add eax,dword ptr ds:[76B30020]
17 retn
18 Func_1:
19 mov edi,edi
20 mov edx,dword ptr ds:[7FFE000C]
21 mov eax,dword ptr ds:[7FFE0008]
22 cmp edx,dword ptr ds:[7FFE0010]
23 jnz short winmm.76B12B0B
24 retn
25 Func_2:
26 ;// 一堆废话,又臭又长...
27 ;// 从第一个"jnz GetTickCount"的跳转来看,
28 ;// 只要让 timeGetTime的返回值跟 GetTickCount一样即可~
3.3.3.3. QueryPerformanceCounterQueryPerformanceCounterQueryPerformanceCounterQueryPerformanceCounter
代码:
复制代码
29 mov edi,edi
30 push ebp
31 mov ebp,esp
32 push ecx
33 push ecx
34 lea eax,dword ptr ss:[ebp-8]
35 push eax
36 push dword ptr ss:[ebp+8]
37 call ntdll.ZwQueryPerformanceCounter ;// 看这个~
38 test eax,eax
39 jl 0xxxxxxxxx
40 cmp dword ptr ss:[ebp-8],0
41 je 0xxxxxxxxx
42 xor eax,eax
43 inc eax
44 leave
45 retn 4
46 ;// ntdll.ZwQueryPerformanceCounter:
47 ;// 这孙子直接进入内核了....
48 mov eax,0A5
49 mov edx,7FFE0300
50 call dword ptr ds:[edx]
51 retn 8
52 ;// 看 win源码知道, 这孙子进内核后又会调用
53 ;// "KeQueryPerformanceCounter"
54 ;// 而这个内核函数做的也只是查询下_KUSER_SHARED_DATA中的东西
3>挂钩实现:
开始动手Hook:(部分源码)
代码:
复制代码
55 //////////////////////////////////////////////////////////////////////////
56 // 1> GetTickCount 的 Hook
57 // 7C80934Akernel32.GetTi> BA 0000FE7F mov edx,7FFE0000
58 // 7C80934F 8B02 mov eax,dword ptr ds:[edx]
59 // 7C809351 F762 04 mul dword ptr ds:[edx+4]
60 // 7C809354 0FACD0 18 shrd eax,edx,18
61 // 7C809358 C3 retn
62 // Hook地址
63 DWORD HookAddr_GetTickCount = 0x7C809358;
64 DWORD dwSpead = 0;
65 DWORD dwTmp = 0;
66 DWORD dwStartTime = 0;
67 _declspec(naked) void HookFunc_GetTickCount()
68 {
69 //
初始时间.(回忆前面的变速齿轮公式...)
70 if (0 == dwStartTime)
71 {
72 __asmmov dwStartTime, eax
73 __asm retn;
74 }
75 __asm
76 {
77 mov ecx, eax ;//now time
78 sub ecx, dwStartTime //sub time
79 //shl ecx, 1
80 mov dwTmp, ecx
81 push eax
82 }
83 dwTmp *= dwSpead;//加速多少倍?
84 __asm
85 {
86 pop eax
87 mov ecx, dwTmp
88 add eax, ecx
89 retn
90 }
91 }
Ps: 实际上这个 Hook 是不是相当于改写了这个函数呢?
下面一个Hook 也类似~~
代码:
复制代码
92 //////////////////////////////////////////////////////////////////////////
93 // 2> timeGetTime
94 // 76B14E4F > 833D 1400B376 0>CMP DWORD PTR DS:[76B30014],0
95 // 76B14E56 0F85 97770000 JNZ
96 // 76B14E5C E8 A8DCFFFF CALL winmm.76B12B09
97 // 76B14E61 2B05 1800B376 SUB EAX,DWORD PTR DS:[76B30018]
98 // 76B14E67 6A00 PUSH 0
99 // 76B14E69 1B15 1C00B376 SBB EDX,DWORD PTR DS:[76B3001C]
100 // 76B14E6F 68 10270000 PUSH 2710
101 // 76B14E74 52 PUSH EDX
102 // 76B14E75 50 PUSH EAX
103 // 76B14E76 E8 07000000 CALL winmm.76B14E82
104 // 76B14E7B 0305 2000B376 ADD EAX,DWORD PTR DS:[76B30020]
105 // 76B14E81 C3 RETN
106 // Hook地址:
107 DWORD HookAddr_timeGetTime = 0x76B14E4F;
108 _declspec(naked) void HookFunc_timeGetTime()
109 {
110 __asm
111 {
112 mov edx, 0x7ffe0000
113 mov eax, dword ptr ds:[edx]
114 mul dword ptr ds:[edx+4]
115 shrd eax, edx, 0x18
116 }
117 // 记录初始时间.(回忆前面的变速齿轮公式...)
118 if(0 == dwStartTime)
119 {
120 __asmmov dwStartTime, eax
121 __asm retn;
122 }
123 __asm
124 {
125 mov ecx, eax
126 sub ecx, dwStartTime
127 mov dwTmp, ecx
128 push eax
129 }
130 // dwSpead加速倍数
131 dwTmp *= dwSpead;
132 __asm
133 {
134 pop eax
135 mov ecx, dwTmp
136 add eax, ecx
137 retn
138 }
139 }
下面最后一个Hook 了~
代码:
复制代码
140 //////////////////////////////////////////////////////////////////////////
141 // 3> QueryPerformanceCounter
142 typedef DWORD (__stdcall * pZwQueryPerformanceCounter)(DWORD, DWORD);
143 pZwQueryPerformanceCounter ZwQueryPerformanceCounter = NULL;
144 // 这个函数需要在挂钩之前调用一次,
145 // 以完成初始化: 找到 ZwQueryPerformanceCounter的地址...
146 void fuck_ZwQueryPerformanceCounter()
147 {
148 HMODULE hModule = LoadLibrary("ntdll.dll");
149 if (NULL == hModule)
150 {
151 //cout << ">load lib error!" << endl;
152 return;
153 }
154 void * p = GetProcAddress(hModule, "ZwQueryPerformanceCounter");
155 if (NULL == p)
156 {
157 //cout << ">get proc addr error!" << endl;
158 goto FUCK_END;
159 }
160 ZwQueryPerformanceCounter = (pZwQueryPerformanceCounter)p;
161 FUCK_END:
162 //FreeLibrary(hModule);
163 //hModule = NULL;
164 return;
165 }
166 // --- QueryPerformanceCounter ----
167 // 7C80A4C7 8BFF mov edi,edi
168 // 7C80A4C9 . 55 push ebp
169 // 7C80A4CA . 8BEC mov ebp,esp <--
170 // 7C80A4CC . 51 push ecx
171 // 7C80A4CD . 51 push ecx
172 // 7C80A4CE . 8D45 F8 lea eax,dword ptr ss:[ebp-8]
173 // 7C80A4D1 . 50 push
eax ; 接收一个返回
174 // 7C80A4D2 . FF75 08 push dword ptr
ss:[ebp+8] ; 入口参数地址
175 // 7C80A4D5 . FF15 DC13807C call dword ptr
ds:[<&ntdll.NtQueryPerformanceCounter>] ; ntdll.ZwQueryPerformanceCounter
176 // 7C80A4DB . 85C0 test eax,eax
177 // 7C80A4DD . 0F8C AB750300 jl
kernel32.7C841A8E ; 非零则跳
178 // 7C80A4E3 . 837D F8 00 cmp dword ptr ss:[ebp-8],0
179 // 7C80A4E7 . 0F84 AB750300 je kernel32.7C841A98
180 // 7C80A4ED > 33C0 xor eax,eax
181 // 7C80A4EF . 40 inc eax
182 // 7C80A4F0 > C9 leave
183 // 7C80A4F1 . C2 0400 retn 4
184 DWORD HookAddr_QueryPerformanceCounter = 0x7C80A4C7;
185 LARGE_INTEGER liStartTime = {0};
186 LARGE_INTEGER liTmp = {0};
187 LARGE_INTEGER *lpPerformanceCount = NULL;// QueryPerformanceCounter的形参...
188 __declspec(naked) BOOL __stdcall HookFunc_QueryPerformanceCounter()
189 {
190 __asm
191 {
192 mov edi, edi
193 push ebp
194 mov ebp, esp
195 push ecx
196 push ecx
197 lea eax, dword ptr [ebp-8]
198 push eax
199 push dword ptr [ebp+8] ;//形参
200 mov eax, ZwQueryPerformanceCounter
201 call eax
202 }
203 //初始化开始时间
204 if ((__int64)0 == *(__int64*)&liStartTime)
205 {
206 __asm
207 {
208 mov eax, dword ptr[ebp+8] //lpPerformanceCount
209 lea edx, liStartTime
210 mov ecx, dword ptr [eax]
211 mov dword ptr [edx], ecx
212 add eax, 4
213 add edx, 4
214 mov ecx, dword ptr [eax]
215 mov dword ptr [edx], ecx
216 // 返回程序
217 xor eax, eax
218 inc eax
219 leave
220 retn 4
221 }
222 }
223 ///// 修改查询回来的时间///////
224 __asmmov eax, dword ptr [ebp+8]//lpPerformanceCount
225 __asmmov lpPerformanceCount, eax
226 *(__int64*)&liTmp = *(__int64*)lpPerformanceCount - *(__int64*)&liStartTime;
227 *(__int64*)&liTmp *= __int64(dwSpead); // 加速倍数
228 *(__int64*)lpPerformanceCount += *(__int64*)&liTmp;
229 ////////////////////////////////
230 __asm
231 {
232 xor eax, eax
233 inc eax
234 leave
235 retn 4
236 }
237 }
Ps: 最后一个 Hook 貌似有点复杂....
其实不难~
也就是将 这个函数查询回来的系统时间改掉, 改成你需要的倍数~
难点在于 这个函数的返回值是个 __int64型的~~
大家要有比较熟练的C 或者汇编基础啊~
哈哈~ 或许还需要一些关于内存的知识~
涉及到一些公司的内部库, 源码我就不附上来了啊~
内核中的地址 0xffdf0000 对应的物理内存, 映射到每个进程中的地址是 0x7ffe0000;
实际上这个地址对应的是一个 _KUSER_SHARED_DATA结构:
[CODE]
nt!_KUSER_SHARED_DATA
+0x000 TickCountLow : Uint4B
+0x004 TickCountMultiplier : Uint4B
+0x008 InterruptTime : _KSYSTEM_TIME
... ...
[\CODE]
+0和+8处的两个结构 对实现变速齿轮有用.
因为三环下: timeGetTime, GetTickCount, QuerPerformanceCount,三个获取时间的函数,
实际上主要的功能是查询+0或者+8地方的值....(PS: 打开OD 自己看着三个函数的实现...)
(顺道多嘴, Hook 着三个函数就能实现一个三环下的变速齿轮当然,扫雷不能加速, 因为它
是用的定时器(timmer)计时~~~)
正题: 内核下,在虚拟机中调试, 看到的是由 KeUpdateSystemTime负责更新!_KUSER_SH
ARED_DATA
中的时间.(具体自己打开你的WinDbg + 看看win 源码).....
楼主说的方法类似于Hook KeUpdateSystemTime函数, 让其更新时间的时候 被我们乘机
修改??
我试了Hook这个函数更新系统时间的, 加速2倍, 结构受到的效果不是系统时间加速两倍,
而是系统时钟走得断断续续, 加速别的程序什么的也不成....
这个直接的, 仅仅的. 修改0xffdf0000的 方法, 应该是不能实现变速齿轮的....
楼主的变速齿轮, 下过来运行 直接蓝屏~ 应该是硬编码的挂钩地址吧?~
看了一下"守望者变速齿轮"的实现..
无奈能力有限, 只能看到其Hook 了 KeUpdateSystemTime,这个可以完整逆向偷学来....
但是其修改了 hal.dll 等的系统 dll..... 不好搞, 不知道怎么搞...
寻求实现变速齿轮 内核版 的方法 ing.....