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

2023-11-21 20:44

本文主要是介绍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 <ntifs.h>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()

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

#include "peb.h"
#include <ntifs.h>// 定义导出
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 进程PIDstatus = PsLookupProcessByProcessId((HANDLE)4656, &eproc);// 得到64位PEBpPeb64 = (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;
}

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

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

#include "peb.h"
#include <ntifs.h>// 定义导出
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 进程PIDstatus = PsLookupProcessByProcessId((HANDLE)6164, &eproc);// 得到32位PEBpPeb32 = (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;
}

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

这篇关于5.4 Windows驱动开发:内核通过PEB取进程参数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/404985

相关文章

SpringBoot 多环境开发实战(从配置、管理与控制)

《SpringBoot多环境开发实战(从配置、管理与控制)》本文详解SpringBoot多环境配置,涵盖单文件YAML、多文件模式、MavenProfile分组及激活策略,通过优先级控制灵活切换环境... 目录一、多环境开发基础(单文件 YAML 版)(一)配置原理与优势(二)实操示例二、多环境开发多文件版

使用docker搭建嵌入式Linux开发环境

《使用docker搭建嵌入式Linux开发环境》本文主要介绍了使用docker搭建嵌入式Linux开发环境,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录1、前言2、安装docker3、编写容器管理脚本4、创建容器1、前言在日常开发全志、rk等不同

SpringBoot 获取请求参数的常用注解及用法

《SpringBoot获取请求参数的常用注解及用法》SpringBoot通过@RequestParam、@PathVariable等注解支持从HTTP请求中获取参数,涵盖查询、路径、请求体、头、C... 目录SpringBoot 提供了多种注解来方便地从 HTTP 请求中获取参数以下是主要的注解及其用法:1

HTTP 与 SpringBoot 参数提交与接收协议方式

《HTTP与SpringBoot参数提交与接收协议方式》HTTP参数提交方式包括URL查询、表单、JSON/XML、路径变量、头部、Cookie、GraphQL、WebSocket和SSE,依据... 目录HTTP 协议支持多种参数提交方式,主要取决于请求方法(Method)和内容类型(Content-Ty

Python实战之SEO优化自动化工具开发指南

《Python实战之SEO优化自动化工具开发指南》在数字化营销时代,搜索引擎优化(SEO)已成为网站获取流量的重要手段,本文将带您使用Python开发一套完整的SEO自动化工具,需要的可以了解下... 目录前言项目概述技术栈选择核心模块实现1. 关键词研究模块2. 网站技术seo检测模块3. 内容优化分析模

Java+AI驱动实现PDF文件数据提取与解析

《Java+AI驱动实现PDF文件数据提取与解析》本文将和大家分享一套基于AI的体检报告智能评估方案,详细介绍从PDF上传、内容提取到AI分析、数据存储的全流程自动化实现方法,感兴趣的可以了解下... 目录一、核心流程:从上传到评估的完整链路二、第一步:解析 PDF,提取体检报告内容1. 引入依赖2. 封装

python中的显式声明类型参数使用方式

《python中的显式声明类型参数使用方式》文章探讨了Python3.10+版本中类型注解的使用,指出FastAPI官方示例强调显式声明参数类型,通过|操作符替代Union/Optional,可提升代... 目录背景python函数显式声明的类型汇总基本类型集合类型Optional and Union(py

基于Java开发一个极简版敏感词检测工具

《基于Java开发一个极简版敏感词检测工具》这篇文章主要为大家详细介绍了如何基于Java开发一个极简版敏感词检测工具,文中的示例代码简洁易懂,感兴趣的小伙伴可以跟随小编一起学习一下... 目录你是否还在为敏感词检测头疼一、极简版Java敏感词检测工具的3大核心优势1.1 优势1:DFA算法驱动,效率提升10

Linux系统管理与进程任务管理方式

《Linux系统管理与进程任务管理方式》本文系统讲解Linux管理核心技能,涵盖引导流程、服务控制(Systemd与GRUB2)、进程管理(前台/后台运行、工具使用)、计划任务(at/cron)及常用... 目录引言一、linux系统引导过程与服务控制1.1 系统引导的五个关键阶段1.2 GRUB2的进化优

Go语言使用Gin处理路由参数和查询参数

《Go语言使用Gin处理路由参数和查询参数》在WebAPI开发中,处理路由参数(PathParameter)和查询参数(QueryParameter)是非常常见的需求,下面我们就来看看Go语言... 目录一、路由参数 vs 查询参数二、Gin 获取路由参数和查询参数三、示例代码四、运行与测试1. 测试编程路