实现Flash加速原理是Hook住与时间相关的几个API函数,将API返回的实际时间值进行改写,来实现加速。
模板依赖于mhook库(https://github.com/SirAnthony/mhook)
#pragma onceclass SpeedMgr
{
public:static SpeedMgr& Instance();BOOL StartService();BOOL StopService();BOOL SetSpeed(float fRate);BOOL Restore();// Inner callDWORD WINAPI GetTickCount(VOID);BOOL WINAPI QueryPerformanceFrequency(__out LARGE_INTEGER *lpFrequency);BOOL WINAPI QueryPerformanceCounter(__out LARGE_INTEGER *lpPerformanceCount);VOID WINAPI Sleep(__in DWORD dwMilliseconds);DWORD WINAPI timeGetTime(VOID);private:SpeedMgr(void);~SpeedMgr(void);private:// EnableBOOL bSpeed_;// GetTickCountDWORD gtcLastReal_;DWORD gtcLastFake_;base::TLock gtc_lock_;// timeGetTimeDWORD tgtLastReal_;DWORD tgtLastFake_;base::TLock tgt_lock_;// QueryPerformanceCounterLONGLONG qpcLastReal_;LONGLONG qpcLastFake_;base::TLock qpc_lock_;// QueryPerformanceFrequencyLONGLONG qpfLastReal_;LONGLONG qpfLastFake_;base::TLock qpf_lock_;// Speed Factorfloat speedFactor_;
};
cpp实现
#include "StdAfx.h"
#include "SpeedMgr.h"
#include "mhook.h"
#include <tchar.h>
#include <math.h>// kernel32.dll
typedef DWORD (WINAPI *pfn_GetTickCount)(VOID);
typedef BOOL (WINAPI *pfn_QueryPerformanceFrequency)(__out LARGE_INTEGER *lpFrequency);
typedef BOOL (WINAPI *pfn_QueryPerformanceCounter)(__out LARGE_INTEGER *lpPerformanceCount);
typedef VOID (WINAPI *pfn_Sleep)(__in DWORD dwMilliseconds);
// winmm.dll
typedef DWORD (WINAPI *pfn_timeGetTime)(VOID);// Real Functions
namespace SpeedAid
{// kernel32.dllpfn_GetTickCount Real_GetTickCount = NULL;pfn_QueryPerformanceFrequency Real_QueryPerformanceFrequency = NULL;pfn_QueryPerformanceCounter Real_QueryPerformanceCounter = NULL;pfn_Sleep Real_Sleep = NULL;// winmm.dllpfn_timeGetTime Real_timeGetTime = NULL;
}// Hook Functions
// kernel32.dll
DWORD WINAPI Hook_GetTickCount(VOID)
{return SpeedMgr::Instance().GetTickCount();
}BOOL WINAPI Hook_QueryPerformanceFrequency(__out LARGE_INTEGER *lpFrequency)
{return SpeedMgr::Instance().QueryPerformanceFrequency(lpFrequency);
}BOOL WINAPI Hook_QueryPerformanceCounter(__out LARGE_INTEGER *lpPerformanceCount)
{return SpeedMgr::Instance().QueryPerformanceCounter(lpPerformanceCount);
}VOID WINAPI Hook_Sleep(__in DWORD dwMilliseconds)
{return SpeedMgr::Instance().Sleep(dwMilliseconds);
}// winmm.dll
DWORD WINAPI Hook_timeGetTime(VOID)
{return SpeedMgr::Instance().timeGetTime();
}SpeedMgr::SpeedMgr(void): speedFactor_(1), bSpeed_(FALSE), gtcLastReal_(0), gtcLastFake_(0), tgtLastReal_(0), tgtLastFake_(0), qpcLastReal_(0), qpcLastFake_(0), qpfLastReal_(0), qpfLastFake_(0)
{HMODULE hMod = ::GetModuleHandle(_T("kernel32.dll"));SpeedAid::Real_GetTickCount = (pfn_GetTickCount) ::GetProcAddress(hMod, "GetTickCount");SpeedAid::Real_QueryPerformanceFrequency= (pfn_QueryPerformanceFrequency) ::GetProcAddress(hMod, "QueryPerformanceFrequency");SpeedAid::Real_QueryPerformanceCounter = (pfn_QueryPerformanceCounter) ::GetProcAddress(hMod, "QueryPerformanceCounter");SpeedAid::Real_Sleep = (pfn_Sleep) ::GetProcAddress(hMod, "Sleep");hMod = LoadLibrary(_T("winmm.dll"));SpeedAid::Real_timeGetTime = (pfn_timeGetTime) ::GetProcAddress(hMod, "timeGetTime");
}SpeedMgr::~SpeedMgr(void)
{StopService();
}SpeedMgr& SpeedMgr::Instance()
{static SpeedMgr instance;return instance;
}BOOL SpeedMgr::StartService()
{BOOL ret = TRUE;ret = Mhook_SetHook((PVOID*)&SpeedAid::Real_GetTickCount, Hook_GetTickCount);ret = Mhook_SetHook((PVOID*)&SpeedAid::Real_QueryPerformanceFrequency, Hook_QueryPerformanceFrequency);ret = Mhook_SetHook((PVOID*)&SpeedAid::Real_QueryPerformanceCounter, Hook_QueryPerformanceCounter);ret = Mhook_SetHook((PVOID*)&SpeedAid::Real_Sleep, Hook_Sleep);ret = Mhook_SetHook((PVOID*)&SpeedAid::Real_timeGetTime, Hook_timeGetTime);// 初始化值gtcLastReal_ = gtcLastFake_ = SpeedAid::Real_GetTickCount();tgtLastReal_ = tgtLastFake_ = SpeedAid::Real_timeGetTime();LARGE_INTEGER f;SpeedAid::Real_QueryPerformanceFrequency(&f);qpfLastReal_ = qpfLastFake_ = f.QuadPart;LARGE_INTEGER t;SpeedAid::Real_QueryPerformanceCounter(&t);qpcLastReal_ = qpcLastFake_ = t.QuadPart;return ret;
}BOOL SpeedMgr::StopService()
{BOOL ret = TRUE;ret = Mhook_Unhook ((PVOID*)&Hook_GetTickCount);ret = Mhook_Unhook ((PVOID*)&Hook_QueryPerformanceCounter);ret = Mhook_Unhook ((PVOID*)&Hook_QueryPerformanceFrequency);ret = Mhook_Unhook ((PVOID*)&Hook_Sleep);ret = Mhook_Unhook ((PVOID*)&Hook_timeGetTime);return ret;
}BOOL SpeedMgr::SetSpeed(float fRate)
{bSpeed_ = TRUE;speedFactor_ = fRate;return TRUE;
}BOOL SpeedMgr::Restore()
{bSpeed_ = FALSE;speedFactor_ = 1;return TRUE;
}// Inner call
DWORD WINAPI SpeedMgr::GetTickCount(VOID)
{DWORD ret = SpeedAid::Real_GetTickCount();DWORD nReal = ret;DWORD dReal = nReal - gtcLastReal_;DWORD dFake = speedFactor_ * dReal;gtcLastFake_ = gtcLastFake_ + dFake;gtcLastReal_ = nReal;return bSpeed_ ? gtcLastFake_ : gtcLastReal_;
}BOOL WINAPI SpeedMgr::QueryPerformanceFrequency(__out LARGE_INTEGER *lpFrequency)
{BOOL ret = SpeedAid::Real_QueryPerformanceFrequency(lpFrequency);LONGLONG nReal = lpFrequency->QuadPart;LONGLONG dReal = nReal - qpfLastReal_;LONGLONG dFake = speedFactor_ * dReal;qpfLastFake_ = qpfLastFake_ + dFake;qpfLastReal_ = nReal;if (bSpeed_)lpFrequency->QuadPart = qpfLastFake_;return ret;
}BOOL WINAPI SpeedMgr::QueryPerformanceCounter(__out LARGE_INTEGER *lpPerformanceCount)
{BOOL ret = SpeedAid::Real_QueryPerformanceCounter(lpPerformanceCount);LONGLONG nReal = lpPerformanceCount->QuadPart;LONGLONG dReal = nReal - qpcLastReal_;LONGLONG dFake = speedFactor_ * dReal;qpcLastFake_ = qpcLastFake_ + dFake;qpcLastReal_ = nReal;if (bSpeed_)lpPerformanceCount->QuadPart = qpcLastFake_;return ret;
}VOID WINAPI SpeedMgr::Sleep(__in DWORD dwMilliseconds)
{if (bSpeed_){DWORD dwValue = dwMilliseconds;dwMilliseconds = static_cast<DWORD> (floor(dwValue / speedFactor_ + 0.5));DWORD dwMinValue = 1;if (dwMilliseconds < dwMinValue){if (dwValue < dwMinValue)dwMilliseconds = dwValue;elsedwMilliseconds = dwMinValue;}}return SpeedAid::Real_Sleep(dwMilliseconds);
}DWORD WINAPI SpeedMgr::timeGetTime(VOID)
{DWORD ret = SpeedAid::Real_timeGetTime();DWORD nReal = ret;DWORD dReal = nReal - tgtLastReal_;DWORD dFake = speedFactor_ * dReal;tgtLastFake_ = tgtLastFake_ + dFake;tgtLastReal_ = nReal;return bSpeed_ ? tgtLastFake_ : tgtLastReal_;
}