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 
 正在加载信息~
 推荐阅读
 Qualcomm HS-USB QDLoader 9008救砖教程 
           最新回复 (0) 
 站点信息
 -  文章2313
-  用户1336
-  访客11754078
 每日一句 
 October ends with magic and candy. 
十月以魔法和糖果收尾。
 十月以魔法和糖果收尾。
新会员
  
 























