加载中
加载中
表情图片
评为精选
鼓励
加载中...
分享
加载中...
文件下载
加载中...
修改排序
加载中...
一种针对线程的隐蔽式SSDT Hook
phpskycn2018/09/21软件综合 IP:云南
Other

这篇文章介绍了本科大一时(2012年)发现的一种隐蔽式SSDT Hook方法,仅适用于32位的Windows系统。当时还没有Windows10,64位系统的普及率也不像现在这么高,当时主要涉及的是32位的Windows 7和Windows XP,代码在Windows XP SP3、Windows 2003 SP1/SP2、Windows 7 SP1、Windows 8下测试通过。

一、SSDT Hook

SSDT Hook是一种经典的Windows内核劫持手段,通过改变Windows用户层的应用程序(RING3)通过SYSENTER指令调用内核功能时进入内核层(RING0)后的系统服务分发(System Services Descriptor)流程,实现对用户层应用程序调用内核功能的拦截。
最古老的SSDT Hook实现是修改内核内存中实现系统服务分发的例程,对其进行kernel inline hook,后来又有人提出修改系统服务分发表(System Services Descriptor Table)的表项。这两种方式均属于全局Hook,缺点十分明显:容易被其它内核权限的程序发现,只需要对相关的例程和SSDT的表项进行校验,即可发现异常之处。

二、系统服务分发的流程

Windows的用户程序在需要调用内核服务时,先将需要调用的内核服务号存入eax寄存器中,随后调用sysenter指令(对于Pentium ii之前的CPUS是int 0x2e)切换到内核模式。sysenter会完成RING3-RING0的切换工作并保存一些信息,随后载入MSR中设定的CS、ESP、EIP的值。这部分操作在ntdll.dll中实现(可以自己编程替代),之后进入内核模式(RIN0),此时EIP指向_KiFastCallEntrt()(对于SYSENTER指令进入),在建立了一个陷阱帧并设置了相关寄存器的值之后进入真正的处理系统服务的例程_KiSystemServiceRepeat(),在WRK 1.2中相关代码如下(\base\ntos\ke\i386\trap.asm):



Other
_KiFastCallEntry proc ; ; Sanitize the segment registers ; mov ecx, KGDT_R3_DATA OR RPL_MASK push KGDT_R0_PCR pop fs mov ds, ecx mov es, ecx ; ; When we trap into the kernel via fast system call we start on the DPC stack. We need ; shift to the threads stack before enabling interrupts. ; mov ecx, PCR[PcTss] ; mov esp, [ecx]+TssEsp0 push KGDT_R3_DATA OR RPL_MASK ; Push user SS push edx ; Push ESP pushfd Kfsc10: push 2 ; Sanitize eflags, clear direction, NT etc add edx, 8 ; (edx) -> arguments popfd ; .errnz(EFLAGS_INTERRUPT_MASK AND 0FFFF00FFh) or byte ptr [esp+1], EFLAGS_INTERRUPT_MASK/0100h ; Enable interrupts in eflags push KGDT_R3_CODE OR RPL_MASK ; Push user CS push dword ptr ds:[USER_SHARED_DATA+UsSystemCallReturn] ; push return address push 0 ; put pad dword for error on stack push ebp ; save the non-volatile registers push ebx ; push esi ; push edi ; mov ebx, PCR[PcSelfPcr] ; Get PRCB address push KGDT_R3_TEB OR RPL_MASK ; Push user mode FS mov esi, [ebx].PcPrcbData+PbCurrentThread ; get current thread address ; ; Save the old exception list in trap frame and initialize a new empty ; exception list. ; push [ebx].PcExceptionList ; save old exception list mov [ebx].PcExceptionList, EXCEPTION_CHAIN_END ; set new empty list mov ebp, [esi].ThInitialStack ; ; Save the old previous mode in trap frame, allocate remainder of trap frame, ; and set the new previous mode. ; push MODE_MASK ; Save previous mode as user sub esp,TsPreviousPreviousMode ; allocate remainder of trap frame sub ebp, NPX_FRAME_LENGTH + KTRAP_FRAME_LENGTH mov byte ptr [esi].ThPreviousMode,MODE_MASK ; set new previous mode of user ; ; Now the full trap frame is build. ; Calculate initial stack pointer from thread initial stack to contain NPX and trap. ; If this isn't the same as esp then we are a VX86 thread and we are rejected ; cmp ebp, esp jne short Kfsc91 ; ; Set the new trap frame address. ; and dword ptr [ebp].TsDr7, 0 test byte ptr [esi].ThDebugActive, 0ffh ; See if we need to save debug registers mov [esi].ThTrapFrame, ebp ; set new trap frame address jnz Dr_FastCallDrSave ; if nz, debugging is active on thread Dr_FastCallDrReturn: ; SET_DEBUG_DATA ; Note this destroys edi sti ; enable interrupts ?FpoValue = 0 ; ; (eax) = Service number ; (edx) = Callers stack pointer ; (esi) = Current thread address ; ; All other registers have been saved and are free. ; ; Check if the service number within valid range ; _KiSystemServiceRepeat: mov edi, eax ; copy system service number shr edi, SERVICE_TABLE_SHIFT ; isolate service table number and edi, SERVICE_TABLE_MASK ; mov ecx, edi ; save service table number add edi, [esi]+ThServiceTable ; compute service descriptor address mov ebx, eax ; save system service number and eax, SERVICE_NUMBER_MASK ; isolate service table offset

这里有一个值得注意的地方:SSDT的地址并非是固定或者存在某个全局变量之中,而是通过PCR拿到当前线程的KTHREAD之后,在KTHREAD之中获取。

KTHREAD的结构如下(位于\base\ntos\inc\ke.h):




Other
typedef struct _KTHREAD { // // The dispatcher header and mutant listhead are fairly infrequently // referenced. // DISPATCHER_HEADER Header; LIST_ENTRY MutantListHead; // // The following fields are referenced during context switches and wait // operatings. They have been carefully laid out to get the best cache // hit ratios. // PVOID InitialStack; PVOID StackLimit; PVOID KernelStack; KSPIN_LOCK ThreadLock; union { KAPC_STATE ApcState; struct { UCHAR ApcStateFill[KAPC_STATE_ACTUAL_LENGTH]; BOOLEAN ApcQueueable; volatile UCHAR NextProcessor; volatile UCHAR DeferredProcessor; UCHAR AdjustReason; SCHAR AdjustIncrement; }; }; KSPIN_LOCK ApcQueueLock; #if !defined(_AMD64_) ULONG ContextSwitches; volatile UCHAR State; UCHAR NpxState; KIRQL WaitIrql; KPROCESSOR_MODE WaitMode; #endif LONG_PTR WaitStatus; union { PKWAIT_BLOCK WaitBlockList; PKGATE GateObject; }; BOOLEAN Alertable; BOOLEAN WaitNext; UCHAR WaitReason; SCHAR Priority; UCHAR EnableStackSwap; volatile UCHAR SwapBusy; BOOLEAN Alerted[MaximumMode]; union { LIST_ENTRY WaitListEntry; SINGLE_LIST_ENTRY SwapListEntry; }; PRKQUEUE Queue; #if !defined(_AMD64_) ULONG WaitTime; union { struct { SHORT KernelApcDisable; SHORT SpecialApcDisable; }; ULONG CombinedApcDisable; }; #endif PVOID Teb; union { KTIMER Timer; struct { UCHAR TimerFill[KTIMER_ACTUAL_LENGTH]; // // N.B. The following bit number definitions must match the // following bit field. // // N.B. These bits can only be written with interlocked // operations. // #define KTHREAD_AUTO_ALIGNMENT_BIT 0 #define KTHREAD_DISABLE_BOOST_BIT 1 union { struct { LONG AutoAlignment : 1; LONG DisableBoost : 1; LONG ReservedFlags : 30; }; LONG ThreadFlags; }; }; }; union { KWAIT_BLOCK WaitBlock[THREAD_WAIT_OBJECTS + 1]; struct { UCHAR WaitBlockFill0[KWAIT_BLOCK_OFFSET_TO_BYTE0]; BOOLEAN SystemAffinityActive; }; struct { UCHAR WaitBlockFill1[KWAIT_BLOCK_OFFSET_TO_BYTE1]; CCHAR PreviousMode; }; struct { UCHAR WaitBlockFill2[KWAIT_BLOCK_OFFSET_TO_BYTE2]; UCHAR ResourceIndex; }; struct { UCHAR WaitBlockFill3[KWAIT_BLOCK_OFFSET_TO_BYTE3]; UCHAR LargeStack; }; #if defined(_AMD64_) struct { UCHAR WaitBlockFill4[KWAIT_BLOCK_OFFSET_TO_LONG0]; ULONG ContextSwitches; }; struct { UCHAR WaitBlockFill5[KWAIT_BLOCK_OFFSET_TO_LONG1]; volatile UCHAR State; UCHAR NpxState; KIRQL WaitIrql; KPROCESSOR_MODE WaitMode; }; struct { UCHAR WaitBlockFill6[KWAIT_BLOCK_OFFSET_TO_LONG2]; ULONG WaitTime; }; struct { UCHAR WaitBlockFill7[KWAIT_BLOCK_OFFSET_TO_LONG3]; union { struct { SHORT KernelApcDisable; SHORT SpecialApcDisable; }; ULONG CombinedApcDisable; }; }; #endif }; LIST_ENTRY QueueListEntry; // // The following fields are accessed during system service dispatch. // PKTRAP_FRAME TrapFrame; PVOID CallbackStack; PVOID ServiceTable; #if defined(_AMD64_) ULONG KernelLimit; #endif // // The following fields are referenced during ready thread and wait // completion. // UCHAR ApcStateIndex; UCHAR IdealProcessor; BOOLEAN Preempted; BOOLEAN ProcessReadyQueue; #if defined(_AMD64_) PVOID Win32kTable; ULONG Win32kLimit; #endif BOOLEAN KernelStackResident; SCHAR BasePriority; SCHAR PriorityDecrement; CHAR Saturation; KAFFINITY UserAffinity; PKPROCESS Process; KAFFINITY Affinity; // // The below fields are infrequently referenced. // PKAPC_STATE ApcStatePointer[2]; union { KAPC_STATE SavedApcState; struct { UCHAR SavedApcStateFill[KAPC_STATE_ACTUAL_LENGTH]; CCHAR FreezeCount; CCHAR SuspendCount; UCHAR UserIdealProcessor; UCHAR CalloutActive; #if defined(_AMD64_) BOOLEAN CodePatchInProgress; #elif defined(_X86_) UCHAR Iopl; #else UCHAR OtherPlatformFill; #endif }; }; PVOID Win32Thread; PVOID StackBase; union { KAPC SuspendApc; struct { UCHAR SuspendApcFill0[KAPC_OFFSET_TO_SPARE_BYTE0]; SCHAR Quantum; }; struct { UCHAR SuspendApcFill1[KAPC_OFFSET_TO_SPARE_BYTE1]; UCHAR QuantumReset; }; struct { UCHAR SuspendApcFill2[KAPC_OFFSET_TO_SPARE_LONG]; ULONG KernelTime; }; struct { UCHAR SuspendApcFill3[KAPC_OFFSET_TO_SYSTEMARGUMENT1]; PVOID TlsArray; }; struct { UCHAR SuspendApcFill4[KAPC_OFFSET_TO_SYSTEMARGUMENT2]; PVOID BBTData; }; struct { UCHAR SuspendApcFill5[KAPC_ACTUAL_LENGTH]; UCHAR PowerState; ULONG UserTime; }; }; union { KSEMAPHORE SuspendSemaphore; struct { UCHAR SuspendSemaphorefill[KSEMAPHORE_ACTUAL_LENGTH]; ULONG SListFaultCount; }; }; LIST_ENTRY ThreadListEntry; PVOID SListFaultAddress; #if defined(_WIN64) LONG64 ReadOperationCount; LONG64 WriteOperationCount; LONG64 OtherOperationCount; LONG64 ReadTransferCount; LONG64 WriteTransferCount; LONG64 OtherTransferCount; #endif } KTHREAD, *PKTHREAD, *PRKTHREAD; #if !defined(_X86AMD64_) && defined(_AMD64_) C_ASSERT((FIELD_OFFSET(KTHREAD, ServiceTable) + 16) == FIELD_OFFSET(KTHREAD, Win32kTable)); C_ASSERT((FIELD_OFFSET(KTHREAD, ServiceTable) + 8) == FIELD_OFFSET(KTHREAD, KernelLimit)); C_ASSERT((FIELD_OFFSET(KTHREAD, Win32kTable) + 8) == FIELD_OFFSET(KTHREAD, Win32kLimit)); #endif

也就是说,在完成系统服务调用的过程中,系统内核实际使用的是SSDT地址是当前线程的PKTHREAD->ServiceTable,只要修改了这个值,也能实现SSDT Hook,并且这个值仅对当前线程有效,并不会产生全局效应,hook的隐蔽性更强。

配合内核重载,这种形式的SSDT Hook可以保护制定的线程,绕过其他程序的SSDT/Kernel Inline Hook(对于Object Hook无效)。

三、针对线程的隐蔽式SSDT Hook实现

首先实现一些辅助函数和数据结构:

Other
typedef struct _KSERVICE_TABLE_DESCRIPTOR { PULONG_PTR Base; PULONG Counter; ULONG Limit; PUCHAR Number; }KSYSTEM_SERVICE_TABLE,*PKSYSTEM_SERVICE_TABLE,**PPKSYSTEM_SERVICE_TABLE; PEPROCESS PsLookUpProcessByName(PUCHAR TragetProcessName){ PEPROCESS Process; LIST_ENTRY ProcessLinksHead; LIST_ENTRY ProcessLinks; ANSI_STRING TragetName; ANSI_STRING ProcessName; Process = PsGetCurrentProcess(); RtlInitAnsiString(&TragetName,(PCSZ)TragetProcessName); ProcessLinks = *(PLIST_ENTRY)((PUCHAR)Process + Offset_ActiveProcessLinks_KPROCESS); ProcessLinksHead = ProcessLinks; do{ RtlInitAnsiString(&ProcessName,(PCSZ)(PsGetProcessImageFileName((PEPROCESS)ProcessLinks.Flink) - Offset_ActiveProcessLinks_KPROCESS)); if(RtlEqualString(&TragetName,&ProcessName,0)){ return (PEPROCESS)RtlPointerAddOffset(ProcessLinks.Flink,- Offset_ActiveProcessLinks_KPROCESS);/*(PEPROCESS)(ProcessLinks.Flink - Offset_ActiveProcessLinks_KPROCESS);*/ } ProcessLinks = *ProcessLinks.Flink; }while(ProcessLinks.Flink != ProcessLinksHead.Flink); KdPrint(("PsLookUpProcessByName() -- Can't Find Traget Process\n")); return NULL; } PKTHREAD PsGetGUIThread(){ PEPROCESS PTragetProcess; LIST_ENTRY ThreadList; LIST_ENTRY ThreadListHead; PULONG PWin32Thread; KdPrint(("PsGetGUIThread()\n")); PTragetProcess = PsLookUpProcessByName((PUCHAR)"csrss.exe"); if(NULL == PTragetProcess){ KdPrint((" PsGetGUIThread() -- Can't Find Traget Process\n")); return NULL; } ThreadList = *(PLIST_ENTRY)((PUCHAR)PTragetProcess + Offset_ThreadListHead_KPROCESS); ThreadListHead = ThreadList; do{ PWin32Thread = (PULONG)((PUCHAR)ThreadList.Flink + (Offset_Win32Thread_KTHREAD - Offset_ThreadListEntry_KTHREAD)); if(0 != *PWin32Thread){ KdPrint(("PsGetGUIThread() -- return %x\n",(PKTHREAD)((PUCHAR)PWin32Thread - Offset_Win32Thread_KTHREAD))); return (PKTHREAD)((PUCHAR)PWin32Thread - Offset_Win32Thread_KTHREAD); } ThreadList = *ThreadList.Flink; }while(ThreadList.Flink != ThreadListHead.Flink); KdPrint(("PsGetGUIThread() -- Can't Find GUI Thread\n\n\n")); return NULL; }

重载内核并初始化SSDT:

Other
NTSTATUS KeInitSSDTData(PDRIVER_OBJECT DriverObject){ NTSTATUS Status; PKTHREAD PCUIThread; PKTHREAD PGUIThread; KdPrint(("InitSSDTData()\n")); if(SSDIF&&SDIF){ Status = STATUS_UNSUCCESSFUL; return Status; } PCUIThread = PsGetCUIThread(); PGUIThread = PsGetGUIThread(); if(!(PCUIThread && PGUIThread)){ KdPrint(("InitSSDTData() -ERROR to get threadinfo \n")); KdPrint(("PCUIThread:%x\n",PCUIThread)); KdPrint(("PGUIThread:%x\n",PGUIThread)); Status = STATUS_UNSUCCESSFUL; return Status; } Status = ReLoadNtos(DriverObject,RetAddress); if(!(NT_SUCCESS(Status))){ KdPrint(("InitSSDTData() -ERROR to reload ntos \n")); return Status; } Status = ReloadWin32K(DriverObject); if(!(NT_SUCCESS(Status))){ KdPrint(("InitSSDTData() -ERROR to reload Win32k \n")); return Status; } KdPrint(("Safe_ServiceDescriptorTable:%x \n",Safe_ServiceDescriptorTable)); __try{ PSystemSSDT = *(PPKSYSTEM_SERVICE_TABLE)((PUCHAR)PCUIThread + (Offset_ServiceTable_KTHREAD)); PSystemSSDTShadow = *(PPKSYSTEM_SERVICE_TABLE)((PUCHAR)PGUIThread + (Offset_ServiceTable_KTHREAD)); } __except(EXCEPTION_EXECUTE_HANDLER){ KdPrint(("InitSSDTData() -ERROR ACCESS_VIOLATION \n")); return STATUS_ACCESS_VIOLATION; } PSafeSSDT = (PKSYSTEM_SERVICE_TABLE)Safe_ServiceDescriptorTable; PSafeSSDTShadow = (PKSYSTEM_SERVICE_TABLE) ExAllocatePool(PagedPool,32); if(NULL == PSafeSSDTShadow){ Status = STATUS_UNSUCCESSFUL; return Status; } (*(KSYSTEM_SERVICE_TABLE(*) [])PSafeSSDTShadow)[0].Base = (*(KSYSTEM_SERVICE_TABLE(*) [])PSafeSSDT)[0].Base; (*(KSYSTEM_SERVICE_TABLE(*) [])PSafeSSDTShadow)[0].Counter = (*(KSYSTEM_SERVICE_TABLE(*) [])PSafeSSDT)[0].Counter; (*(KSYSTEM_SERVICE_TABLE(*) [])PSafeSSDTShadow)[0].Limit = (*(KSYSTEM_SERVICE_TABLE(*) [])PSafeSSDT)[0].Limit; (*(KSYSTEM_SERVICE_TABLE(*) [])PSafeSSDTShadow)[0].Number = (*(KSYSTEM_SERVICE_TABLE(*) [])PSafeSSDT)[0].Number; (*(KSYSTEM_SERVICE_TABLE(*) [])PSafeSSDTShadow)[1].Base = Safe_ServiceDescriptorShadowSSDTTable->ServiceTable; (*(KSYSTEM_SERVICE_TABLE(*) [])PSafeSSDTShadow)[1].Counter = Safe_ServiceDescriptorShadowSSDTTable->CounterTable; (*(KSYSTEM_SERVICE_TABLE(*) [])PSafeSSDTShadow)[1].Limit = Safe_ServiceDescriptorShadowSSDTTable->TableSize; (*(KSYSTEM_SERVICE_TABLE(*) [])PSafeSSDTShadow)[1].Number = Safe_ServiceDescriptorShadowSSDTTable->ArgumentTable; SSDIF = 1;//Set flag SDIF = 1;//Set flag ProcessInfo.ProcessCount = 0; ProcessInfo.ProcessListHead.Blink = (PLIST_ENTRY)&ProcessInfo; ProcessInfo.ProcessListHead.Flink = (PLIST_ENTRY)&ProcessInfo; ExInitializeFastMutex(&ProcessInfo.FastMutex); //ObvInitVirtualHandleMoudle(); Status = InitializeCommonVariables(); #ifdef DEBUGINFO KdPrint(("ProcessInfoTable:%x\n",&ProcessInfo)); #endif return STATUS_SUCCESS; }

替换PKTHREAD->ServiceTable:

Kotlin
NTSTATUS ReplaceServiceTableOfThread(PKTHREAD PTragetThread){ PULONG PWin32Thread; PULONG* PServiceTable; PWin32Thread = (PULONG)((PUCHAR)PTragetThread + Offset_Win32Thread_KTHREAD); PServiceTable = (PULONG*)((PUCHAR)PTragetThread + Offset_ServiceTable_KTHREAD); __try{ if(0 == *PWin32Thread){ //On CUIThread.Use SSDT if(0 == SDIF){ //The Date of My SSDT have not be inited return STATUS_UNSUCCESSFUL; } if(*PServiceTable != (PULONG)PSafeSSDT){ *PServiceTable = (PULONG)PSafeSSDT; } } else{ if(0 == SSDIF){ //The Date of My SSDT have not be inited return STATUS_UNSUCCESSFUL; } if(*PServiceTable != (PULONG)PSafeSSDTShadow){ *PServiceTable = (PULONG)PSafeSSDTShadow; } } } __except(EXCEPTION_EXECUTE_HANDLER){ KdPrint(("ReplaceServiceTableOfThread() -ERROR ACCESS_VIOLATION \n")); return STATUS_ACCESS_VIOLATION; } return STATUS_SUCCESS; }

处理指定进程(作为暴露给外界的接口,参数为进程名):

Other
NTSTATUS KeReplaceServiceTableOfProcessCheck(PEPROCESS TragetProcess){ NTSTATUS Status; PLIST_ENTRY NextEntry; PPROCESS_PROTECT_INFO_ENTRY PProcessInfoEntry; PVOID HandleTable; ExAcquireFastMutex(&(ProcessInfo.FastMutex)); //Check that the TragetProcess is not in the table NextEntry = ProcessInfo.ProcessListHead.Flink; while(NextEntry != (PLIST_ENTRY)&(ProcessInfo.ProcessListHead)){ PProcessInfoEntry = (PPROCESS_PROTECT_INFO_ENTRY)NextEntry; if(PProcessInfoEntry->Process == TragetProcess){ //The TragetProcess was in the table,just return success Status = STATUS_SUCCESS; goto End; } NextEntry = PProcessInfoEntry->ProcessList.Flink; } //We ture that is a new process //Now,Init process info and protect the trager process //�ڽ�����Ϣ������ӱ��� PProcessInfoEntry = (PPROCESS_PROTECT_INFO_ENTRY)ExAllocatePool(PagedPool,sizeof(PROCESS_PROTECT_INFO_ENTRY)); if(!PProcessInfoEntry){ Status = STATUS_NO_MEMORY; goto End; } Status = ObvCreateVirtualHandleTable(TragetProcess,(PPVIRTUAL_HANDLE_TABLE)&HandleTable); if(!NT_SUCCESS(Status)){ ExFreePool(PProcessInfoEntry); goto End; } PProcessInfoEntry->Process = TragetProcess; PProcessInfoEntry->HabdleTable = HandleTable; PProcessInfoEntry->ProcessList.Flink = (PLIST_ENTRY)&ProcessInfo.ProcessListHead; PProcessInfoEntry->ProcessList.Blink = (PLIST_ENTRY)ProcessInfo.ProcessListHead.Blink; ((PPROCESS_PROTECT_INFO_ENTRY)(PProcessInfoEntry->ProcessList.Blink))->ProcessList.Flink = (PLIST_ENTRY)PProcessInfoEntry; ProcessInfo.ProcessListHead.Blink = (PLIST_ENTRY)PProcessInfoEntry; ProcessInfo.ProcessCount++; //-- Status = KeReplaceServiceTableOfProcess(TragetProcess); //##########Hide Process############### // //Status = PsHideProcess(TragetProcess); //##################################### //Check that is success to replace the ServiceTable if(!NT_SUCCESS(Status)){ ProcessInfo.ProcessListHead.Blink = (PLIST_ENTRY)PProcessInfoEntry->ProcessList.Blink; ((PPROCESS_PROTECT_INFO_ENTRY)(PProcessInfoEntry->ProcessList.Blink))->ProcessList.Flink = (PLIST_ENTRY)&ProcessInfo.ProcessListHead; ExFreePool(PProcessInfoEntry); } End: ExReleaseFastMutex(&ProcessInfo.FastMutex); return Status; } NTSTATUS KeReplaceServiceTableOfProcessByName(char* ProcessName){ NTSTATUS Status = STATUS_UNSUCCESSFUL; PEPROCESS PTragetProcess = PsLookUpProcessByName((PUCHAR)ProcessName); KdPrint((" ReplaceServiceTableOfProcessByName()\n")); if(PTragetProcess == NULL){ return Status; } Status = KeReplaceServiceTableOfProcessCheck(PTragetProcess); return Status; }

进程/线程创建通知,防止冲突造成蓝屏:

Other
VOID PsCreateProcessNotify( HANDLE ParentId, HANDLE ProcessID, BOOLEAN Create) { NTSTATUS Status; PEPROCESS Process; PPROCESS_PROTECT_INFO_ENTRY NextProcess; PVIRTUAL_HANDLE_TABLE HandleTable; ANSI_STRING ProcessName; Status = PsLookupProcessByProcessId(ProcessID,&Process); if(!NT_SUCCESS(Status)){//PID->PEPROCESS return; } //RObfDereferenceObjectSafe(Process); ObDereferenceObject(Process); if(!Create){ //���̹ر�֪ͨ //�������Ƿ�Ϊ�ܱ������̣������ͷ���Ӧ��Դ ExAcquireFastMutex(&(ProcessInfo.FastMutex)); NextProcess = (PPROCESS_PROTECT_INFO_ENTRY)ProcessInfo.ProcessListHead.Flink; while(NextProcess != (PPROCESS_PROTECT_INFO_ENTRY)&ProcessInfo.ProcessListHead){ if(NextProcess->Process == Process){ HandleTable = (PVIRTUAL_HANDLE_TABLE)NextProcess->HabdleTable; //����վ����ָ�� NextProcess->HabdleTable = NULL; Status = ObvFreeVirtualHandleTable(HandleTable); (NextProcess->ProcessList.Flink)->Blink = (NextProcess->ProcessList.Blink); (NextProcess->ProcessList.Blink)->Flink = (NextProcess->ProcessList.Flink); ProcessInfo.ProcessCount--; ExFreePool(NextProcess); //�Ѿ��ͷŵ��ˣ�ֱ���ͷ��� + ���� //�����غ������Ϊδ֪�� ExReleaseFastMutex(&ProcessInfo.FastMutex); return; } NextProcess = (PPROCESS_PROTECT_INFO_ENTRY)NextProcess->ProcessList.Flink; } ExReleaseFastMutex(&ProcessInfo.FastMutex); } /* else if(FocusOn){ RtlInitAnsiString(&ProcessName,(PCSZ)(PsGetProcessImageFileName(Process))); if(!strcmp(ProcessName.Buffer,(char*)ProcessSpyOn)){ KeReplaceServiceTableOfProcessCheck(Process); } }*/ return; }

四、其他部分

代码来自当年自己做的小项目,年代有点久远很多细节想不起来了,那时候编码习惯也不是很好,注释不多而且还保留了大段的废弃代码;当年写了文档但是毁于今年一场小地震造成的硬盘损毁。
伸手党没法直接拿去用,里面包含了对object hook的处理部分,下次有空再写。
当年配合简单的进程断链隐藏可以通过大部分常见的检测方法而且未被发现,代码里用了不少硬编码,如果用在用户量大的产品中,最好通过搜索实现结构偏移定位。
另外,Windows NT 6.0 64位系统下该方法失效,因为SSDT获取不再通过PKTHREAD->ServiceTable。

[修改于 6年8个月前 - 2018/09/21 12:58:33]

来自:计算机科学 / 软件综合
0
新版本公告
~~空空如也

想参与大家的讨论?现在就 登录 或者 注册

所属专业
所属分类
上级专业
同级专业
phpskycn
专家 老干部 学者 机友 笔友
文章
403
回复
4591
学术分
8
2009/03/15注册,1个月9天前活动

CV

主体类型:个人
所属领域:无
认证方式:手机号
IP归属地:未同步
插入公式
评论控制
加载中...
文号:{{pid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

笔记
{{note.content}}
{{n.user.username}}
{{fromNow(n.toc)}} {{n.status === noteStatus.disabled ? "已屏蔽" : ""}} {{n.status === noteStatus.unknown ? "正在审核" : ""}} {{n.status === noteStatus.deleted ? '已删除' : ''}}
  • 编辑
  • 删除
  • {{n.status === 'disabled' ? "解除屏蔽" : "屏蔽" }}
我也是有底线的