X64驱动:内核里操作进程

注意:下面的所有案例必须使用.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, &ethread)))
        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_PROCESSTERMINATE_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

原文地址:https://www.cnblogs.com/LyShark/p/11706656.html

时间: 2024-10-12 13:36:34

X64驱动:内核里操作进程的相关文章

内核里操作进程

 在内核里操作进程 在内核里操作进程,相信是很多对 WINDOWS 内核编程感兴趣的朋友第一个学习的知识点.但在这里,我要让大家失望了,在内核里操作进程没什么特别的,就标准方法而言,还是调用那几个和进程相关的 NATIVE API 而已(当然了,本文所说的进程操作,还包括对线程和 DLL 模块的操作).本文包括 10 个部分:分别是:枚举进程.暂停进程.恢复进程.结束进程.枚举线程.暂停线程.恢复线程.结束线程.枚举 DLL 模块.卸载 DLL 模块. 1.枚举进程.进程就是活动起来的程序.每一

windows内核代码之进程操作

[toc] 一丶简介 整理一下windows内核中.常用的代码.这里只整理下进程的相关代码. 二丶 windows内核之遍历进程 内核中记录进程的结构体是EPROCESS结构.所以只需要遍历这个结构即可.标准方法可以使用ZwQuerySystemInformation函数.使用SystemProcessInformation功能号. 另外也有很多种枚举进程的方法比如找到EPROCESS结构进行枚举的.(CPU结构体 KPCR)等等.不过兼容性都是不太好.另一种方法是枚举句柄表 PspCidTab

linux驱动current,引用当前进程,及task_struct(转)

尽管内核模块不象应用程序一样顺序执行, 内核做的大部分动作是代表一个特定进程的. 内核代码可以引用当前进程, 通过存取全局项 current, 它在 <asm/current.h> 中定义, 它产生一个指针指向结构 task_struct, 在 <Linux/sched.h> 定义. current 指针指向当前在运行的进程. 在一个系统调用执行期间, 例如 open 或者 read, 当前进程是发出调用的进程. 内核代码可以通过使用 current 来使用进程特定的信息, 如果它

Linux内核剖析 之 进程简介

1.概念 1.1  什么是进程? 进程是程序执行的一个实例,可以看作充分描述程序已经执行到何种程度的数据结构的汇集. 从内核观点看,进程的目的就是担当分配系统资源(CPU时间,内存等)的实体. 我们熟悉的fork()库函数,它有两种用法: (1).一个父进程希望复制自己,使父子进程执行不同的代码段,常用于网络服务程序. (2).一个进程要执行一个不同的程序,fork()后立即exec(),如shell. 1.2  什么是线程? 有时候,一个进程希望有多个执行流,如一款麻将游戏,三个由电脑控制的人

Windows内核原理研究——进程创建

进程可能是用户接触的Windows系统中最多的部分了,对于Windows系统而言,进程是一个独立的地址空间可以为线程提供一个独立的执行环境, 也就是说 进程= 独立的地址空间 一个进程内核对象 线程= 一个线程自己的栈 一个线程内核对象 当然这个栈是在进程的地址空间中.那么,也就是说线程才是真正“干活”的东西,进程只不过是一些资源的集合而已.只能说是“原材料”. 在我学习Windows内核以前一直觉得进程的种种特性很神奇,比如说地址空间独立是怎么实现的呢?我们的电脑使用的都是同一块内存怎么能实现

Linux内核剖析 之 进程简单介绍

1.概念 1.1  什么是进程? 进程是程序运行的一个实例.能够看作充分描写叙述程序已经运行到何种程度的数据结构的汇集. 从内核观点看.进程的目的就是担当分配系统资源(CPU时间,内存等)的实体. 我们熟悉的fork()库函数,它有两种使用方法: (1).一个父进程希望复制自己,使父子进程运行不同的代码段.经常使用于网络服务程序. (2).一个进程要运行一个不同的程序,fork()后马上exec(),如shell. 1.2  什么是线程? 有时候,一个进程希望有多个运行流,如一款麻将游戏,三个由

linux内核分析之进程地址空间【转】

转自:http://blog.csdn.net/bullbat/article/details/7106094 版权声明:本文为博主原创文章,未经博主允许不得转载. 本文主要介绍linux内核中进程地址空间的数据结构描述,包括mm_struct/vm_area_struct.进程线性地址区间的分配流程,并对相应的源代码做了注释. 内核中的函数以相当直接了当的方式获得动态内存.当给用户态进程分配内存时,情况完全不同了.进程对动态内存的请求被认为是不紧迫的,一般来说,内核总是尽量推迟给用户态进程分配

【转载】linux内核笔记之进程地址空间

原文:linux内核笔记之进程地址空间 进程的地址空间由允许进程使用的全部线性地址组成,在32位系统中为0~3GB,每个进程看到的线性地址集合是不同的. 内核通过线性区的资源(数据结构)来表示线性地址区间,线性区是由起始线性地址,长度和一些访问权限来描述的.线性区的大小为页框的整数倍,起始地址为4096的整数倍. 下图展示了x86 Linux 进程的地址空间组织结构: 正文段 .text ,这是CPU执行的机器指令部分.通常正文段是共享的,而且是只读的,以防止程序修改其自身的指令. 数据段 .d

用户空间与内核空间,进程上下文与中断上下文[总结]

用户空间与内核空间,进程上下文与中断上下文[总结] 最近有研究到zabbix监控,就得清楚cpu各个指标的含义, 1,简单回顾下cpu及计算机组成: 计算机五大部件: 运算器 控制器 存储器 输入/输出设备. 2,cpu 进程的内核态和用户态 我们知道现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32次方).操心系统的核心是内核,独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件设备的所有权限.为 了保证用户进程不能直接操作内核,