标签:pat def mat user 可读性 cname 版本 特定 term
注意:下面的所有案例必须使用.C结尾的文件,且必须在链接选项中加入 /INTEGRITYCHECK
选项,否则编译根本无法通过(整理修正,整合,Win10可编译并运行),内核代码相对固定,如果对内核编程不太熟的话,请不要随意修改代码,否则很容易蓝屏,大佬绕过
内核枚举进程: 进程就是活动起来的程序,每一个进程在内核里,都有一个名为 EPROCESS
的结构记录它的详细信息,其中就包括进程名,PID,PPID,进程路径等,通常在应用层枚举进程只列出所有进程的编号即可,不过在内核层需要把它的 EPROCESS 地址给列举出来。
内核枚举进程使用PspCidTable
这个未公开的函数,它能最大的好处是能得到进程的EPROCESS地址,由于是未公开的函数,所以我们需要变相的调用这个函数,通过PsLookupProcessByProcessId
函数查到进程的EPROCESS,如果PsLookupProcessByProcessId
返回失败,则证明此进程不存在,如果返回成功则把EPROCESS、PID、PPID、进程名等通过DbgPrint打印到屏幕上。
#include <ntifs.h>
NTKERNELAPI UCHAR* PsGetProcessImageFileName(IN PEPROCESS Process); //未公开的进行导出即可
NTKERNELAPI HANDLE PsGetProcessInheritedFromUniqueProcessId(IN PEPROCESS Process);//未公开进行导出
// 根据进程ID返回进程EPROCESS结构体,失败返回NULL
PEPROCESS LookupProcess(HANDLE Pid)
{
PEPROCESS eprocess = NULL;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
Status = PsLookupProcessByProcessId(Pid, &eprocess);
if (NT_SUCCESS(Status))
return eprocess;
return NULL;
}
VOID EnumProcess()
{
PEPROCESS eproc = NULL;
for (int temp = 0; temp < 100000; temp += 4)
{
eproc = LookupProcess((HANDLE)temp);
if (eproc != NULL)
{
DbgPrint("进程名: %s --> 进程PID = %d --> 父进程PPID = %d\r\n",PsGetProcessImageFileName(eproc),PsGetProcessId(eproc),
PsGetProcessInheritedFromUniqueProcessId(eproc));
ObDereferenceObject(eproc);
}
}
}
VOID UnDriver(PDRIVER_OBJECT driver)
{
DbgPrint(("Uninstall Driver Is OK \n"));
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
EnumProcess();
Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}
内核终止进程: 结束进程的标准方法就是使用ZwOpenProcess
打开进程获得句柄,然后使用ZwTerminateProcess
结束,最后使用ZwClose
关闭句柄,代码如下:
#include <ntifs.h>
NTKERNELAPI UCHAR* PsGetProcessImageFileName(IN PEPROCESS Process);
// 根据进程ID返回进程EPROCESS结构体,失败返回NULL
PEPROCESS GetProcessNameByProcessId(HANDLE pid)
{
PEPROCESS ProcessObj = NULL;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
Status = PsLookupProcessByProcessId(pid, &ProcessObj);
if (NT_SUCCESS(Status))
return ProcessObj;
return NULL;
}
// 根据ProcessName获取到进程的PID号
HANDLE GetPidByProcessName(char *ProcessName)
{
PEPROCESS pCurrentEprocess = NULL;
HANDLE pid = 0;
for (int i = 0; i < 1000000000; i += 4)
{
pCurrentEprocess = GetProcessNameByProcessId((HANDLE)i);
if (pCurrentEprocess != NULL)
{
pid = PsGetProcessId(pCurrentEprocess);
if (strstr(PsGetProcessImageFileName(pCurrentEprocess), ProcessName) != NULL)
{
ObDereferenceObject(pCurrentEprocess);
return pid;
}
ObDereferenceObject(pCurrentEprocess);
}
}
return (HANDLE)-1;
}
int KillProcess(char *ProcessName)
{
PEPROCESS pCurrentEprocess = NULL;
HANDLE pid = 0;
HANDLE Handle = NULL;
OBJECT_ATTRIBUTES obj;
CLIENT_ID cid = { 0 };
NTSTATUS Status = STATUS_UNSUCCESSFUL;
for (int i = 0; i < 10000000; i += 4)
{
pCurrentEprocess = GetProcessNameByProcessId((HANDLE)i);
if (pCurrentEprocess != NULL)
{
pid = PsGetProcessId(pCurrentEprocess);
if (strstr(PsGetProcessImageFileName(pCurrentEprocess), ProcessName) != NULL)
{
ObDereferenceObject(pCurrentEprocess);
DbgPrint("已经找到对应的PID,开始执行结束代码...");
InitializeObjectAttributes(&obj, NULL, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
cid.UniqueProcess = (HANDLE)pid;
cid.UniqueThread = 0;
Status = ZwOpenProcess(&Handle, GENERIC_ALL, &obj, &cid);
if (NT_SUCCESS(Status))
{
ZwTerminateProcess(Handle, 0);
ZwClose(Handle);
}
ZwClose(Handle);
return 0;
}
ObDereferenceObject(pCurrentEprocess);
}
}
return -1;
}
VOID UnDriver(PDRIVER_OBJECT driver)
{
DbgPrint(("Uninstall Driver Is OK \n"));
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
int Retn = 0;
Retn = KillProcess("calc.exe");
DbgPrint("结束状态: %d \n", Retn);
Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}
内核枚举线程: 内核线程的枚举与进程相似,线程中也存在一个ETHREAD结构,但在枚举线程之前需要先来枚举到指定进程的eprocess结构,然后在根据eprocess结构对指定线程进行枚举。
#include <ntddk.h>
#include <windef.h>
//声明API
NTKERNELAPI UCHAR* PsGetProcessImageFileName(IN PEPROCESS Process);
NTKERNELAPI NTSTATUS PsLookupProcessByProcessId(HANDLE Id, PEPROCESS *Process);
NTKERNELAPI NTSTATUS PsLookupThreadByThreadId(HANDLE Id, PETHREAD *Thread);
NTKERNELAPI PEPROCESS IoThreadToProcess(PETHREAD Thread);
//根据进程ID返回进程EPROCESS,失败返回NULL
PEPROCESS LookupProcess(HANDLE Pid)
{
PEPROCESS eprocess = NULL;
if (NT_SUCCESS(PsLookupProcessByProcessId(Pid, &eprocess)))
return eprocess;
else
return NULL;
}
//根据线程ID返回线程ETHREAD,失败返回NULL
PETHREAD LookupThread(HANDLE Tid)
{
PETHREAD ethread;
if (NT_SUCCESS(PsLookupThreadByThreadId(Tid, ðread)))
return ethread;
else
return NULL;
}
//枚举指定进程中的线程
VOID EnumThread(PEPROCESS Process)
{
ULONG i = 0, c = 0;
PETHREAD ethrd = NULL;
PEPROCESS eproc = NULL;
for (i = 4; i<262144; i = i + 4) // 一般来说没有超过100000的PID和TID
{
ethrd = LookupThread((HANDLE)i);
if (ethrd != NULL)
{
//获得线程所属进程
eproc = IoThreadToProcess(ethrd);
if (eproc == Process)
{
//打印出ETHREAD和TID
DbgPrint("线程: ETHREAD=%p TID=%ld\n",ethrd,(ULONG)PsGetThreadId(ethrd));
}
ObDereferenceObject(ethrd);
}
}
}
// 通过枚举的方式定位到指定的进程,这里传递一个进程名称
VOID MyEnumThread(char *ProcessName)
{
ULONG i = 0;
PEPROCESS eproc = NULL;
for (i = 4; i<100000000; i = i + 4)
{
eproc = LookupProcess((HANDLE)i);
if (eproc != NULL)
{
ObDereferenceObject(eproc);
if (strstr(PsGetProcessImageFileName(eproc), ProcessName) != NULL)
{
EnumThread(eproc); // 相等则说明是我们想要的进程,直接枚举其中的线程
}
}
}
}
VOID DriverUnload(IN PDRIVER_OBJECT DriverObject){}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
MyEnumThread("calc.exe");
DriverObject->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}
强力枚举进程模块: 枚举进程中的所有模块信息,DLL模块记录在 PEB 的 LDR 链表里,LDR 是一个双向链表,枚举链表即可,相应的卸载可使用MmUnmapViewOfSection
函数,分别传入进程的EPROCESS,DLL模块基址即可。
#include <ntddk.h>
#include <windef.h>
//声明结构体
typedef struct _KAPC_STATE
{
LIST_ENTRY ApcListHead[2];
PKPROCESS Process;
UCHAR KernelApcInProgress;
UCHAR KernelApcPending;
UCHAR UserApcPending;
} KAPC_STATE, *PKAPC_STATE;
typedef struct _LDR_DATA_TABLE_ENTRY
{
LIST_ENTRY64 InLoadOrderLinks;
LIST_ENTRY64 InMemoryOrderLinks;
LIST_ENTRY64 InInitializationOrderLinks;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
PVOID SectionPointer;
ULONG CheckSum;
PVOID LoadedImports;
PVOID EntryPointActivationContext;
PVOID PatchInformation;
LIST_ENTRY64 ForwarderLinks;
LIST_ENTRY64 ServiceTagLinks;
LIST_ENTRY64 StaticLinks;
PVOID ContextInformation;
ULONG64 OriginalBase;
LARGE_INTEGER LoadTime;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
ULONG64 LdrInPebOffset = 0x018; //peb.ldr
ULONG64 ModListInPebOffset = 0x010; //peb.ldr.InLoadOrderModuleList
//声明API
NTKERNELAPI UCHAR* PsGetProcessImageFileName(IN PEPROCESS Process);
NTKERNELAPI PPEB PsGetProcessPeb(PEPROCESS Process);
NTKERNELAPI HANDLE PsGetProcessInheritedFromUniqueProcessId(IN PEPROCESS Process);
//根据进程ID返回进程EPROCESS,失败返回NULL
PEPROCESS LookupProcess(HANDLE Pid)
{
PEPROCESS eprocess = NULL;
if (NT_SUCCESS(PsLookupProcessByProcessId(Pid, &eprocess)))
return eprocess;
else
return NULL;
}
//枚举指定进程的模块
VOID EnumModule(PEPROCESS Process)
{
SIZE_T Peb = 0;
SIZE_T Ldr = 0;
PLIST_ENTRY ModListHead = 0;
PLIST_ENTRY Module = 0;
ANSI_STRING AnsiString;
KAPC_STATE ks;
//EPROCESS地址无效则退出
if (!MmIsAddressValid(Process))
return;
//获取PEB地址
Peb = (SIZE_T)PsGetProcessPeb(Process);
//PEB地址无效则退出
if (!Peb)
return;
//依附进程
KeStackAttachProcess(Process, &ks);
__try
{
//获得LDR地址
Ldr = Peb + (SIZE_T)LdrInPebOffset;
//测试是否可读,不可读则抛出异常退出
ProbeForRead((CONST PVOID)Ldr, 8, 8);
//获得链表头
ModListHead = (PLIST_ENTRY)(*(PULONG64)Ldr + ModListInPebOffset);
//再次测试可读性
ProbeForRead((CONST PVOID)ModListHead, 8, 8);
//获得第一个模块的信息
Module = ModListHead->Flink;
while (ModListHead != Module)
{
//打印信息:基址、大小、DLL路径
DbgPrint("模块基址=%p 大小=%ld 路径=%wZ\n",(PVOID)(((PLDR_DATA_TABLE_ENTRY)Module)->DllBase),
(ULONG)(((PLDR_DATA_TABLE_ENTRY)Module)->SizeOfImage),&(((PLDR_DATA_TABLE_ENTRY)Module)->FullDllName));
Module = Module->Flink;
//测试下一个模块信息的可读性
ProbeForRead((CONST PVOID)Module, 80, 8);
}
}
__except (EXCEPTION_EXECUTE_HANDLER){;}
//取消依附进程
KeUnstackDetachProcess(&ks);
}
// 通过枚举的方式定位到指定的进程,这里传递一个进程名称
VOID MyEnumModule(char *ProcessName)
{
ULONG i = 0;
PEPROCESS eproc = NULL;
for (i = 4; i<100000000; i = i + 4)
{
eproc = LookupProcess((HANDLE)i);
if (eproc != NULL)
{
ObDereferenceObject(eproc);
if (strstr(PsGetProcessImageFileName(eproc), ProcessName) != NULL)
{
EnumModule(eproc); // 相等则说明是我们想要的进程,直接枚举其中的线程
}
}
}
}
VOID DriverUnload(IN PDRIVER_OBJECT DriverObject){}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
MyEnumModule("calc.exe");
DriverObject->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}
遍历内核加载sys驱动文件:
#include <ntddk.h>
#include <wdm.h>
typedef struct _LDR_DATA_TABLE_ENTRY {
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImages;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
union {
LIST_ENTRY HashLinks;
struct {
PVOID SectionPointer;
ULONG CheckSum;
};
};
union {
struct {
ULONG TimeDateStamp;
};
struct {
PVOID LoadedImports;
};
};
}LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
VOID DriverUnload(IN PDRIVER_OBJECT DriverObject){}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
ULONG count = 0;
NTSTATUS Status;
DriverObject->DriverUnload = DriverUnload;
PLDR_DATA_TABLE_ENTRY pLdr = NULL;
PLIST_ENTRY pListEntry = NULL;
PLIST_ENTRY pCurrentListEntry = NULL;
PLDR_DATA_TABLE_ENTRY pModule = NULL;
pLdr = (PLDR_DATA_TABLE_ENTRY)DriverObject->DriverSection;
pListEntry = pLdr->InLoadOrderLinks.Flink;
pCurrentListEntry = pListEntry->Flink;
while (pCurrentListEntry != pListEntry)
{
pModule = CONTAINING_RECORD(pCurrentListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
if (pModule->BaseDllName.Buffer != 0)
{
DbgPrint("基址:%p ---> 偏移:%p ---> 结束地址:%p---> 模块名:%wZ \r\n", pModule->DllBase, pModule->SizeOfImages - (LONGLONG)pModule->DllBase,
(LONGLONG)pModule->DllBase + pModule->SizeOfImages,pModule->BaseDllName);
}
pCurrentListEntry = pCurrentListEntry->Flink;
}
DriverObject->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}
检测进程的启动与退出可以使用 PsSetCreateProcessNotifyRoutineEx
来创建回调,当新进程产生时回调函数会被率先执行,并通过PsGetProcessImageFileName
即将PID转换为进程名,然后通过_stricmp
对比,如果发现是calc.exe
进程则拒绝执行,禁止特定服务的运行,实现代码如下:
#include <ntddk.h>
NTKERNELAPI PCHAR PsGetProcessImageFileName(PEPROCESS Process);
NTKERNELAPI NTSTATUS PsLookupProcessByProcessId(HANDLE ProcessId, PEPROCESS *Process);
PCHAR GetProcessNameByProcessId(HANDLE ProcessId)
{
NTSTATUS st = STATUS_UNSUCCESSFUL;
PEPROCESS ProcessObj = NULL;
PCHAR string = NULL;
st = PsLookupProcessByProcessId(ProcessId, &ProcessObj);
if (NT_SUCCESS(st))
{
string = PsGetProcessImageFileName(ProcessObj);
ObfDereferenceObject(ProcessObj);
}
return string;
}
VOID MyCreateProcessNotifyEx(PEPROCESS Process, HANDLE ProcessId, PPS_CREATE_NOTIFY_INFO CreateInfo)
{
char ProcName[16] = { 0 };
if (CreateInfo != NULL)
{
DbgPrint("[%ld]%s创建进程: %wZ", CreateInfo->ParentProcessId, GetProcessNameByProcessId(CreateInfo->ParentProcessId), CreateInfo->ImageFileName);
strcpy(ProcName, PsGetProcessImageFileName(Process));
if (!_stricmp(ProcName, "calc.exe"))
{
CreateInfo->CreationStatus = STATUS_UNSUCCESSFUL;
}
}
}
VOID UnDriver(PDRIVER_OBJECT driver)
{
PsSetCreateProcessNotifyRoutineEx((PCREATE_PROCESS_NOTIFY_ROUTINE_EX)MyCreateProcessNotifyEx, TRUE);
DbgPrint(("驱动卸载成功"));
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
NTSTATUS status;
status = PsSetCreateProcessNotifyRoutineEx((PCREATE_PROCESS_NOTIFY_ROUTINE_EX)MyCreateProcessNotifyEx, FALSE);
Driver->DriverUnload = UnDriver;
DbgPrint("驱动加载成功!");
return STATUS_SUCCESS;
}
而检测线程操作与检测进程差不多,检测线程需要调用PsSetCreateThreadNotifyRoutine
创建回调函数,然后就可以检测线程的创建了,具体代码如下:
#include <ntddk.h>
NTKERNELAPI PCHAR PsGetProcessImageFileName(PEPROCESS Process);
NTKERNELAPI NTSTATUS PsLookupProcessByProcessId(HANDLE ProcessId, PEPROCESS *Process);
VOID MyCreateThreadNotify(HANDLE ProcessId,HANDLE ThreadId,BOOLEAN Create)
{
if (Create)
DbgPrint("线程创建 --> PID=%ld;TID=%ld", ProcessId, ThreadId);
else
DbgPrint("线程退出 --> PID=%ld;TID=%ld", ProcessId, ThreadId);
}
VOID UnDriver(PDRIVER_OBJECT driver)
{
PsRemoveCreateThreadNotifyRoutine(MyCreateThreadNotify);
DbgPrint(("驱动卸载成功"));
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
NTSTATUS status;
status = PsSetCreateThreadNotifyRoutine(MyCreateThreadNotify);
DbgPrint("PsSetCreateThreadNotifyRoutine: %x", status);
Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}
以检测进程驱动为例,当驱动加载后,计算器就无法打开了。
监控进程对象和线程对象操作,可以使用ObRegisterCallbacks
这个内核回调函数,通过回调我们可以实现保护calc.exe进程不被关闭,具体操作从OperationInformation->Object
获得进程或线程的对象,然后再回调中判断是否是计算器,如果是就直接去掉TERMINATE_PROCESS
或TERMINATE_THREAD
权限即可。
由于X64环境中PG的限制,导致我们无法对SSDT挂钩,所以此时的ObRegisterCallbacks
函数就显得非常有用,但它只能监控进程对象和线程对象,且驱动程序必须有数字签名才能使用此函数,想要直接使用此回调函数,要么就直接交保护费,要么可以在DriverEntry开头加上一个标志即可,只要 DriverObject->DriverSection->Flags 的值是0x20就能够直接运行。
为了能够给标志赋值,我们需要手动声明_LDR_DATA_TABLE_ENTRY
这个结构体。
typedef struct _LDR_DATA_TABLE_ENTRY {
LIST_ENTRY64 InLoadOrderLinks;
LIST_ENTRY64 InMemoryOrderLinks;
LIST_ENTRY64 InInitializationOrderLinks;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
PVOID SectionPointer;
ULONG CheckSum;
PVOID LoadedImports;
PVOID EntryPointActivationContext;
PVOID PatchInformation;
LIST_ENTRY64 ForwarderLinks;
LIST_ENTRY64 ServiceTagLinks;
LIST_ENTRY64 StaticLinks;
PVOID ContextInformation;
ULONG OriginalBase;
LARGE_INTEGER LoadTime;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
接着在驱动的开头,必须是开头,加上以下四条代码,即可实现无签加载。
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
PLDR_DATA_TABLE_ENTRY ldr;
ldr = (PLDR_DATA_TABLE_ENTRY)Driver->DriverSection;
ldr->Flags |= 0x20;
Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}
附上进程监控回调的写法,网上一大堆。
#include <ntddk.h>
#include <ntstrsafe.h>
PVOID Globle_Object_Handle;
OB_PREOP_CALLBACK_STATUS MyObjectCallBack(PVOID RegistrationContext,POB_PRE_OPERATION_INFORMATION OperationInformation)
{
DbgPrint("执行了我们的回调函数...");
return STATUS_SUCCESS;
}
VOID UnDriver(PDRIVER_OBJECT driver)
{
ObUnRegisterCallbacks(Globle_Object_Handle);
DbgPrint("回调卸载完成...");
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
OB_OPERATION_REGISTRATION Base; // 回调函数结构体
OB_CALLBACK_REGISTRATION CallbackReg;
CallbackReg.RegistrationContext = NULL; // 注册上下文(你回调函数返回参数)
CallbackReg.Version = OB_FLT_REGISTRATION_VERSION; // 注册回调版本
CallbackReg.OperationRegistration = &Base;
CallbackReg.OperationRegistrationCount = 1; // 操作注册计数(下钩数量)
RtlUnicodeStringInit(&CallbackReg.Altitude, L"600000");
Base.ObjectType = PsProcessType; // 进程操作类型.此处为进程操作
Base.Operations = OB_OPERATION_HANDLE_CREATE; // 操作的类型 OB_OPERATION_HANDLE_CREATE
Base.PreOperation = MyObjectCallBack; // 你自己的回调函数
Base.PostOperation = NULL;
ObRegisterCallbacks(&CallbackReg, &Globle_Object_Handle); // 注册回调
DbgPrint("回调注册成功...");
Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}
如下代码片段,是回调函数的一种写法,网上还有其他的更多写法,但大同小异,都是这么个步骤。
PVOID Globle_Object_Handle;
NTKERNELAPI UCHAR * PsGetProcessImageFileName(PEPROCESS Process);
#define PROCESS_TERMINATE (0x001)
OB_PREOP_CALLBACK_STATUS MyObjectCallBack(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION Operation)
{
PEPROCESS pProcess = NULL;
UCHAR *ProcessName = NULL;
pProcess = (PEPROCESS)Operation->Object;
ProcessName = PsGetProcessImageFileName(pProcess);
if (Operation->Operation == OB_OPERATION_HANDLE_CREATE)
{
if (strstr(ProcessName, "calc"))
{
if ((Operation->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_TERMINATE) == 1)
{
Operation->Parameters->CreateHandleInformation.DesiredAccess = ~PROCESS_TERMINATE;
return STATUS_UNSUCCESSFUL;
}
}
}
return STATUS_SUCCESS;
}
111
标签:pat def mat user 可读性 cname 版本 特定 term
原文地址:https://www.cnblogs.com/LyShark/p/11706656.html