A forum for reverse engineering, OS internals and malware analysis 

Forum for discussion about kernel-mode development.
 #26029  by pboy0922
 Tue Jun 09, 2015 5:00 am
Hi,everyone
I want to make some software(game etc) run faster,so I hook KeUpdateSystemTime and KeQueryPerformanceCounter.
Then the effect of speed up is OK, and the system time is also speed up.
Now I want to make the system time normal while other software speed up,how can I get it? :D
^_^
 #26032  by pboy0922
 Tue Jun 09, 2015 9:27 am
hi TETYYSs,I know the method you said,it running ring3 and must inject shellcode or dll into someone process to hook QueryPerformanceCounter.Now I need a ring0 driver to do it and must make system time be normal.I know some software had implement this function,like the attachment file :D
Attachments
qianfeng_speeder
(3.09 MiB) Downloaded 31 times
 #26035  by pboy0922
 Tue Jun 09, 2015 11:41 am
TETYYSs wrote:You don't. Hook QueryPerformanceCounter inside process to do that. Kernel mode is global.
hi TETYYSs,I know the method you said,it running ring3 and must inject shellcode or dll into someone process to hook QueryPerformanceCounter.Now I need a ring0 driver to do it and must make system time be normal.I know some software had implement this function,like the attachment file :D
 #26039  by pboy0922
 Tue Jun 09, 2015 3:29 pm
myid wrote:Talk is cheap. Show me the code.
hi,my Key Code is
[syntax="c"]
#pragma pack(push) //保存对齐状态
#pragma pack(1)//设定为1字节对齐

typedef struct _JmpStub
{
unsigned char jmp;
unsigned long *offset;
}JmpStub,*PJmpStub;

typedef struct _FakeKeUpdateSystemTime
{
unsigned short mul;
unsigned long *speedx;
unsigned short div;
unsigned long *speedbase;
JmpStub jmpStub;
}FakeKeUpdateSystemTime,*PFakeKeUpdateSystemTime;

typedef struct _OriginalFunction
{
unsigned char OriginalHead[12];//存储函数的头几个字节,默认为nop
JmpStub jmpStub;
}OriginalFunction,*POriginalFunction;
#pragma pack(pop)//恢复对齐状态


ULONG g_uSpeedX = 600;
ULONG g_uSpeedBase = 100;

ULONG g_uHookOffsetKeUpdateSystemTime = 0;//内联hook函数KeUpdateSystemTime的字节数
BOOLEAN g_bHookKeUpdateSystemTime = FALSE;
LPVOID g_lpfnKeUpdateSystemTime = NULL;
PFakeKeUpdateSystemTime g_FakeKeUpdateSystemTime = NULL;
POriginalFunction g_OriginalKeUpdateSystemTime = NULL;

ULONG g_uHookOffsetKeQueryPerformanceCounter = 0;//内联hook函数KeQueryPerformanceCounter的字节数
BOOLEAN g_bHookKeQueryPerformanceCounter = FALSE;
//LPVOID g_lpfnKeQueryPerformanceCounter = NULL;
POriginalFunction g_OriginalKeQueryPerformanceCounter = NULL;
LARGE_INTEGER g_liPreOriginalCounter;// 前一个查询到的性能指标数
LARGE_INTEGER g_liPreReturnCounter;// 变化后的性能指标数值


NTSTATUS HookKeyFunctions()
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
status = HookKeUpdateSystemTime();
if(!NT_SUCCESS(status)) return status;
status = HookKeQueryPerformanceCounter();
return status;
}

NTSTATUS HookKeUpdateSystemTime()
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PFakeKeUpdateSystemTime lpFake = NULL;
POriginalFunction lpOriginal = NULL;
JmpStub jmpStub = {0};
KIRQL Irql;
GetHookOffset();
if(!g_bHookKeUpdateSystemTime)
{
g_lpfnKeUpdateSystemTime = GetFuncAddress(L"KeUpdateSystemTime");
if(!g_lpfnKeUpdateSystemTime) return status;

lpOriginal = (POriginalFunction)ExAllocatePoolWithTag(NonPagedPool,sizeof(OriginalFunction),XSPEED_ORIGINAL_FUNCTION_TAG);
if(!lpOriginal) return status;
RtlFillMemory(lpOriginal,sizeof(OriginalFunction),0x90);
RtlCopyMemory(lpOriginal->OriginalHead,g_lpfnKeUpdateSystemTime,g_uHookOffsetKeUpdateSystemTime);
lpOriginal->jmpStub.jmp = 0xe9;
lpOriginal->jmpStub.offset = (unsigned long *)((unsigned char *)g_lpfnKeUpdateSystemTime + g_uHookOffsetKeUpdateSystemTime - (unsigned char *)(lpOriginal+1));

lpFake = (PFakeKeUpdateSystemTime)ExAllocatePoolWithTag(NonPagedPool,sizeof(FakeKeUpdateSystemTime),XSPEED_FAKE_UPDATE_TAG);
if(!lpFake) return status;
RtlZeroMemory(lpFake,sizeof(FakeKeUpdateSystemTime));
lpFake->mul = 0x25f7; //mul g_uSpeedX
lpFake->speedx = &g_uSpeedX;
lpFake->div = 0x35f7;//div g_uSpeedBase
lpFake->speedbase = &g_uSpeedBase;
lpFake->jmpStub.jmp = 0xe9;//jmp
lpFake->jmpStub.offset = (unsigned long *)((unsigned char *)lpOriginal - (unsigned char *)(lpFake+1));//

jmpStub.jmp = 0xe9;
jmpStub.offset = (unsigned long *)((unsigned char *)lpFake - (unsigned char *)g_lpfnKeUpdateSystemTime - sizeof(JmpStub));//

PageProtectOff();
Irql = KeRaiseIrqlToDpcLevel();
RtlCopyMemory(g_lpfnKeUpdateSystemTime,&jmpStub,sizeof(JmpStub));
KeLowerIrql( Irql );
PageProtectOn();

g_FakeKeUpdateSystemTime = lpFake;
g_OriginalKeUpdateSystemTime = lpOriginal;
g_bHookKeUpdateSystemTime = TRUE;

status = STATUS_SUCCESS;
}

return status;
}

NTSTATUS HookKeQueryPerformanceCounter()
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
POriginalFunction lpOriginal = NULL;
JmpStub jmpStub = {0};
KIRQL Irql = 0;
unsigned char *lpKeQueryPerformanceCounter = (unsigned char *)KeQueryPerformanceCounter;

if(!g_bHookKeQueryPerformanceCounter)
{
// 初始化数值
g_liPreOriginalCounter.QuadPart = 0;
g_liPreReturnCounter.QuadPart = 0;

// 首次查询
g_liPreOriginalCounter = KeQueryPerformanceCounter( NULL );
g_liPreReturnCounter.QuadPart = g_liPreOriginalCounter.QuadPart;

lpOriginal = (POriginalFunction)ExAllocatePoolWithTag(NonPagedPool,sizeof(OriginalFunction),XSPEED_ORIGINAL_FUNCTION_TAG);
if(!lpOriginal) return status;
RtlFillMemory(lpOriginal,sizeof(OriginalFunction),0x90);
RtlCopyMemory(lpOriginal->OriginalHead,KeQueryPerformanceCounter,g_uHookOffsetKeQueryPerformanceCounter);
lpOriginal->jmpStub.jmp = 0xe9;
lpOriginal->jmpStub.offset = (unsigned long *)((unsigned char *)KeQueryPerformanceCounter + g_uHookOffsetKeQueryPerformanceCounter - (unsigned char *)(lpOriginal+1));

jmpStub.jmp = 0xe9;
jmpStub.offset = (unsigned long *)((unsigned char *)FakeKeQueryPerformanceCounter - (unsigned char *)KeQueryPerformanceCounter - sizeof(JmpStub));

PageProtectOff();
Irql = KeRaiseIrqlToDpcLevel();
RtlCopyMemory(KeQueryPerformanceCounter,&jmpStub,sizeof(JmpStub));
KeLowerIrql( Irql );
PageProtectOn();

g_OriginalKeQueryPerformanceCounter = lpOriginal;
g_bHookKeQueryPerformanceCounter = TRUE;
status = STATUS_SUCCESS;
}

return status;
}

[/syntax]
 #26043  by myid
 Tue Jun 09, 2015 6:10 pm
pboy0922 wrote:
myid wrote:Talk is cheap. Show me the code.
hi,my Key Code is
[syntax="c"]
#pragma pack(push) //保存对齐状态
#pragma pack(1)//设定为1字节对齐

typedef struct _JmpStub
{
unsigned char jmp;
unsigned long *offset;
}JmpStub,*PJmpStub;

typedef struct _FakeKeUpdateSystemTime
{
unsigned short mul;
unsigned long *speedx;
unsigned short div;
unsigned long *speedbase;
JmpStub jmpStub;
}FakeKeUpdateSystemTime,*PFakeKeUpdateSystemTime;

typedef struct _OriginalFunction
{
unsigned char OriginalHead[12];//存储函数的头几个字节,默认为nop
JmpStub jmpStub;
}OriginalFunction,*POriginalFunction;
#pragma pack(pop)//恢复对齐状态


ULONG g_uSpeedX = 600;
ULONG g_uSpeedBase = 100;

ULONG g_uHookOffsetKeUpdateSystemTime = 0;//内联hook函数KeUpdateSystemTime的字节数
BOOLEAN g_bHookKeUpdateSystemTime = FALSE;
LPVOID g_lpfnKeUpdateSystemTime = NULL;
PFakeKeUpdateSystemTime g_FakeKeUpdateSystemTime = NULL;
POriginalFunction g_OriginalKeUpdateSystemTime = NULL;

ULONG g_uHookOffsetKeQueryPerformanceCounter = 0;//内联hook函数KeQueryPerformanceCounter的字节数
BOOLEAN g_bHookKeQueryPerformanceCounter = FALSE;
//LPVOID g_lpfnKeQueryPerformanceCounter = NULL;
POriginalFunction g_OriginalKeQueryPerformanceCounter = NULL;
LARGE_INTEGER g_liPreOriginalCounter;// 前一个查询到的性能指标数
LARGE_INTEGER g_liPreReturnCounter;// 变化后的性能指标数值


NTSTATUS HookKeyFunctions()
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
status = HookKeUpdateSystemTime();
if(!NT_SUCCESS(status)) return status;
status = HookKeQueryPerformanceCounter();
return status;
}

NTSTATUS HookKeUpdateSystemTime()
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PFakeKeUpdateSystemTime lpFake = NULL;
POriginalFunction lpOriginal = NULL;
JmpStub jmpStub = {0};
KIRQL Irql;
GetHookOffset();
if(!g_bHookKeUpdateSystemTime)
{
g_lpfnKeUpdateSystemTime = GetFuncAddress(L"KeUpdateSystemTime");
if(!g_lpfnKeUpdateSystemTime) return status;

lpOriginal = (POriginalFunction)ExAllocatePoolWithTag(NonPagedPool,sizeof(OriginalFunction),XSPEED_ORIGINAL_FUNCTION_TAG);
if(!lpOriginal) return status;
RtlFillMemory(lpOriginal,sizeof(OriginalFunction),0x90);
RtlCopyMemory(lpOriginal->OriginalHead,g_lpfnKeUpdateSystemTime,g_uHookOffsetKeUpdateSystemTime);
lpOriginal->jmpStub.jmp = 0xe9;
lpOriginal->jmpStub.offset = (unsigned long *)((unsigned char *)g_lpfnKeUpdateSystemTime + g_uHookOffsetKeUpdateSystemTime - (unsigned char *)(lpOriginal+1));

lpFake = (PFakeKeUpdateSystemTime)ExAllocatePoolWithTag(NonPagedPool,sizeof(FakeKeUpdateSystemTime),XSPEED_FAKE_UPDATE_TAG);
if(!lpFake) return status;
RtlZeroMemory(lpFake,sizeof(FakeKeUpdateSystemTime));
lpFake->mul = 0x25f7; //mul g_uSpeedX
lpFake->speedx = &g_uSpeedX;
lpFake->div = 0x35f7;//div g_uSpeedBase
lpFake->speedbase = &g_uSpeedBase;
lpFake->jmpStub.jmp = 0xe9;//jmp
lpFake->jmpStub.offset = (unsigned long *)((unsigned char *)lpOriginal - (unsigned char *)(lpFake+1));//

jmpStub.jmp = 0xe9;
jmpStub.offset = (unsigned long *)((unsigned char *)lpFake - (unsigned char *)g_lpfnKeUpdateSystemTime - sizeof(JmpStub));//

PageProtectOff();
Irql = KeRaiseIrqlToDpcLevel();
RtlCopyMemory(g_lpfnKeUpdateSystemTime,&jmpStub,sizeof(JmpStub));
KeLowerIrql( Irql );
PageProtectOn();

g_FakeKeUpdateSystemTime = lpFake;
g_OriginalKeUpdateSystemTime = lpOriginal;
g_bHookKeUpdateSystemTime = TRUE;

status = STATUS_SUCCESS;
}

return status;
}

NTSTATUS HookKeQueryPerformanceCounter()
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
POriginalFunction lpOriginal = NULL;
JmpStub jmpStub = {0};
KIRQL Irql = 0;
unsigned char *lpKeQueryPerformanceCounter = (unsigned char *)KeQueryPerformanceCounter;

if(!g_bHookKeQueryPerformanceCounter)
{
// 初始化数值
g_liPreOriginalCounter.QuadPart = 0;
g_liPreReturnCounter.QuadPart = 0;

// 首次查询
g_liPreOriginalCounter = KeQueryPerformanceCounter( NULL );
g_liPreReturnCounter.QuadPart = g_liPreOriginalCounter.QuadPart;

lpOriginal = (POriginalFunction)ExAllocatePoolWithTag(NonPagedPool,sizeof(OriginalFunction),XSPEED_ORIGINAL_FUNCTION_TAG);
if(!lpOriginal) return status;
RtlFillMemory(lpOriginal,sizeof(OriginalFunction),0x90);
RtlCopyMemory(lpOriginal->OriginalHead,KeQueryPerformanceCounter,g_uHookOffsetKeQueryPerformanceCounter);
lpOriginal->jmpStub.jmp = 0xe9;
lpOriginal->jmpStub.offset = (unsigned long *)((unsigned char *)KeQueryPerformanceCounter + g_uHookOffsetKeQueryPerformanceCounter - (unsigned char *)(lpOriginal+1));

jmpStub.jmp = 0xe9;
jmpStub.offset = (unsigned long *)((unsigned char *)FakeKeQueryPerformanceCounter - (unsigned char *)KeQueryPerformanceCounter - sizeof(JmpStub));

PageProtectOff();
Irql = KeRaiseIrqlToDpcLevel();
RtlCopyMemory(KeQueryPerformanceCounter,&jmpStub,sizeof(JmpStub));
KeLowerIrql( Irql );
PageProtectOn();

g_OriginalKeQueryPerformanceCounter = lpOriginal;
g_bHookKeQueryPerformanceCounter = TRUE;
status = STATUS_SUCCESS;
}

return status;
}

[/syntax]
AFAIK, if you make your time speed as 2x faster, you should correct system time every 2 seconds(actually, is 1 second).
 #26052  by TETYYSs
 Wed Jun 10, 2015 5:54 am
pboy0922 wrote:
TETYYSs wrote:You don't. Hook QueryPerformanceCounter inside process to do that. Kernel mode is global.
hi TETYYSs,I know the method you said,it running ring3 and must inject shellcode or dll into someone process to hook QueryPerformanceCounter.Now I need a ring0 driver to do it and must make system time be normal.I know some software had implement this function,like the attachment file :D
ring3 hook does not tamper with global system time, so you don't need a kernel driver at all.
 #26054  by cziter15
 Wed Jun 10, 2015 7:57 am
The best way to do this from kernelmode on x86 is to hook NtQueryPerformanceCounter via SSDT.
You can allso call PsGetCurrentProcess inside your hook and tamper values only if call is made in context of a process you need to speed up.

Remember that on x64 kernelmode hooking is not allowed due to Patchguard.
 #26083  by pboy0922
 Mon Jun 15, 2015 2:31 am
TETYYSs wrote:
pboy0922 wrote:
TETYYSs wrote:You don't. Hook QueryPerformanceCounter inside process to do that. Kernel mode is global.
hi TETYYSs,I know the method you said,it running ring3 and must inject shellcode or dll into someone process to hook QueryPerformanceCounter.Now I need a ring0 driver to do it and must make system time be normal.I know some software had implement this function,like the attachment file :D
ring3 hook does not tamper with global system time, so you don't need a kernel driver at all.
I must do it in ring0 because of the requirement, :(