• 5.4 Windows驱动开发:内核通过PEB取进程参数


    PEB结构(Process Envirorment Block Structure)其中文名是进程环境块信息,进程环境块内部包含了进程运行的详细参数信息,每一个进程在运行后都会存在一个特有的PEB结构,通过附加进程并遍历这段结构即可得到非常多的有用信息。

    在应用层下,如果想要得到PEB的基地址只需要取fs:[0x30]即可,TEB线程环境块则是fs:[0x18],如果在内核层想要得到应用层进程的PEB信息我们需要调用特定的内核函数来获取。

    在内核层要获取应用层进程的PEB结构,可以通过以下步骤实现:

    • 1.调用内核函数PsGetCurrentProcess获取当前进程的EPROCESS结构。
    • 2.调用内核函数KeStackAttachProcess,附加到目标进程。
    • 3.调用内核函数PsGetProcessWow64Process,获取目标进程的PEB结构信息。
    • 4.通过PEB结构的Ldr成员可以访问到该进程加载的所有模块,遍历整个Ldr链表即可得到需要的模块信息。
    • 5.遍历完成后,通过调用KeUnstackDetachProcess函数脱离进程空间。

    首先在开始写代码之前需要先定义好PEB进程环境快结构体,用于对内存指针解析,新建peb.h文件并保存如下代码,这些是微软的结构定义分为32位与64位,官方定义规范而已不需要费工夫。

    #pragma once
    #include 
    
    typedef struct _CURDIR              // 2 elements, 0x18 bytes (sizeof) 
    {
        /*0x000*/     struct _UNICODE_STRING DosPath; // 3 elements, 0x10 bytes (sizeof) 
        /*0x010*/     VOID*        Handle;
    }CURDIR, *PCURDIR;
    
    typedef struct _RTL_DRIVE_LETTER_CURDIR // 4 elements, 0x18 bytes (sizeof) 
    {
        /*0x000*/     UINT16       Flags;
        /*0x002*/     UINT16       Length;
        /*0x004*/     ULONG32      TimeStamp;
        /*0x008*/     struct _STRING DosPath;             // 3 elements, 0x10 bytes (sizeof) 
    }RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR;
    
    typedef enum _SYSTEM_DLL_TYPE  // 7 elements, 0x4 bytes
    {
        PsNativeSystemDll = 0 /*0x0*/,
        PsWowX86SystemDll = 1 /*0x1*/,
        PsWowArm32SystemDll = 2 /*0x2*/,
        PsWowAmd64SystemDll = 3 /*0x3*/,
        PsWowChpeX86SystemDll = 4 /*0x4*/,
        PsVsmEnclaveRuntimeDll = 5 /*0x5*/,
        PsSystemDllTotalTypes = 6 /*0x6*/
    }SYSTEM_DLL_TYPE, *PSYSTEM_DLL_TYPE;
    
    typedef struct _EWOW64PROCESS        // 3 elements, 0x10 bytes (sizeof) 
    {
        /*0x000*/     VOID*        Peb;
        /*0x008*/     UINT16       Machine;
        /*0x00A*/     UINT8        _PADDING0_[0x2];
        /*0x00C*/     enum _SYSTEM_DLL_TYPE NtdllType;
    }EWOW64PROCESS, *PEWOW64PROCESS;
    
    typedef struct _RTL_USER_PROCESS_PARAMETERS                // 37 elements, 0x440 bytes (sizeof) 
    {
        /*0x000*/     ULONG32      MaximumLength;
        /*0x004*/     ULONG32      Length;
        /*0x008*/     ULONG32      Flags;
        /*0x00C*/     ULONG32      DebugFlags;
        /*0x010*/     VOID*        ConsoleHandle;
        /*0x018*/     ULONG32      ConsoleFlags;
        /*0x01C*/     UINT8        _PADDING0_[0x4];
        /*0x020*/     VOID*        StandardInput;
        /*0x028*/     VOID*        StandardOutput;
        /*0x030*/     VOID*        StandardError;
        /*0x038*/     struct _CURDIR CurrentDirectory;                       // 2 elements, 0x18 bytes (sizeof)   
        /*0x050*/     struct _UNICODE_STRING DllPath;                        // 3 elements, 0x10 bytes (sizeof)   
        /*0x060*/     struct _UNICODE_STRING ImagePathName;                  // 3 elements, 0x10 bytes (sizeof)   
        /*0x070*/     struct _UNICODE_STRING CommandLine;                    // 3 elements, 0x10 bytes (sizeof)   
        /*0x080*/     VOID*        Environment;
        /*0x088*/     ULONG32      StartingX;
        /*0x08C*/     ULONG32      StartingY;
        /*0x090*/     ULONG32      CountX;
        /*0x094*/     ULONG32      CountY;
        /*0x098*/     ULONG32      CountCharsX;
        /*0x09C*/     ULONG32      CountCharsY;
        /*0x0A0*/     ULONG32      FillAttribute;
        /*0x0A4*/     ULONG32      WindowFlags;
        /*0x0A8*/     ULONG32      ShowWindowFlags;
        /*0x0AC*/     UINT8        _PADDING1_[0x4];
        /*0x0B0*/     struct _UNICODE_STRING WindowTitle;                    // 3 elements, 0x10 bytes (sizeof)   
        /*0x0C0*/     struct _UNICODE_STRING DesktopInfo;                    // 3 elements, 0x10 bytes (sizeof)   
        /*0x0D0*/     struct _UNICODE_STRING ShellInfo;                      // 3 elements, 0x10 bytes (sizeof)   
        /*0x0E0*/     struct _UNICODE_STRING RuntimeData;                    // 3 elements, 0x10 bytes (sizeof)   
        /*0x0F0*/     struct _RTL_DRIVE_LETTER_CURDIR CurrentDirectores[32];
        /*0x3F0*/     UINT64       EnvironmentSize;
        /*0x3F8*/     UINT64       EnvironmentVersion;
        /*0x400*/     VOID*        PackageDependencyData;
        /*0x408*/     ULONG32      ProcessGroupId;
        /*0x40C*/     ULONG32      LoaderThreads;
        /*0x410*/     struct _UNICODE_STRING RedirectionDllName;             // 3 elements, 0x10 bytes (sizeof)   
        /*0x420*/     struct _UNICODE_STRING HeapPartitionName;              // 3 elements, 0x10 bytes (sizeof)   
        /*0x430*/     UINT64*      DefaultThreadpoolCpuSetMasks;
        /*0x438*/     ULONG32      DefaultThreadpoolCpuSetMaskCount;
        /*0x43C*/     UINT8        _PADDING2_[0x4];
    }RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;
    
    typedef struct _PEB_LDR_DATA                            // 9 elements, 0x58 bytes (sizeof) 
    {
        /*0x000*/     ULONG32      Length;
        /*0x004*/     UINT8        Initialized;
        /*0x005*/     UINT8        _PADDING0_[0x3];
        /*0x008*/     VOID*        SsHandle;
        /*0x010*/     struct _LIST_ENTRY InLoadOrderModuleList;           // 2 elements, 0x10 bytes (sizeof) 
        /*0x020*/     struct _LIST_ENTRY InMemoryOrderModuleList;         // 2 elements, 0x10 bytes (sizeof) 
        /*0x030*/     struct _LIST_ENTRY InInitializationOrderModuleList; // 2 elements, 0x10 bytes (sizeof) 
        /*0x040*/     VOID*        EntryInProgress;
        /*0x048*/     UINT8        ShutdownInProgress;
        /*0x049*/     UINT8        _PADDING1_[0x7];
        /*0x050*/     VOID*        ShutdownThreadId;
    }PEB_LDR_DATA, *PPEB_LDR_DATA;
    
    typedef struct _PEB64
    {
        UCHAR InheritedAddressSpace;
        UCHAR ReadImageFileExecOptions;
        UCHAR BeingDebugged;
        UCHAR BitField;
        ULONG64 Mutant;
        ULONG64 ImageBaseAddress;
        PPEB_LDR_DATA Ldr;
        PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
        ULONG64 SubSystemData;
        ULONG64 ProcessHeap;
        ULONG64 FastPebLock;
        ULONG64 AtlThunkSListPtr;
        ULONG64 IFEOKey;
        ULONG64 CrossProcessFlags;
        ULONG64 UserSharedInfoPtr;
        ULONG SystemReserved;
        ULONG AtlThunkSListPtr32;
        ULONG64 ApiSetMap;
    } PEB64, *PPEB64;
    
    #pragma pack(4)
    typedef struct _PEB32
    {
        UCHAR InheritedAddressSpace;
        UCHAR ReadImageFileExecOptions;
        UCHAR BeingDebugged;
        UCHAR BitField;
        ULONG Mutant;
        ULONG ImageBaseAddress;
        ULONG Ldr;
        ULONG ProcessParameters;
        ULONG SubSystemData;
        ULONG ProcessHeap;
        ULONG FastPebLock;
        ULONG AtlThunkSListPtr;
        ULONG IFEOKey;
        ULONG CrossProcessFlags;
        ULONG UserSharedInfoPtr;
        ULONG SystemReserved;
        ULONG AtlThunkSListPtr32;
        ULONG ApiSetMap;
    } PEB32, *PPEB32;
    
    typedef struct _PEB_LDR_DATA32
    {
        ULONG Length;
        BOOLEAN Initialized;
        ULONG SsHandle;
        LIST_ENTRY32 InLoadOrderModuleList;
        LIST_ENTRY32 InMemoryOrderModuleList;
        LIST_ENTRY32 InInitializationOrderModuleList;
        ULONG EntryInProgress;
    } PEB_LDR_DATA32, *PPEB_LDR_DATA32;
    
    typedef struct _LDR_DATA_TABLE_ENTRY32
    {
        LIST_ENTRY32 InLoadOrderLinks;
        LIST_ENTRY32 InMemoryOrderModuleList;
        LIST_ENTRY32 InInitializationOrderModuleList;
        ULONG DllBase;
        ULONG EntryPoint;
        ULONG SizeOfImage;
        UNICODE_STRING32 FullDllName;
        UNICODE_STRING32 BaseDllName;
        ULONG Flags;
        USHORT LoadCount;
        USHORT TlsIndex;
        union
        {
            LIST_ENTRY32 HashLinks;
            ULONG SectionPointer;
        }u1;
        ULONG CheckSum;
        union
        {
            ULONG TimeDateStamp;
            ULONG LoadedImports;
        }u2;
        ULONG EntryPointActivationContext;
        ULONG PatchInformation;
    } LDR_DATA_TABLE_ENTRY32, *PLDR_DATA_TABLE_ENTRY32;
    
    #pragma pack()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180

    接着就来实现对PEB的获取操作,以64位为例,我们需要调用PsGetProcessPeb()这个内核函数,因为该内核函数没有被公开所以调用之前需要头部导出,该函数需要传入用户进程的EProcess结构,该结构可用PsLookupProcessByProcessId函数动态获取到,获取到以后直接KeStackAttachProcess()附加到应用层进程上,即可直接输出进程的PEB结构信息,如下代码。

    #include "peb.h"
    #include 
    
    // 定义导出
    NTKERNELAPI PVOID NTAPI PsGetProcessPeb(_In_ PEPROCESS Process);
    
    VOID UnDriver(PDRIVER_OBJECT driver)
    {
        DbgPrint(("Uninstall Driver Is OK \n"));
    }
    // LyShark
    NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
    {
        DbgPrint("hello lyshark \n");
    
        NTSTATUS status = STATUS_UNSUCCESSFUL;
        PEPROCESS eproc = NULL;
        KAPC_STATE kpc = { 0 };
    
        PPEB64 pPeb64 = NULL;
    
        __try
        {
            // HANDLE)4656 进程PID
            status = PsLookupProcessByProcessId((HANDLE)4656, &eproc);
    
            // 得到64位PEB
            pPeb64 = (PPEB64)PsGetProcessPeb(eproc);
    
            DbgPrint("PEB64 = %p \n", pPeb64);
    
            if (pPeb64 != 0)
            {
                // 验证可读性
                ProbeForRead(pPeb64, sizeof(PEB32), 1);
    
                // 附加进程
                KeStackAttachProcess(eproc, &kpc);
    
                DbgPrint("进程基地址: 0x%p \n", pPeb64->ImageBaseAddress);
                DbgPrint("ProcessHeap = 0x%p \n", pPeb64->ProcessHeap);
                DbgPrint("BeingDebugged = %d \n", pPeb64->BeingDebugged);
    
                // 脱离进程
                KeUnstackDetachProcess(&kpc);
            }
        }
        __except (EXCEPTION_EXECUTE_HANDLER)
        {
            Driver->DriverUnload = UnDriver;
            return STATUS_SUCCESS;
        }
    
        Driver->DriverUnload = UnDriver;
        return STATUS_SUCCESS;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    PEB64代码运行后,我们加载驱动即可看到如下结果:

    而相对于64位进程来说,获取32位进程的PEB信息可以直接调用PsGetProcessWow64Process()函数得到,该函数已被导出可以任意使用,获取PEB代码如下。

    #include "peb.h"
    #include 
    
    // 定义导出
    NTKERNELAPI PVOID NTAPI PsGetProcessPeb(_In_ PEPROCESS Process);
    
    VOID UnDriver(PDRIVER_OBJECT driver)
    {
        DbgPrint(("Uninstall Driver Is OK \n"));
    }
    
    // LyShark
    NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
    {
        DbgPrint("hello lyshark \n");
    
        NTSTATUS status = STATUS_UNSUCCESSFUL;
        PEPROCESS eproc = NULL;
        KAPC_STATE kpc = { 0 };
    
        PPEB32 pPeb32 = NULL;
    
        __try
        {
            // HANDLE)4656 进程PID
            status = PsLookupProcessByProcessId((HANDLE)6164, &eproc);
    
            // 得到32位PEB
            pPeb32 = (PPEB32)PsGetProcessWow64Process(eproc);
    
            DbgPrint("PEB32 = %p \n", pPeb32);
    
            if (pPeb32 != 0)
            {
                // 验证可读性
                ProbeForRead(pPeb32, sizeof(PEB32), 1);
    
                // 附加进程
                KeStackAttachProcess(eproc, &kpc);
    
                DbgPrint("进程基地址: 0x%p \n", pPeb32->ImageBaseAddress);
                DbgPrint("ProcessHeap = 0x%p \n", pPeb32->ProcessHeap);
                DbgPrint("BeingDebugged = %d \n", pPeb32->BeingDebugged);
    
                // 脱离进程
                KeUnstackDetachProcess(&kpc);
            }
            
        }
        __except (EXCEPTION_EXECUTE_HANDLER)
        {
            Driver->DriverUnload = UnDriver;
            return STATUS_SUCCESS;
        }
    
        Driver->DriverUnload = UnDriver;
        return STATUS_SUCCESS;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    PEB32代码运行后,我们加载驱动即可看到如下结果:

  • 相关阅读:
    (202402)多智能体MetaGPT入门2:AI Agent知识体系结构
    项目记录:使用SpringBoot + MyBatisPlus 在MySQL字段设置外键后ID自增失效导致添加失败问题(ID生成策略)
    基于MATLAB的电流、电压互感器特性的仿真分析
    Python零基础入门-8 错误和异常
    前端框架Bootstrap
    读《山本》
    Python中一个非常高效的json对比库--deepdiff
    【ES6知识】Promise 对象
    六、Big Data Tools安装
    闭关之 C++ 并发编程笔记(二):同步、内存模型和原子操作
  • 原文地址:https://blog.csdn.net/lyshark_csdn/article/details/134539788