InfinityHook 核心原理 替换WmipLoggerContext[CLCK_INDEX]->GetCpuClock
原作者见 https://github.com/everdox/InfinityHook
from 6789base.sys version 5.12.0.4874
为节约版面以下只放关键内容
DriverEntry->InitializeInfinityHook()
启动两条线程,一条初始化infhook,一条保护infhook
__int64 InitializeInfinityHook()
{
HANDLE ThreadHandle; // [rsp+40h] [rbp-58h]
HANDLE Handle; // [rsp+48h] [rbp-50h]
OBJECT_ATTRIBUTES ObjectAttributes; // [rsp+50h] [rbp-48h]
unsigned int v4; // [rsp+80h] [rbp-18h]
v4 = -1073741823;
ThreadHandle = 0i64;
ObjectAttributes.Length = 0;
memset(&ObjectAttributes.RootDirectory, 0, 0x28ui64);
if ( byte_3648C )
return 3221225473i64;
stru_365D0.Count = 1;
stru_365D0.Owner = 0i64;
stru_365D0.Contention = 0;
KeInitializeEvent(&stru_365D0.Event, SynchronizationEvent, 0);
sub_22980(&unk_36608);
KeInitializeEvent(&Event, NotificationEvent, 0);
byte_36938 = 1;
stru_36568.Count = 1;
stru_36568.Owner = 0i64;
stru_36568.Contention = 0;
KeInitializeEvent(&stru_36568.Event, SynchronizationEvent, 0);
ObjectAttributes.Length = 48;
ObjectAttributes.RootDirectory = 0i64;
ObjectAttributes.Attributes = 512;
ObjectAttributes.ObjectName = 0i64;
ObjectAttributes.SecurityDescriptor = 0i64;
ObjectAttributes.SecurityQualityOfService = 0i64;
v4 = PsCreateSystemThread(
&ThreadHandle,
0x1FFFFFu,
&ObjectAttributes,
0i64,
0i64,
(PKSTART_ROUTINE)InfinityHookInitThread,
0i64);
if ( !v4 )
ZwClose(ThreadHandle);
ObjectAttributes.Length = 48;
ObjectAttributes.RootDirectory = 0i64;
ObjectAttributes.Attributes = 512;
ObjectAttributes.ObjectName = 0i64;
ObjectAttributes.SecurityDescriptor = 0i64;
ObjectAttributes.SecurityQualityOfService = 0i64;
v4 = PsCreateSystemThread(
&Handle,
0x1FFFFFu,
&ObjectAttributes,
0i64,
0i64,
(PKSTART_ROUTINE)InitializeInfinityHookProtectThread,
0i64);
if ( !v4 )
{
ObReferenceObjectByHandle(Handle, 0x1FFFFFu, PsThreadType, 0, &g_ThreadObject, 0i64);
ZwClose(Handle);
}
return v4;
}
void __fastcall InfinityHookInitThread(PVOID StartContext)
{
__int64 _RAX; // rax
LARGE_INTEGER (*_RCX)(); // rcx
__int64 _RCX; // rcx
LARGE_INTEGER Interval; // [rsp+20h] [rbp-28h]
_QWORD *getCpuClock; // [rsp+28h] [rbp-20h]
int v6; // [rsp+30h] [rbp-18h]
v6 = -1073741823;
getCpuClock = 0i64;
Interval.QuadPart = -30000000i64;
while ( !LoadNtdll() )
KeDelayExecutionThread(0, 0, &Interval);
if ( (int)InitializeInfhookCore() >= 0 )
{
v6 = EnableEtwLogger();
if ( v6 >= 0 )
{
v6 = GetCkcl(2u, (_QWORD *)infhookCore + 90115);
if ( v6 >= 0 && *((_QWORD *)infhookCore + 90115) )
{
getCpuClock = (_QWORD *)(*((_QWORD *)infhookCore + 90115)
+ (unsigned int)OFFSET_WMI_LOGGER_CONTEXT_CPU_CYCLE_CLOCK);
if ( (unsigned __int8)MmIsAddressValid(getCpuClock)
&& (unsigned __int8)MmIsAddressValid((char *)getCpuClock + 7) )
{
if ( *getCpuClock >= MmSystemRangeStart )
{
_RAX = *((_QWORD *)infhookCore + 90115) + (unsigned int)OFFSET_WMI_LOGGER_CONTEXT_CPU_CYCLE_CLOCK;
_RCX = InternalGetCpuClock;
__asm { xchg rcx, [rax] }
*((_QWORD *)infhookCore + 90114) = _RCX;
v6 = 0;
}
else
{
v6 = 0xC0000001;
}
}
else
{
v6 = 0xC0000001;
}
}
else
{
v6 = 0xC0000001;
}
}
else
{
v6 = 0xC0000001;
}
}
else
{
v6 = 0xC0000001;
}
PsTerminateSystemThread(0);
}
NTSTATUS __stdcall EnableEtwLogger()
{
NTSTATUS result; // eax
NTSTATUS v1; // [rsp+20h] [rbp-18h]
NTSTATUS v2; // [rsp+20h] [rbp-18h]
v1 = IfhpModifyTraceSettings(1);
if ( v1 >= 0 )
goto LABEL_9;
v2 = IfhpModifyTraceSettings(0);
if ( v2 < 0 )
return v2;
v1 = IfhpModifyTraceSettings(1);
if ( v1 >= 0 )
LABEL_9:
result = v1;
else
result = v1;
return result;
}
IfhModifyTraceSettings复制粘贴过于直球这里就不贴代码了,放个对比图:
主要流程:初始化infhookCore结构(应该是一个很大的结构体,具体成员就不逆了)
sub_2D210判断两个不明物体(无关紧要懒得逆)
寻找explorer.exe的PID
加载L"\\SystemRoot\\system32\\ntdll.dll"并搜索导出表,把nt函数全部保存进infhookcore里的一个表
NTSTATUS __stdcall InitializeInfhookCore()
{
LARGE_INTEGER Interval; // [rsp+20h] [rbp-28h]
NTSTATUS v2; // [rsp+28h] [rbp-20h]
UNICODE_STRING DestinationString; // [rsp+30h] [rbp-18h]
v2 = -1073741823;
Interval.QuadPart = -30000000i64;
if ( infhookCore && isZwTraceControlAvailable )
return 0;
while ( 1 )
{
if ( !infhookCore )
{
infhookCore = ExAllocatePoolWithTag(NonPagedPool, 720928ui64, 'hchk');
if ( !infhookCore )
{
v2 = -1073741670;
goto LABEL_26;
}
memset(infhookCore, 0, 0xB0020ui64);
}
if ( !*((_QWORD *)infhookCore + 90112) || !*((_QWORD *)infhookCore + 90113) )
{
v2 = sub_2D210((char *)infhookCore + 720896, (char *)infhookCore + 720904);
if ( v2 < 0 || !*((_QWORD *)infhookCore + 90112) || !*((_QWORD *)infhookCore + 90113) )
{
v2 = -1073741823;
goto LABEL_26;
}
}
RtlInitUnicodeString(&DestinationString, L"explorer.exe");
v2 = FindProcessByProcessName(&DestinationString, &g_ExplorerPID);
if ( v2 >= 0 )
{
if ( g_ExplorerPID )
break;
}
KeDelayExecutionThread(0, 0, &Interval);
}
v2 = LoadSSDTFunctionEntry();
if ( v2 >= 0 )
{
v2 = LoadOffsetsVars();
if ( v2 >= 0 )
{
v2 = LoadSSSDTFunctionEntry();
if ( v2 >= 0 )
{
byte_3648D = 1;
sub_2A640();
ZwTraceControl = (__int64 (__fastcall *)(_QWORD, _QWORD, _QWORD, _QWORD, _DWORD, _QWORD))MakeZwTraceControl();
if ( ZwTraceControl )
{
isZwTraceControlAvailable = 1;
v2 = 0;
}
else
{
v2 = -1073741823;
}
}
else
{
v2 = -1073741823;
}
}
else
{
v2 = -1073741823;
}
}
else
{
v2 = -1073741823;
}
LABEL_26:
if ( v2 )
{
if ( infhookCore )
{
ExFreePoolWithTag(infhookCore, 0x6863686Bu);
infhookCore = 0i64;
}
}
return v2;
}
根据系统版本加载一些偏移
NTSTATUS __stdcall LoadOffsetsVars()
{
NTSTATUS v1; // [rsp+20h] [rbp-18h]
unsigned int v2; // [rsp+24h] [rbp-14h]
v1 = 0;
v2 = GetBuildNumber();
if ( v2 > 14393 )
{
if ( v2 != 15063 && v2 != 16299 && v2 != 17134 && v2 != 17763 && v2 != 18362 )
goto LABEL_18;
LABEL_17:
LODWORD(OFFSET_WMI_LOGGER_CONTEXT_CPU_CYCLE_CLOCK) = 40;
offset_SystemCallNumber = 0x80i64;
PerfGlobalGroupMask = GetPerfGlobalGroupMask();
goto LABEL_18;
}
switch ( v2 )
{
case 14393u:
goto LABEL_17;
case 610u:
LODWORD(OFFSET_WMI_LOGGER_CONTEXT_CPU_CYCLE_CLOCK) = 24;
offset_SystemCallNumber = 0x1F8i64;
PerfGlobalGroupMask = GetPerfGlobalGroupMask2();
break;
case 620u:
LODWORD(OFFSET_WMI_LOGGER_CONTEXT_CPU_CYCLE_CLOCK) = 40;
offset_SystemCallNumber = 0x80i64;
PerfGlobalGroupMask = GetPerfGlobalGroupMask3();
break;
case 630u:
case 10240u:
case 10586u:
goto LABEL_17;
}
LABEL_18:
if ( v2 > 18362 )
v1 = FindOffsetsFor18383();
return v1;
}
注意这里还会在KeReleaseSpinLock里面搜索PerfGlobalGroupMask
_int64 GetPerfGlobalGroupMask()
{
_BYTE *v1; // [rsp+20h] [rbp-38h]
unsigned int v2; // [rsp+28h] [rbp-30h]
__int64 v3; // [rsp+30h] [rbp-28h]
UNICODE_STRING DestinationString; // [rsp+40h] [rbp-18h]
v2 = 0;
v3 = 0i64;
RtlInitUnicodeString(&DestinationString, L"KeReleaseSpinLock");
v1 = MmGetSystemRoutineAddress(&DestinationString);
if ( !v1 )
return 0i64;
while ( v2 < 0xA )
{
if ( v1[v2] == 0x40
&& v1[v2 + 1] == 0x53
&& v1[v2 + 2] == 0x48
&& (unsigned __int8)v1[v2 + 3] == 0x83
&& (unsigned __int8)v1[v2 + 6] == 0xF6
&& v1[v2 + 7] == 5 )
{
v3 = (__int64)&v1[*(unsigned int *)&v1[v2 + 8] + 7];
if ( !(unsigned __int8)MmIsAddressValid(v3) || !(unsigned __int8)MmIsAddressValid(v3 + 15) )
return 0i64;
return v3;
}
++v2;
}
return v3;
}
注意这个PerfGlobalGroupMask[2] & 0x40控制SYSTEM_CALL的etw记录是否开启
6789安全卫士为了不让自己的hook被关闭,会给这里监控并强制置位
LoadSSSDTFunctionEntry没什么可说的,和LoadSSDTFunctionEntry的唯一区别就是取entry之前先attach了explorer
从刚才获取的ssdt入口中取出ZwTraceControl(貌似6789安全卫士用的还是NtTraceControl?我没仔细看,但是如果是NtTraceControl的话我只能说这也太捞了吧,他不怕我蓝屏的吗?)
__int64 MakeZwTraceControl()
{
__int64 result; // rax
char *v1; // [rsp+20h] [rbp-18h]
v1 = FindZwForSSDT("NtTraceControl");
if ( v1 )
result = *((_QWORD *)v1 + 42);
else
result = 0i64;
return result;
}
获取ClckLoggerContext,根据版本不同获取方法还不一样
NTSTATUS __fastcall GetCkcl(unsigned int type, _QWORD *clck)
{
NTSTATUS result; // eax
unsigned int v3; // [rsp+20h] [rbp-18h]
unsigned int typee; // [rsp+40h] [rbp+8h]
_QWORD *clck_1; // [rsp+48h] [rbp+10h]
clck_1 = clck;
typee = type;
v3 = GetBuildNumber();
if ( v3 <= 14393 )
{
if ( v3 != 14393 )
{
switch ( v3 )
{
case 610u:
return GetCkclWmiLoggerContext7601(typee, clck_1);
case 620u:
return GetCkclWmiLoggerContext9200(typee, clck_1);
case 630u:
return GetCkclWmiLoggerContext9600(typee, clck_1);
}
if ( v3 != 10240 && v3 != 10586 )
goto LABEL_19;
}
return GetCkclWmiLoggerContext(typee, clck_1);
}
if ( v3 == 15063 || v3 == 16299 || v3 == 17134 || v3 == 17763 || v3 == 18362 )
return GetCkclWmiLoggerContext(typee, clck_1);
LABEL_19:
if ( v3 <= 18362 )
result = 0xC0000001;
else
result = sub_2A0A0(typee, clck_1);
return result;
}
7600 7601从EtwSendTraceBuffer里搜索WmipLoggerContext
9200(win8)9600(win8.1)也是同样的套路这里就不重复发了
win10上面使用经典的复制粘贴大法
这里不多说懂得都懂好吧
最后使用InterlockedExchange替换完getcpuclock指针初始化就算完成了
getCpuClock = (_QWORD *)(*((_QWORD *)infhookCore + 90115)
+ (unsigned int)OFFSET_WMI_LOGGER_CONTEXT_CPU_CYCLE_CLOCK);
if ( (unsigned __int8)MmIsAddressValid(getCpuClock)
&& (unsigned __int8)MmIsAddressValid((char *)getCpuClock + 7) )
{
if ( *getCpuClock >= MmSystemRangeStart )
{
_RAX = *((_QWORD *)infhookCore + 90115) + (unsigned int)OFFSET_WMI_LOGGER_CONTEXT_CPU_CYCLE_CLOCK;
_RCX = InternalGetCpuClock;
__asm { xchg rcx, [rax] }
*((_QWORD *)infhookCore + 90114) = _RCX;
v6 = 0;
}
然后是它的保护线程
void __fastcall InitializeInfinityHookProtectThread(PVOID StartContext)
{
LARGE_INTEGER Interval; // [rsp+30h] [rbp-28h]
NTSTATUS v5; // [rsp+38h] [rbp-20h]
LARGE_INTEGER Timeout; // [rsp+40h] [rbp-18h]
__int64 ckcl; // [rsp+48h] [rbp-10h]
Timeout.LowPart = 0;
memset((char *)&Timeout.QuadPart + 4, 0, 4ui64);
ckcl = 0i64;
Interval.QuadPart = -10000000i64;
if ( g_ThreadObject )
{
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
v5 = KeWaitForSingleObject(&Event, Executive, 0, 0, &Timeout);
if ( v5 != 0x102 )
{
PsTerminateSystemThread(0);
return;
}
if ( infhookCore )
break;
KeDelayExecutionThread(0, 0, &Interval);
}
if ( *((_QWORD *)infhookCore + 90114) )
break;
KeDelayExecutionThread(0, 0, &Interval);
}
v5 = GetCkcl(2u, &ckcl);
if ( v5 >= 0 )
break;
KeDelayExecutionThread(0, 0, &Interval);
}
if ( *((_QWORD *)infhookCore + 0x16003) != ckcl )
break;
if ( !*((_QWORD *)infhookCore + 0x16003) || !(unsigned __int8)MmIsAddressValid(*((_QWORD *)infhookCore + 90115)) )
goto LABEL_27;
LABEL_16:
if ( *(LARGE_INTEGER (**)())((unsigned int)OFFSET_WMI_LOGGER_CONTEXT_CPU_CYCLE_CLOCK
+ *((_QWORD *)infhookCore + 90115)) != InternalGetCpuClock )
{
_RAX = *((_QWORD *)infhookCore + 0x16003) + (unsigned int)OFFSET_WMI_LOGGER_CONTEXT_CPU_CYCLE_CLOCK;
_RCX = InternalGetCpuClock;
__asm { xchg rcx, [rax] }
*((_QWORD *)infhookCore + 90114) = _RCX;
}
if ( PerfGlobalGroupMask && !(*(_DWORD *)(PerfGlobalGroupMask + 8i64) & 0x40) )
*((_QWORD *)infhookCore + 90115) = 0i64;
else
LABEL_27:
KeDelayExecutionThread(0, 0, &Interval);
}
v5 = EnableEtwLogger();
if ( v5 >= 0 )
{
v5 = GetCkcl(2u, &ckcl);
if ( v5 >= 0 )
{
*((_QWORD *)infhookCore + 90115) = ckcl;
if ( *((_QWORD *)infhookCore + 90115) )
goto LABEL_16;
KeDelayExecutionThread(0, 0, &Interval);
}
else
{
KeDelayExecutionThread(0, 0, &Interval);
}
}
else
{
KeDelayExecutionThread(0, 0, &Interval);
}
}
}
}
流程大概是:
1、GetCkcl(2 获取clckloggercontext指针
2、如果infhookcore.clck指针不等于刚才获取的clck指针则重启clck logger(不等于说明有别人关闭了或者修改了clck logger)并设置
infhookcore.clck为新的clck logger
3、如果clck+offset_GetCpuClock处的函数指针不等于InternalGetCpuClock则替换函数指针为InternalGetCpuClock
4、如果PerfGlobalGroupMask[2] 不包含 0x40的bit(说明etw的SYSTEMCALL监控被人为关闭)则置infhookcore.clck为0,回到第2步(也就是自动重启clck logger)
让我们看看
InternalGetCpuClock做了什么
LARGE_INTEGER InternalGetCpuClock()
{
unsigned int walkTimes; // ecx
char *hookEntry; // [rsp+20h] [rbp-58h]
unsigned int j; // [rsp+30h] [rbp-48h]
__int64 syscallFunction; // [rsp+48h] [rbp-30h]
void **StackCurrent; // [rsp+50h] [rbp-28h]
unsigned int walkStackOffset; // [rsp+60h] [rbp-18h]
unsigned int syscallNumber; // [rsp+64h] [rbp-14h]
void *retaddr; // [rsp+78h] [rbp+0h]
j = 0;
syscallNumber = GetSystemCallNumber();
if ( (int)KeGetCurrentIrql() < 2 )
{
if ( ExGetPreviousMode() )
{
syscallFunction = GetSSDTEntryRoutine(syscallNumber);
if ( syscallFunction )
{
hookEntry = GetSSDTHookEntry(syscallNumber);
if ( hookEntry )
{
if ( *((_DWORD *)hookEntry + 65) || *((_DWORD *)hookEntry + 64) )
{
if ( (int)(unsigned __int8)hookEntry[332] <= 0 )
walkStackOffset = 0;
else
walkStackOffset = 0x70;
for ( StackCurrent = (void **)(__readgsqword(0x1A8u) - (walkStackOffset + 400i64));
StackCurrent > &retaddr;
--StackCurrent )
{
walkTimes = j++;
if ( walkTimes >= 10 )
break;
if ( (unsigned __int8)MmIsAddressValid(StackCurrent) == 1
&& (unsigned __int8)MmIsAddressValid((char *)StackCurrent + 7) == 1
&& (void *)syscallFunction == *StackCurrent )
{
_RCX = NewSSDTRoutine;
_RAX = StackCurrent;
__asm { xchg rcx, [rax] }
return KeQueryPerformanceCounter(0i64);
}
}
}
}
}
}
}
return KeQueryPerformanceCounter(0i64);
}
__int64 GetSystemCallNumber()
{
return *(_DWORD *)(offset_SystemCallNumber + PsGetCurrentThread()) & 0xFFFF;
}
__int64 __fastcall GetSSDTEntryRoutine(unsigned int syscallNumber)
{
__int64 result; // rax
char v2; // [rsp+20h] [rbp-18h]
if ( syscallNumber < 0x1000 )
{
if ( syscallNumber < 0x400 )
result = GetSSDTEntry(*((__int64 **)infhookCore + 90112), syscallNumber, &v2);
else
result = 0i64;
}
else if ( syscallNumber - 4096 < 0x400 )
{
result = GetSSDTEntry((__int64 *)(*((_QWORD *)infhookCore + 90113) + 32i64), syscallNumber - 4096, &v2);
}
else
{
result = 0i64;
}
return result;
}
首先:必须是来自用户模式的系统调用,并且irql小于DISPATCH_LEVEL
获取CurrentThread->SystemCallNumber 根据syscallnumber取ssdt function entry和hook entry(hookentry不一定有)
for ( StackCurrent = (void **)(__readgsqword(0x1A8u) - (walkStackOffset + 400i64));
StackCurrent > &retaddr;
--StackCurrent )
{
从RspBase(gs:0x1A8)-0x70到_AddressOfReturnAddress进行栈遍历
找到(void *)syscallFunction == *StackCurrent的情况
则把
*StackCurrent替换为NewSSDTRoutine
NewSSDTRoutine 如下:
.text:0000000000030169 55 push rbp
.text:000000000003016A 48 8B EC mov rbp, rsp
.text:000000000003016D 9C pushfq
.text:000000000003016E 41 52 push r10
.text:0000000000030170 48 81 EC C0 00 00 00 sub rsp, 0C0h
.text:0000000000030177 48 89 4D 10 mov [rbp+arg_0], rcx
.text:000000000003017B 48 89 55 18 mov [rbp+arg_8], rdx
.text:000000000003017F 4C 89 45 20 mov [rbp+arg_10], r8
.text:0000000000030183 4C 89 4D 28 mov [rbp+arg_18], r9
.text:0000000000030187 E8 C4 FF FF FF call GetSystemCallNumber
.text:000000000003018C 89 84 24 B8 00 00 00 mov [rsp+0D0h+var_18], eax
.text:0000000000030193 8B 8C 24 B8 00 00 00 mov ecx, [rsp+0D0h+var_18]
.text:000000000003019A 48 8D 55 10 lea rdx, [rbp+arg_0]
.text:000000000003019E 4C 8D 84 24 B0 00 00 00 lea r8, [rsp+0D0h+var_20]
.text:00000000000301A6 E8 F5 95 FF FF call CallHookEntryRoutine
.text:00000000000301AB 83 F8 02 cmp eax, 2
.text:00000000000301AE 48 8B 84 24 B0 00 00 00 mov rax, [rsp+0D0h+var_20]
.text:00000000000301B6 74 5B jz short loc_30213
.text:00000000000301B8 8B 8C 24 B8 00 00 00 mov ecx, [rsp+0D0h+var_18]
.text:00000000000301BF E8 CC 94 FF FF call GetSSDTEntryRoutine
.text:00000000000301C4 48 85 C0 test rax, rax
.text:00000000000301C7 74 4A jz short loc_30213
.text:00000000000301C9 4C 8B D0 mov r10, rax
.text:00000000000301CC 48 8D 75 30 lea rsi, [rbp+arg_20]
.text:00000000000301D0 48 8D 7C 24 20 lea rdi, [rsp+0D0h+var_B0]
.text:00000000000301D5 FC cld
.text:00000000000301D6 48 C7 C1 0E 00 00 00 mov rcx, 0Eh
.text:00000000000301DD F3 48 A5 rep movsq
.text:00000000000301E0 48 8B 4D 10 mov rcx, [rbp+arg_0]
.text:00000000000301E4 48 8B 55 18 mov rdx, [rbp+arg_8]
.text:00000000000301E8 4C 8B 45 20 mov r8, [rbp+arg_10]
.text:00000000000301EC 4C 8B 4D 28 mov r9, [rbp+arg_18]
.text:00000000000301F0 41 FF D2 call r10
.text:00000000000301F3 48 89 84 24 B0 00 00 00 mov [rsp+0D0h+var_20], rax
.text:00000000000301FB 8B 8C 24 B8 00 00 00 mov ecx, [rsp+0D0h+var_18]
.text:0000000000030202 48 8D 55 10 lea rdx, [rbp+arg_0]
.text:0000000000030206 4C 8B 84 24 B0 00 00 00 mov r8, [rsp+0D0h+var_20]
.text:000000000003020E E8 4D 96 FF FF call sub_29860
.text:0000000000030213
.text:0000000000030213 loc_30213: ; CODE XREF: NewSSDTRoutine+4D↑j
.text:0000000000030213 ; NewSSDTRoutine+5E↑j
.text:0000000000030213 48 8B 84 24 B0 00 00 00 mov rax, [rsp+0D0h+var_20]
.text:000000000003021B 48 81 C4 C0 00 00 00 add rsp, 0C0h
.text:0000000000030222 41 5A pop r10
.text:0000000000030224 9D popfq
.text:0000000000030225 5D pop rbp
.text:0000000000030226 C3 retn
.text:0000000000030226 NewSSDTRoutine endp
hookentry里有八个函数指针(*(QWORD *)&hookEntry[16 * i + 8])当这个ssdt被调用时6789安全卫士就会帮我们call这八个entry (如果非0的话)
__int64 __fastcall CallHookEntryRoutine(unsigned int a1, __int64 a2, __int64 a3)
{
unsigned int i; // [rsp+20h] [rbp-38h]
char *hookEntry; // [rsp+30h] [rbp-28h]
_QWORD *a3a; // [rsp+68h] [rbp+10h]
__int64 a1a; // [rsp+70h] [rbp+18h]
a1a = a3;
a3a = (_QWORD *)a2;
hookEntry = GetSSDTHookEntry(a1);
if ( !hookEntry || !*((_DWORD *)hookEntry + 65) )
return 1i64;
for ( i = 0; i < 8; ++i )
{
if ( *(_QWORD *)&hookEntry[16 * i + 8]
&& (unsigned int)CallHookEntryRoutineInternal(
a1a,
*(__int64 (__fastcall **)(__int64, _QWORD, _QWORD, _QWORD))&hookEntry[16 * i + 8],
a3a) == 2 )
{
return 2i64;
}
}
return 1i64;
}
__int64 __fastcall CallHookEntryRoutineInternal(__int64 a1, __int64 (__fastcall *fn)(__int64, _QWORD, _QWORD, _QWORD), _QWORD *a3)
{
ULONG_PTR stackParameters[15]; // [rsp+20h] [rbp-A0h]
qmemcpy(stackParameters, a3 + 3, sizeof(stackParameters));
return fn(a1, *a3, a3[1], a3[2]);
}
如果CallHookEntryRoutine返回2的话就是拦截了这次系统调用,不调用原始函数
否则从infhookcore表中取出原始ssdt函数,把寄存器参数和栈参数恢复,call r10调用原始ssdt函数
.text:00000000000301C9 4C 8B D0 mov r10, rax
.text:00000000000301CC 48 8D 75 30 lea rsi, [rbp+arg_20]
.text:00000000000301D0 48 8D 7C 24 20 lea rdi, [rsp+0D0h+var_B0]
.text:00000000000301D5 FC cld
.text:00000000000301D6 48 C7 C1 0E 00 00 00 mov rcx, 0Eh
.text:00000000000301DD F3 48 A5 rep movsq//memcpy恢复栈参数
.text:00000000000301E0 48 8B 4D 10 mov rcx, [rbp+arg_0]//恢复寄存器参数
.text:00000000000301E4 48 8B 55 18 mov rdx, [rbp+arg_8]
.text:00000000000301E8 4C 8B 45 20 mov r8, [rbp+arg_10]
.text:00000000000301EC 4C 8B 4D 28 mov r9, [rbp+arg_18]
.text:00000000000301F0 41 FF D2 call r10 //原始SSDT函数
总结:这套代码好多地方都有蓝屏的隐患(比如
https://github.com/everdox/InfinityHook/issues/18
),而且unistall的时候没法动态卸载驱动(什么?你不让用户卸载啊?那没事了)
喜讯:18950预览版已经把InfinityHook愉悦送走
6789安全卫士只看到了第二层,而他把微软想成了第一层,实际上微软在第五层
[课程]FART 脱壳王!加量不加价!FART作者讲授!
最后于 2020-3-26 13:16
被hzqst编辑
,原因: