win进程保护 by 句柄表

如未特殊说明均在以下机器测试

Windows 7 Professional with Service Pack 1 (x86) - DVD (Chinese-Simplified)

ed2k://|file|cn_windows_7_professional_with_sp1_x86_dvd_u_677162.iso|2653276160|08F65018BD9B5BC8D77C1C7C5615A329|/

Windows 10 (business edition), version 1903 (updated June 2019) (x64) - DVD (Chinese-Simplified)

ed2k://|file|cn_windows_10_business_edition_version_1903_updated_june_2019_x64_dvd_830837d9.iso|5032351744|DFF5FF3B87D209D16ECE7543255FA573|/

下面代码仅在win7下测试

句柄表

https://bbs.kanxue.com/thread-272049.htm

全局句柄表

全局句柄表是以线程和进程id为索引

对于32位操作系统的句柄表,一项为8字节,存放内核对象地址和一些属性,每一项都是一个_HANDLE_TABLE_ENTRY结构体类型

对于全局句柄表地址如果最后为0结尾(如0x123450),则该地址就是全局句柄表(大小为4096)

如果以1结尾如(0x123451)则该地址指向一个全局句柄表的指针数组,每一个数组元素指向一个全局句柄表

2结尾递推,类似与页表这样的形式

全局句柄表地址存放在nt!PspCidTable处指向的一个nt!_HANDLE_TABLE结构体(**CID句柄表(Client ID handle table)**)

kd> dd nt!PspCidTable
83f5dd94 89001080 00000000 80000020 00000101
83f5dda4 80000328 80000024 00000000 00000000
83f5ddb4 00000000 00000000 00000000 00000113
83f5ddc4 00000000 00000000 83f0c4be 00000000
83f5ddd4 00000000 00000000 00000000 00000008
83f5dde4 00000000 83f5dde8 83f5dde8 00000000
83f5ddf4 00000000 00000000 00000000 00000000
83f5de04 00000000 807cec28 807cac28 00000000
kd> dt _handle_table 89001080
nt!_HANDLE_TABLE
+0x000 TableCode : 0x9168b001
+0x004 QuotaProcess : (null)
+0x008 UniqueProcessId : (null)
+0x00c HandleLock : _EX_PUSH_LOCK
+0x010 HandleTableList : _LIST_ENTRY [ 0x89001090 - 0x89001090 ]
+0x018 HandleContentionEvent : _EX_PUSH_LOCK
+0x01c DebugInfo : (null)
+0x020 ExtraInfoPages : 0n0
+0x024 Flags : 1
+0x024 StrictFIFO : 0y1
+0x028 FirstFreeHandle : 0xf20
+0x02c LastFreeHandleEntry : 0x89004808 _HANDLE_TABLE_ENTRY
+0x030 HandleCount : 0x20f
+0x034 NextHandleNeedingPool : 0x1000
+0x038 HandleCountHighWatermark : 0x2f4

句柄表里的项需要把后三位清零才能的到eprocess或者ethread地址(即&0xfffffff8)

通过对象头nt!_OBJECT_HEADER结构体中的TypeIndex成员来判断是进程还是线程,该成员数值是nt!ObTypeIndexTable表的索引,ObTypeIndexTable是结构体_OBJECT_TYPE,其中的Name为Process就为进程,反之

全局句柄表抹除保护进程

利用未导出函数PVOID ExpLookupHandleTableEntry(pspCidTable,id)

第一个参数为pspCidTable的位置,第二参数为句柄id

返回值为所到的_HANDLE_TABLE_ENTRY的地址

好处就是win10的句柄表是加密的,利用该函数就不用我们自己去解析和解密了

clearhandle.h

#pragma once
#include "search.h"

#include "drivercommon.h"


//0x8 bytes (sizeof)
typedef struct _HANDLE_TABLE_ENTRY {
union {
VOID* Object; //0x0
ULONG ObAttributes; //0x0
struct _HANDLE_TABLE_ENTRY_INFO* InfoTable; //0x0
ULONG Value; //0x0
};
union {
ULONG GrantedAccess; //0x4
struct {
USHORT GrantedAccessIndex; //0x4
USHORT CreatorBackTraceIndex; //0x6
};
ULONG NextFreeTableEntry; //0x4
};
}HANDLE_TABLE_ENTRY, * PHANDLE_TABLE_ENTRY;

PHANDLE_TABLE_ENTRY MyExpLookupHandleTableEntry(HANDLE id);

BOOLEAN ProtectProcess(HANDLE id);

clearhandle.c

#include "clearhandle.h"
PVOID GetPspCidTable() {
static PVOID tableAd = NULL;
if (tableAd) {
return tableAd;
}
FindCode fc[2] = { 0 };
UNICODE_STRING name = { 0 };

initFindCodeStruct(&fc[0], "FF ?? ?? 8B ?? ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B F8 85 FF", 0, +5);
initFindCodeStruct(&fc[1], "75 ?? 8B D3 E8 ?? ?? ?? ?? 84 C0 75 ??", 0x1C, 0);

RtlInitUnicodeString(&name, L"PsLookupProcessByProcessId");
PUCHAR startAd = (PUCHAR)MmGetSystemRoutineAddress(&name);

ULONG_PTR PspCidTableOffset = findAddressByCode(startAd, startAd + 0x200, fc, 2);
if (PspCidTableOffset) {
tableAd = **(PVOID**)(PspCidTableOffset);
}
return tableAd;
}
PVOID GetExpLookupHandleTableEntryAd() {
static PVOID funcAd = NULL;
if (funcAd) {
return funcAd;
}
FindCode fc[2] = { 0 };
UNICODE_STRING name = { 0 };

initFindCodeStruct(&fc[0], "FF ?? ?? 8B 4D ?? E8 ?? ?? ?? ?? 8B F0 85 F6 75 ?? EB ??", 0, +7);
initFindCodeStruct(&fc[1], "8B 4D ?? 56 E8 ?? ?? ?? ?? EB ??", 0x17, 0);

RtlInitUnicodeString(&name, L"ExEnumHandleTable");
PUCHAR startAd = (PUCHAR)MmGetSystemRoutineAddress(&name);

ULONG_PTR funcOffset = findAddressByCode(startAd, startAd + 0x400, fc, 1);
if (funcOffset) {
funcAd = (PVOID)((*(PULONG_PTR)funcOffset) + funcOffset + 4);
}
return funcAd;
}
//返回id对应的_HANDLE_TABLE_ENTRY的地址
PHANDLE_TABLE_ENTRY MyExpLookupHandleTableEntry(HANDLE id) {
//原函数第一个参数用了ecx来传递 32位只能这样模拟,第二个参数随便写 x64就不用了
typedef PVOID(__fastcall* ExpLookupHandleTableEntry)(PVOID, PVOID, HANDLE);
PVOID pspCidTable = GetPspCidTable();
ExpLookupHandleTableEntry func = (ExpLookupHandleTableEntry)GetExpLookupHandleTableEntryAd();
if (!pspCidTable || !func) {
return NULL;
}
return (PHANDLE_TABLE_ENTRY)func(pspCidTable, 0, id);
}

ULONG32 GetIdOffset() {
FindCode fc[1] = { 0 };
UNICODE_STRING name = { 0 };
#ifdef _WIN64
initFindCodeStruct(&fc[0], "48 8B ?? ?? ?? ?? ?? C3", 0, 3);
#else
initFindCodeStruct(&fc[0], "8B EC 8B 45 ?? 8B 80 ?? ?? ?? ??", 0, 7);
#endif // _WIN64
RtlInitUnicodeString(&name, L"PsGetProcessId");
PUCHAR startAd = (PUCHAR)MmGetSystemRoutineAddress(&name);
ULONG_PTR funcOffset = findAddressByCode(startAd, startAd + 0x400, fc, 1);
if (!funcOffset) {
return -1;
}
return *(PULONG32)(funcOffset);
}

BOOLEAN ClearProcessId(HANDLE id) {
PEPROCESS process = NULL;
NTSTATUS status = PsLookupProcessByProcessId(id, &process);
if (!NT_SUCCESS(status)) {
LOG("%x", status);
return FALSE;
}
ObDereferenceObject(process);
ULONG offset = GetIdOffset();
*(VOID**)((PCHAR)process + offset) = 0;
return TRUE;
}

BOOLEAN ProtectProcess(HANDLE id) {
//DbgBreakPoint();
PHANDLE_TABLE_ENTRY entry = MyExpLookupHandleTableEntry(id);
if (!entry) {
LOG("Myexplookuphandletableentry fail");
return FALSE;
}
/*
* 直接抹除entry->Value会在关闭进程时调用PspProcessDelete时蓝屏
* if ( PROCESS->UniqueProcessId && !ExDestroyHandle(0, (int *)PspCidTable, (int)PROCESS->UniqueProcessId) )
KeBugCheck(0x17u);
所以把进程id给为0就可以避免蓝屏
使用VMware测试时需要把vm的内核系统回调删除否则会蓝屏k
*/
if (!ClearProcessId(id)) {
return FALSE;
}

memset(entry, 0, sizeof(HANDLE_TABLE_ENTRY));
return TRUE;
}

image-20240619120046123

私有句柄表

句柄表位置信息存在Eprocess.ObjectTable,也是_HANDLE_TABLE结构,句柄表里项依旧是_HANDLE_TABLE_ENTRY结构 但是_HANDLE_TABLE_ENTRY结构里的Object存的是对象头_OBJECT_HEADER位置

句柄表权限问题看https://bbs.kanxue.com/thread-272049.htm

摘抄:

64位分为:

划分 含义
(56-64bit)8位 该位的前四位始终为0,后四位标志比如写成函数SetHandleInformation()函数是否设定了HANDLE_FLAG_PROTECT_FROM_CLOSE标志位,如果设定了这四位的值为0x2
(32-55bit)24位 通过获得句柄的函数得到的访问掩码,在进程中就是OpenProcess(dwDesiredAccess,BInheritHandle,dwProcessId)中的dwDesiredAccess
(3-31bit)29位 内核对象的首地址,后三位用0填充
(0-3bit)3位 分别表示三种权限句柄通用权限。

保护之句柄降权

ExEnumHandleTable来遍历所有进程私有句柄表,发现我们想保护的进程句柄相同就把他的读写权限抹除

#include "drivercommon.h"

//来自https://learn.microsoft.com/zh-cn/windows/win32/procthread/process-security-and-access-rights

#define PROCESS_VM_READ (0x0010) // winnt
#define PROCESS_VM_WRITE (0x0020) // winnt

BOOLEAN g_bWorking = FALSE;
HANDLE g_thread = NULL;
typedef struct _HANDLE_TABLE_ENTRY {
union {
VOID* Object; //0x0
ULONG ObAttributes; //0x0
struct _HANDLE_TABLE_ENTRY_INFO* InfoTable; //0x0
ULONG Value; //0x0
};
union {
ULONG GrantedAccess; //0x4
struct {
USHORT GrantedAccessIndex; //0x4
USHORT CreatorBackTraceIndex; //0x6
};
ULONG NextFreeTableEntry; //0x4
};
}HANDLE_TABLE_ENTRY, * PHANDLE_TABLE_ENTRY;

typedef BOOLEAN(NTAPI* EX_ENUMERATE_HANDLE_ROUTINE)(
IN PHANDLE_TABLE_ENTRY HandleTableEntry,
IN HANDLE Handle,
IN PVOID EnumParameter
);

BOOLEAN ExEnumHandleTable(
__in PVOID HandleTable,
__in EX_ENUMERATE_HANDLE_ROUTINE EnumHandleProcedure,
__in PVOID EnumParameter,
__out_opt PHANDLE Handle
);

BOOLEAN NTAPI enumRoutine(
IN PHANDLE_TABLE_ENTRY HandleTableEntry,
IN HANDLE Handle,
IN PVOID EnumParameter
) {
if (HandleTableEntry) {//获取到的私有句柄表项
ULONG_PTR obj = (HandleTableEntry->Value & ~7) + 0x18;//跳过对象头
if (obj == (ULONG_PTR)EnumParameter) {
HandleTableEntry->GrantedAccess &= ~(PROCESS_VM_READ | PROCESS_VM_WRITE);
}
}
return FALSE;//返回false表示没有找到,然ExEnumHandleTable继续遍历
}
PEPROCESS FindProcessByName(PWCH name) {
PEPROCESS process = NULL;
NTSTATUS status = NULL;
for (size_t i = 0; i < 0x100000; i += 4) {
status = PsLookupProcessByProcessId((HANDLE)i, &process);
if (!NT_SUCCESS(status) || !process) {
continue;
}
PUNICODE_STRING ProcessName = NULL;
status = SeLocateProcessImageName(process, &ProcessName);
if (!NT_SUCCESS(status) || !ProcessName->Length) {
ObDereferenceObject(process);
continue;
}
_wcsupr(ProcessName->Buffer);
if (wcsstr(ProcessName->Buffer, name) != 0) {
ExFreePoolWithTag(ProcessName, 0);
ObDereferenceObject(process);
LOG("%S", ProcessName->Buffer);
return process;
}
ExFreePoolWithTag(ProcessName, 0);
ObDereferenceObject(process);
}
LOG("not find");
return NULL;
}

VOID ProcessHandleResetPrivilege(PEPROCESS ep) {
PEPROCESS curprocess = NULL;
NTSTATUS status = NULL;
while (g_bWorking) {
for (size_t i = 4; i < 0x10000; i += 4) {
status = PsLookupProcessByProcessId((HANDLE)i, &curprocess);
if (!NT_SUCCESS(status)) {
continue;
}
if (PsGetProcessExitStatus(curprocess) == 0x103)
ExEnumHandleTable(*(PULONG)((PUCHAR)curprocess + 0xf4), enumRoutine, ep, NULL);
if (PsGetProcessExitStatus(curprocess) == 0x103)//有可能遍历完后进程已经结束,内存已经被释放了,进程活着的时候再dereference
ObDereferenceObject(curprocess);
}
LARGE_INTEGER tin = { 0 };
tin.QuadPart = 8 * DELAY_ONE_SECOND;
KeDelayExecutionThread(KernelMode, FALSE, &tin);
}
}

VOID DriverUnload(_In_ struct _DRIVER_OBJECT* DriverObject) {
UNREFERENCED_PARAMETER(DriverObject);
LOG("%s", __FUNCTION__);
g_bWorking = FALSE;
//ProcessHandleResetPrivilege线程可能还在运行,但是卸载后驱动空间不见了,线程访问不存在地址,蓝屏,等待或者休眠几秒即可
if (g_thread) {
LOG("wait");
ZwWaitForSingleObject(g_thread, FALSE, NULL);
ZwClose(g_thread);
}
//LARGE_INTEGER tin = { 0 };
//tin.QuadPart = -10000 * 15000;
//KeDelayExecutionThread(KernelMode, FALSE, &tin);

}
NTSTATUS DriverEntry(
__in struct _DRIVER_OBJECT* DriverObject,
__in PUNICODE_STRING RegistryPath
) {
UNREFERENCED_PARAMETER(RegistryPath);
DriverObject->DriverUnload = DriverUnload;
PEPROCESS process = FindProcessByName(L"DBGVIEW.EXE");
if (!process) {
return STATUS_UNSUCCESSFUL;
}
/*
* 测试中发现,当debugview进程关闭,但是ce没有关闭之前打开的debugview进程句柄,导致全局句柄表依旧有dbgview
* FindProcessByName依旧可以返回该句柄
*/
if (PsGetProcessExitStatus(process) != STATUS_PENDING) {
LOG("process teminaled ,but someone still own his handle");
return STATUS_UNSUCCESSFUL;
}
NTSTATUS status = PsCreateSystemThread(&g_thread, THREAD_ALL_ACCESS, NULL, NULL, NULL, ProcessHandleResetPrivilege, process);
if (!NT_SUCCESS(status)) {
return status;
}

g_bWorking = TRUE;
LOG("%s", __FUNCTION__);
return STATUS_SUCCESS;
}

效果对于ce来说就是正常显示一下后全部变???????

反保护之防止句柄降权(提权)

上面的保护遍历是通过对比私有句柄表里的eprocess是否是他的进程来的,我们可以伪造他的eprocess并进一步eprocess里的一些特征改掉(id name cr3等),用伪造的eprocess覆盖私有句柄表来逃避检测

#include "drivercommon.h"
#include <intrin.h>

PVOID g_fakeObj = NULL;
typedef struct _HANDLE_TABLE_ENTRY {
union {
VOID* Object; //0x0
ULONG ObAttributes; //0x0
struct _HANDLE_TABLE_ENTRY_INFO* InfoTable; //0x0
ULONG Value; //0x0
};
union {
ULONG GrantedAccess; //0x4
struct {
USHORT GrantedAccessIndex; //0x4
USHORT CreatorBackTraceIndex; //0x6
};
ULONG NextFreeTableEntry; //0x4
};
}HANDLE_TABLE_ENTRY, * PHANDLE_TABLE_ENTRY;

typedef BOOLEAN(NTAPI* EX_ENUMERATE_HANDLE_ROUTINE)(
IN PHANDLE_TABLE_ENTRY HandleTableEntry,
IN HANDLE Handle,
IN PVOID EnumParameter
);

BOOLEAN ExEnumHandleTable(
__in PVOID HandleTable,
__in EX_ENUMERATE_HANDLE_ROUTINE EnumHandleProcedure,
__in PVOID EnumParameter,
__out_opt PHANDLE Handle
);

BOOLEAN NTAPI enumRoutine(
IN PHANDLE_TABLE_ENTRY HandleTableEntry,
IN HANDLE Handle,
IN PVOID EnumParameter
) {
if (HandleTableEntry) {
ULONG process = (HandleTableEntry->Value & ~7) + 0x18;
if (process == (ULONG)EnumParameter) {
HandleTableEntry->Value = (ULONG)g_fakeObj | 1;
HandleTableEntry->GrantedAccess |= PROCESS_ALL_ACCESS;
}
}
return FALSE;
}

ULONG GetIdOffset() {
UNICODE_STRING name = { 0 };
RtlInitUnicodeString(&name, L"PsGetProcessId");
PUCHAR startAd = (PUCHAR)MmGetSystemRoutineAddress(&name);
return *(PULONG)(startAd + 10);
}

PEPROCESS FindProcessByName(PWCH name) {
PEPROCESS process = NULL;
NTSTATUS status = NULL;
for (size_t i = 0; i < 0x100000; i += 4) {
status = PsLookupProcessByProcessId((HANDLE)i, &process);
if (!NT_SUCCESS(status) || !process) {
continue;
}
PUNICODE_STRING ProcessName = NULL;
status = SeLocateProcessImageName(process, &ProcessName);
if (!NT_SUCCESS(status) || !ProcessName->Length) {
ObDereferenceObject(process);
continue;
}
_wcsupr(ProcessName->Buffer);
if (wcsstr(ProcessName->Buffer, name) != 0) {
ExFreePoolWithTag(ProcessName, 0);
ObDereferenceObject(process);
LOG("%S", ProcessName->Buffer);
return process;
}
ExFreePoolWithTag(ProcessName, 0);
ObDereferenceObject(process);
}
LOG("not find");
return NULL;
}

VOID DriverUnload(_In_ struct _DRIVER_OBJECT* DriverObject) {
UNREFERENCED_PARAMETER(DriverObject);
LOG("%s", __FUNCTION__);
}
NTSTATUS DriverEntry(
__in struct _DRIVER_OBJECT* DriverObject,
__in PUNICODE_STRING RegistryPath
) {
UNREFERENCED_PARAMETER(RegistryPath);

PEPROCESS targetProcess = FindProcessByName(L"DBGVIEW.EXE");
if (!targetProcess) {
return STATUS_UNSUCCESSFUL;
}
PVOID targetObj = (PUCHAR)targetProcess - 0x18;
//伪造obj内存
//TODO:什么时候释放内存
g_fakeObj = ExAllocatePool(NonPagedPool, PAGE_SIZE);
if (!g_fakeObj) {
return STATUS_UNSUCCESSFUL;
}
PUCHAR fakeProcess = (PUCHAR)g_fakeObj + 0x18;

memset(g_fakeObj, 0, PAGE_SIZE);
memcpy(g_fakeObj, targetObj, 0x350);

//抹除id
*(PHANDLE)((PUCHAR)fakeProcess + GetIdOffset()) = 0;

//伪造cr3
ULONG_PTR cr4 = __readcr4();
ULONG srcCr3 = *(PULONG)((PUCHAR)targetProcess + 0x18);

PVOID fakeCr3 = ExAllocatePool(NonPagedPool, PAGE_SIZE);
if (NULL == fakeCr3) {
ExFreePool(g_fakeObj);
return STATUS_UNSUCCESSFUL;
}
memset(fakeCr3, 0, PAGE_SIZE);
int size = PAGE_SIZE; //10 10 12分页

if (cr4 & (0x20)) {//2 9 9 12分页
size = 4 * 8;
}
PHYSICAL_ADDRESS phySrcCr3 = { 0 };
phySrcCr3.QuadPart = srcCr3;
// WIN10 1803以上,不能映射页表
//有弊端 如果是小页。在一次映射多页时候 不一定成功,如果是大页一次映射2M 或者4M 必须是页开头,跨页就有问题
PVOID virtualCr3 = MmMapIoSpace(phySrcCr3, size, MmNonCached);
memcpy(fakeCr3, virtualCr3, size);
//如果不替换CR3 进程退出,或者在某些API的情况会卡死,蓝屏
PHYSICAL_ADDRESS phyFakeCr3 = MmGetPhysicalAddress(fakeCr3);

*(PULONG)((PUCHAR)fakeProcess + 0x18) = phyFakeCr3.QuadPart;

//遍历ce进程私有句柄表替换对象提权
PEPROCESS hackProcess = FindProcessByName(L"CHEATENGINE-I386.EXE");

if (NULL == hackProcess) {
ExFreePool(g_fakeObj);
ExFreePool(fakeCr3);
return STATUS_UNSUCCESSFUL;
}
ExEnumHandleTable(*(PULONG_PTR)((PUCHAR)hackProcess + 0xf4), enumRoutine, targetProcess, NULL);
/*
当前线程附加到目标进程的地址空间
KAPC_STATE kapcState = { 0 };
KeStackAttachProcess(process, &kapcState);
LONG_PTR cr3 = __readcr3();
KeUnstackDetachProcess(&kapcState);
*/
DriverObject->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}

句柄回调保护

ObRegisterCallbacks注册回调拦截对句柄的操作,进行降权处理

仅在win10下测试

ExportFunc.h

#pragma once
#include <ntifs.h>
NTSTATUS MmCopyVirtualMemory(
IN PEPROCESS FromProcess,
IN CONST VOID* FromAddress,
IN PEPROCESS ToProcess,
OUT PVOID ToAddress,
IN SIZE_T BufferSize,
IN KPROCESSOR_MODE PreviousMode,
OUT PSIZE_T NumberOfBytesCopied
);
PPEB PsGetProcessPeb(__in PEPROCESS Process);
PVOID PsGetCurrentProcessWow64Process();

EXTERN_C void* NTAPI PsGetProcessWow64Process(PEPROCESS Process);


EXTERN_C void* NTAPI PsGetThreadTeb(PETHREAD Thread);

protect.h

#pragma once
#include "../drivercommon.h"
#include "../ExportFunc.h"
NTSTATUS InitObRegister();
VOID DestoryObRegister();

NTSTATUS InitObRegisterUnProtect();
VOID DestoryObRegisterUnprotect();

NTSTATUS SetProtectPid(HANDLE pid);
NTSTATUS UnProtectPid(HANDLE pid);

protect.c

#include "protect.h"
#include "../SearchCode.h"
HANDLE gRegProtectHandle = NULL;
HANDLE gProtectId=-1;

HANDLE gRegUnProtectHandle = NULL;
HANDLE gUnProtectId = -1;
OB_PREOP_CALLBACK_STATUS PobPreOperationCallbackProtect(
PVOID RegistrationContext,
POB_PRE_OPERATION_INFORMATION OperationInformation
) {

if (-1== gProtectId) {
return OB_PREOP_SUCCESS;
}
PEPROCESS Process = OperationInformation->Object;
if (!Process) return OB_PREOP_SUCCESS;

HANDLE currentPid = PsGetCurrentProcessId();

HANDLE targetPid = PsGetProcessId(Process);

if (currentPid == gProtectId) return OB_PREOP_SUCCESS;

if (targetPid != gProtectId) return OB_PREOP_SUCCESS;
LOG("protect targetpid:%x\r\n", targetPid);

//DbgBreakPoint();

if (OperationInformation->Operation == OB_OPERATION_HANDLE_CREATE) {
OperationInformation->Parameters->CreateHandleInformation.DesiredAccess = 0;
OperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess = 0;
}
else {

OperationInformation->Parameters->DuplicateHandleInformation.DesiredAccess = 0;
OperationInformation->Parameters->DuplicateHandleInformation.OriginalDesiredAccess = 0;
}

return OB_PREOP_SUCCESS;

}

OB_PREOP_CALLBACK_STATUS PobPreOperationCallbackUnProtect(
PVOID RegistrationContext,
POB_PRE_OPERATION_INFORMATION OperationInformation
) {
if (-1 == gUnProtectId) {
return OB_PREOP_SUCCESS;
}
PEPROCESS Process = OperationInformation->Object;
if (!Process) return OB_PREOP_SUCCESS;

HANDLE currentPid = PsGetCurrentProcessId();

HANDLE targetPid = PsGetProcessId(Process);

if (currentPid == gUnProtectId) return OB_PREOP_SUCCESS;

if (targetPid != gUnProtectId) return OB_PREOP_SUCCESS;
LOG("unprotect targetpid:%x\r\n",targetPid);
//DbgBreakPoint();

if (OperationInformation->Operation == OB_OPERATION_HANDLE_CREATE) {
OperationInformation->Parameters->CreateHandleInformation.DesiredAccess = PROCESS_ALL_ACCESS;
OperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess = PROCESS_ALL_ACCESS;
}
else {

OperationInformation->Parameters->DuplicateHandleInformation.DesiredAccess = PROCESS_ALL_ACCESS;
OperationInformation->Parameters->DuplicateHandleInformation.OriginalDesiredAccess = PROCESS_ALL_ACCESS;
}

return OB_PREOP_SUCCESS;
}
NTSTATUS InitObRegister() {
//未兼容win7
NTSTATUS status = STATUS_UNSUCCESSFUL;
//MmVerifyCallbackFunctionCheckFlags地址
ULONG_PTR MmVerifyCallbackFunctionCheckFlagsAd = searchCode("ntoskrnl.exe", ".text", "48 ?? ?? ?? ?? ?? ?? E8 ?? ?? ?? ?? 33 D2 48 8B CE E8 ?? ?? ?? ?? 48 85 C0 74 ?? 85 FF 74 ??", -0x37);
if (!MmVerifyCallbackFunctionCheckFlagsAd) {
return STATUS_UNSUCCESSFUL;
}
ULONG64 jmpRcx = searchCode("ntoskrnl.exe", ".text", "FFE1", 0);

if (!jmpRcx)
return STATUS_UNSUCCESSFUL;
OB_OPERATION_REGISTRATION operationRegRation = { 0 };
operationRegRation.ObjectType = PsProcessType;
operationRegRation.Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;
operationRegRation.PreOperation = jmpRcx;

OB_CALLBACK_REGISTRATION callBackRegRation = { 0 };
callBackRegRation.Version = ObGetFilterVersion();
callBackRegRation.OperationRegistrationCount = 1;
RtlInitUnicodeString(&callBackRegRation.Altitude, L"456340");
callBackRegRation.RegistrationContext = PobPreOperationCallbackProtect;
callBackRegRation.OperationRegistration = &operationRegRation;

//patch
UCHAR bufCode[10] = { 0 };
//66 B8 01 00
UCHAR patch[] = { 0xB8 ,0x01,0x00 ,0x00 ,0x00 ,0x90,0xc3};
PHYSICAL_ADDRESS phyAddress = MmGetPhysicalAddress(MmVerifyCallbackFunctionCheckFlagsAd);
if (!phyAddress.QuadPart) {
return STATUS_UNSUCCESSFUL;
}

PVOID mapMmVerifyCallbackFunctionCheckFlagsAd = MmMapIoSpace(phyAddress, 10, MmNonCached);

if (!mapMmVerifyCallbackFunctionCheckFlagsAd) {
return STATUS_UNSUCCESSFUL;
}

memcpy(bufCode, mapMmVerifyCallbackFunctionCheckFlagsAd, 10);

memcpy(mapMmVerifyCallbackFunctionCheckFlagsAd, patch, sizeof(patch));
status = ObRegisterCallbacks(&callBackRegRation, &gRegProtectHandle);

//恢复patch
memcpy(mapMmVerifyCallbackFunctionCheckFlagsAd, bufCode, 10);
return status;
}
VOID DestoryObRegister() {
if (gRegProtectHandle)
ObUnRegisterCallbacks(gRegProtectHandle);
}
NTSTATUS SetProtectPid(HANDLE pid) {
NTSTATUS status;
//DbgBreakPoint();
if (!gRegProtectHandle) {
status = InitObRegister();
}
else {
status = STATUS_SUCCESS;
}
//DbgBreakPoint();
if (NT_SUCCESS(status)) {
LOG("sucess protect");
gProtectId = pid;
}
else {
LOG("fail %x",status);
}
return status;
}

NTSTATUS InitObRegisterUnProtect() {
NTSTATUS status = STATUS_UNSUCCESSFUL;
//MmVerifyCallbackFunctionCheckFlags地址
ULONG_PTR MmVerifyCallbackFunctionCheckFlagsAd = searchCode("ntoskrnl.exe", ".text", "48 ?? ?? ?? ?? ?? ?? E8 ?? ?? ?? ?? 33 D2 48 8B CE E8 ?? ?? ?? ?? 48 85 C0 74 ?? 85 FF 74 ??", -0x37);
if (!MmVerifyCallbackFunctionCheckFlagsAd) {
return STATUS_UNSUCCESSFUL;
}
ULONG64 jmpRcx = searchCode("ntoskrnl.exe", ".text", "FFE1", 0);

if (!jmpRcx)
return STATUS_UNSUCCESSFUL;
OB_OPERATION_REGISTRATION operationRegRation = { 0 };
operationRegRation.ObjectType = PsProcessType;
operationRegRation.Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;
operationRegRation.PreOperation = jmpRcx;

OB_CALLBACK_REGISTRATION callBackRegRation = { 0 };
callBackRegRation.Version = ObGetFilterVersion();
callBackRegRation.OperationRegistrationCount = 1;
RtlInitUnicodeString(&callBackRegRation.Altitude, L"456100");
callBackRegRation.RegistrationContext = PobPreOperationCallbackUnProtect;
callBackRegRation.OperationRegistration = &operationRegRation;

//patch
UCHAR bufCode[10] = { 0 };
//66 B8 01 00
UCHAR patch[] = { 0xB8 ,0x01,0x00 ,0x00 ,0x00 ,0x90,0xc3 };
PHYSICAL_ADDRESS phyAddress = MmGetPhysicalAddress(MmVerifyCallbackFunctionCheckFlagsAd);
if (!phyAddress.QuadPart) {
return STATUS_UNSUCCESSFUL;
}

PVOID mapMmVerifyCallbackFunctionCheckFlagsAd = MmMapIoSpace(phyAddress, 10, MmNonCached);

if (!mapMmVerifyCallbackFunctionCheckFlagsAd) {
return STATUS_UNSUCCESSFUL;
}

memcpy(bufCode, mapMmVerifyCallbackFunctionCheckFlagsAd, 10);

memcpy(mapMmVerifyCallbackFunctionCheckFlagsAd, patch, sizeof(patch));
status = ObRegisterCallbacks(&callBackRegRation, &gRegUnProtectHandle);

//恢复patch
memcpy(mapMmVerifyCallbackFunctionCheckFlagsAd, bufCode, 10);
return status;
}
VOID DestoryObRegisterUnprotect() {
if (gRegUnProtectHandle)
ObUnRegisterCallbacks(gRegUnProtectHandle);
}

NTSTATUS UnProtectPid(HANDLE pid) {
NTSTATUS status;
//DbgBreakPoint();
if (!gRegUnProtectHandle) {
status = InitObRegisterUnProtect();
}
else {
status = STATUS_SUCCESS;
}
//DbgBreakPoint();
if (NT_SUCCESS(status)) {
LOG("sucess unprotect");
gUnProtectId = pid;
}
else {
LOG("fail %x", status);
}
return status;
}