1>变速齿轮原理:变速齿轮利用HOOK API实现针对Windows主流应用程序的变速功能,
QueryPerformanceCounter,
GetTickCount,
timeGetTime
3个API实现的完美加速。 (有些程序如<扫雷>是通过timer计时的,Hook这三个函数还不能实现加速)
为了实现变速效果,按键精灵作者采用公式算法实现了加速减速效果,公式如下: Result := 上次返回时间 + Round((当前返回时间 - 上次正常时间) * Power(2,倍数)); [注:Round 表示取整] 原文:http://baike.baidu.com/view/384648.htm
根据这个分析, 所以我们写变速齿轮的思路就出来了: 挂钩这三个函数, 修改器返回值. 完成~
2>逆向这三个Api:
1. GetTickCount
代码:
mov edx,7FFE0000h mov eax,dword ptr ds:[edx] mul dword ptr ds:[edx+4] shrd eax,edx,18h retn
2. timeGetTime
代码:
cmp dword ptr ds:[76B30014],0 jnz GetTickCount call Func_1 sub eax,dword ptr ds:[76B30018] push 0 sbb edx,dword ptr ds:[76B3001C] push 2710 push edx push eax call Func_2 add eax,dword ptr ds:[76B30020] retn Func_1: mov edi,edi mov edx,dword ptr ds:[7FFE000C] mov eax,dword ptr ds:[7FFE0008] cmp edx,dword ptr ds:[7FFE0010] jnz short winmm.76B12B0B retn Func_2: ;// 一堆废话,又臭又长... ;// 从第一个"jnz GetTickCount"的跳转来看, ;// 只要让timeGetTime的返回值跟GetTickCount一样即可~
3. QueryPerformanceCounter
代码:
mov edi,edi push ebp mov ebp,esp push ecx push ecx lea eax,dword ptr ss:[ebp-8] push eax push dword ptr ss:[ebp+8] call ntdll.ZwQueryPerformanceCounter ;// 看这个~ test eax,eax jl 0xxxxxxxxx cmp dword ptr ss:[ebp-8],0 je 0xxxxxxxxx xor eax,eax inc eax leave retn 4 ;// ntdll.ZwQueryPerformanceCounter: ;// 这孙子直接进入内核了.... mov eax,0A5 mov edx,7FFE0300 call dword ptr ds:[edx] retn 8 ;// 看win源码知道, 这孙子进内核后又会调用 ;// "KeQueryPerformanceCounter" ;// 而这个内核函数做的也只是查询下_KUSER_SHARED_DATA中的东西
3>挂钩实现:开始动手Hook:(部分源码)
代码:
////////////////////////////////////////////////////////////////////////// // 1> GetTickCount 的Hook // 7C80934A kernel32.GetTi> BA 0000FE7F mov edx,7FFE0000 // 7C80934F 8B02 mov eax,dword ptr ds:[edx] // 7C809351 F762 04 mul dword ptr ds:[edx+4] // 7C809354 0FACD0 18 shrd eax,edx,18 // 7C809358 C3 retn // Hook地址 DWORD HookAddr_GetTickCount = 0x7C809358; DWORD dwSpead = 0; DWORD dwTmp = 0; DWORD dwStartTime = 0; _declspec(naked) void HookFunc_GetTickCount() { // 记录初始时间.(回忆前面的变速齿轮公式...) if (0 == dwStartTime) { __asm mov dwStartTime, eax __asm retn; } __asm { mov ecx, eax ;//now time sub ecx, dwStartTime //sub time //shl ecx, 1 mov dwTmp, ecx push eax } dwTmp *= dwSpead;//加速多少倍? __asm { pop eax mov ecx, dwTmp add eax, ecx retn } }
Ps: 实际上这个Hook是不是相当于改写了这个函数呢?
下面一个Hook也类似~~
代码:
////////////////////////////////////////////////////////////////////////// // 2> timeGetTime // 76B14E4F > 833D 1400B376 0>CMP DWORD PTR DS:[76B30014],0 // 76B14E56 0F85 97770000 JNZ // 76B14E5C E8 A8DCFFFF CALL winmm.76B12B09 // 76B14E61 2B05 1800B376 SUB EAX,DWORD PTR DS:[76B30018] // 76B14E67 6A 00 PUSH 0 // 76B14E69 1B15 1C00B376 SBB EDX,DWORD PTR DS:[76B3001C] // 76B14E6F 68 10270000 PUSH 2710 // 76B14E74 52 PUSH EDX // 76B14E75 50 PUSH EAX // 76B14E76 E8 07000000 CALL winmm.76B14E82 // 76B14E7B 0305 2000B376 ADD EAX,DWORD PTR DS:[76B30020] // 76B14E81 C3 RETN // Hook地址: DWORD HookAddr_timeGetTime = 0x76B14E4F; _declspec(naked) void HookFunc_timeGetTime() { __asm { mov edx, 0x7ffe0000 mov eax, dword ptr ds:[edx] mul dword ptr ds:[edx+4] shrd eax, edx, 0x18 } // 记录初始时间.(回忆前面的变速齿轮公式...) if(0 == dwStartTime) { __asm mov dwStartTime, eax __asm retn; } __asm { mov ecx, eax sub ecx, dwStartTime mov dwTmp, ecx push eax } // dwSpead加速倍数 dwTmp *= dwSpead; __asm { pop eax mov ecx, dwTmp add eax, ecx retn } }
下面最后一个Hook了~
代码:
////////////////////////////////////////////////////////////////////////// // 3> QueryPerformanceCounter typedef DWORD (__stdcall * pZwQueryPerformanceCounter)(DWORD, DWORD); pZwQueryPerformanceCounter ZwQueryPerformanceCounter = NULL; // 这个函数需要在挂钩之前调用一次, // 以完成初始化: 找到ZwQueryPerformanceCounter的地址... void fuck_ZwQueryPerformanceCounter() { HMODULE hModule = LoadLibrary("ntdll.dll"); if (NULL == hModule) { //cout << ">load lib error!" << endl; return; } void * p = GetProcAddress(hModule, "ZwQueryPerformanceCounter"); if (NULL == p) { //cout << ">get proc addr error!" << endl; goto FUCK_END; } ZwQueryPerformanceCounter = (pZwQueryPerformanceCounter)p; FUCK_END: //FreeLibrary(hModule); //hModule = NULL; return; } // --- QueryPerformanceCounter ---- // 7C80A4C7 8BFF mov edi,edi // 7C80A4C9 . 55 push ebp // 7C80A4CA . 8BEC mov ebp,esp <-- // 7C80A4CC . 51 push ecx // 7C80A4CD . 51 push ecx // 7C80A4CE . 8D45 F8 lea eax,dword ptr ss:[ebp-8] // 7C80A4D1 . 50 push eax ; 接收一个返回 // 7C80A4D2 . FF75 08 push dword ptr ss:[ebp+8] ; 入口参数地址 // 7C80A4D5 . FF15 DC13807C call dword ptr ds:[] ; ntdll.ZwQueryPerformanceCounter // 7C80A4DB . 85C0 test eax,eax // 7C80A4DD . 0F8C AB750300 jl kernel32.7C841A8E ; 非零则跳 // 7C80A4E3 . 837D F8 00 cmp dword ptr ss:[ebp-8],0 // 7C80A4E7 . 0F84 AB750300 je kernel32.7C841A98 // 7C80A4ED > 33C0 xor eax,eax // 7C80A4EF . 40 inc eax // 7C80A4F0 > C9 leave // 7C80A4F1 . C2 0400 retn 4 DWORD HookAddr_QueryPerformanceCounter = 0x7C80A4C7; LARGE_INTEGER liStartTime = {0}; LARGE_INTEGER liTmp = {0}; LARGE_INTEGER *lpPerformanceCount = NULL;// QueryPerformanceCounter的形参... __declspec(naked) BOOL __stdcall HookFunc_QueryPerformanceCounter() { __asm { mov edi, edi push ebp mov ebp, esp push ecx push ecx lea eax, dword ptr [ebp-8] push eax push dword ptr [ebp+8] ;//形参 mov eax, ZwQueryPerformanceCounter call eax } //初始化开始时间 if ((__int64)0 == *(__int64*)&liStartTime) { __asm { mov eax, dword ptr[ebp+8] //lpPerformanceCount lea edx, liStartTime mov ecx, dword ptr [eax] mov dword ptr [edx], ecx add eax, 4 add edx, 4 mov ecx, dword ptr [eax] mov dword ptr [edx], ecx // 返回程序 xor eax, eax inc eax leave retn 4 } } ///// 修改查询回来的时间/////// __asm mov eax, dword ptr [ebp+8]//lpPerformanceCount __asm mov lpPerformanceCount, eax *(__int64*)&liTmp = *(__int64*)lpPerformanceCount - *(__int64*)&liStartTime; *(__int64*)&liTmp *= __int64(dwSpead); // 加速倍数 *(__int64*)lpPerformanceCount += *(__int64*)&liTmp; //////////////////////////////// __asm { xor eax, eax inc eax leave retn 4 } }
Ps: 最后一个Hook貌似有点复杂.... 其实不难~ 也就是将 这个函数查询回来的系统时间改掉, 改成你需要的倍数~ 难点在于 这个函数的返回值是个 __int64型的~~ 大家要有比较熟练的C或者汇编基础啊~ 哈哈~ 或许还需要一些关于内存的知识~
收藏的用户(1) X
正在加载信息~
推荐阅读
最新回复 (0)
站点信息
- 文章2302
- 用户1336
- 访客10968998
每日一句
Qingming Festival invites us to honor ancestors with quiet reflection and respect.
清明节邀请我们以静思与敬意祭奠祖先。
清明节邀请我们以静思与敬意祭奠祖先。
新会员