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

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

首先在开始写代码之前需要先定义好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"));
} 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;
}

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"));
} 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;
}

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

驱动开发:内核通过PEB得到进程参数的更多相关文章

  1. Windows驱动开发-内核常用内存函数

    搞内存常用函数 C语言 内核 malloc ExAllocatePool memset RtlFillMemory memcpy RtlMoveMemory free ExFreePool

  2. 驱动开发:内核中实现Dump进程转储

    多数ARK反内核工具中都存在驱动级别的内存转存功能,该功能可以将应用层中运行进程的内存镜像转存到特定目录下,内存转存功能在应对加壳程序的分析尤为重要,当进程在内存中解码后,我们可以很容易的将内存镜像导 ...

  3. 驱动开发:内核R3与R0内存映射拷贝

    在上一篇博文<驱动开发:内核通过PEB得到进程参数>中我们通过使用KeStackAttachProcess附加进程的方式得到了该进程的PEB结构信息,本篇文章同样需要使用进程附加功能,但这 ...

  4. 驱动开发:内核遍历进程VAD结构体

    在上一篇文章<驱动开发:内核中实现Dump进程转储>中我们实现了ARK工具的转存功能,本篇文章继续以内存为出发点介绍VAD结构,该结构的全程是Virtual Address Descrip ...

  5. 用Visual studio2012在Windows8上开发内核驱动监视进程创建

    在Windows NT中,80386保护模式的“保护”比Windows 95中更坚固,这个“镀金的笼子”更加结实,更加难以打破.在Windows 95中,至少应用程序I/O操作是不受限制的,而在Win ...

  6. 驱动开发:内核层InlineHook挂钩函数

    在上一章<驱动开发:内核LDE64引擎计算汇编长度>中,LyShark教大家如何通过LDE64引擎实现计算反汇编指令长度,本章将在此基础之上实现内联函数挂钩,内核中的InlineHook函 ...

  7. Linux驱动开发必看详解神秘内核(完全转载)

    Linux驱动开发必看详解神秘内核 完全转载-链接:http://blog.chinaunix.net/uid-21356596-id-1827434.html   IT168 技术文档]在开始步入L ...

  8. 《windows内核安全与驱动开发》ctrl2cap中的ObReferenceObjectByName疑问

    国内有关于windows内核驱动这块的书籍实在是甚少,不过好在<windows内核安全与驱动开发>这本书还算不错(内容方面),但是不得不说这本书在许多地方存在着一些细节上的问题.比如我今天 ...

  9. [arm驱动]Linux内核开发之阻塞非阻塞IO----轮询操作【转】

    本文转载自:http://7071976.blog.51cto.com/7061976/1392082 <[arm驱动]Linux内核开发之阻塞非阻塞IO----轮询操作>涉及内核驱动函数 ...

随机推荐

  1. Macos系统编译percona及部分函数在Macos系统上运算差异

    欢迎来到 GreatSQL社区分享的MySQL技术文章,如有疑问或想学习的内容,可以在下方评论区留言,看到后会进行解答 本文来源:原创投稿 GreatSQL社区原创内容未经授权不得随意使用,转载请联系 ...

  2. 杭州思科对 Apache DolphinScheduler Alert 模块的改造

    杭州思科已经将 Apache DolphinScheduler 引入公司自建的大数据平台.目前,杭州思科大数据工程师 李庆旺 负责 Alert 模块的改造已基本完成,以更完善的 Alert 模块适应实 ...

  3. kubernetes网络模型

    Overview 本文将探讨Kubernetes中的网络模型,以及对各种网络模型进行分析. Underlay Network Model 什么是Underlay Network 底层网络 Underl ...

  4. 【面试题】JSON.stringify()妙用,你真的知道吗?

    JSON.stringify()妙用 点击打开视频讲解更加详细 语法:JSON.stringify(value, replacer , space) value:将要序列化成 一个JSON 字符串的值 ...

  5. day23--Java集合06

    Java集合06 13.Map接口02 13.2Map接口常用方法 put():添加 remove():根据键键删除映射关系 get():根据键获取值 size():获取元素个数 isEnpty(): ...

  6. Vue 3-150行代码实现新国标红绿灯效果案例

    昨天刷视频,都是关于新国标红绿灯的,看大家议论纷纷,下班就用150行代码通过Vue组件实践红绿模拟演示,视频也跟大家展示过了.今天接着更新图文版本,大家跟着优雅哥通过该案例实操模拟一下. 不过新国标红 ...

  7. HTML <option> 标签的属性:selected ; disabled ; label ; value;

    HTML <option> 标签的属性:selected ;  disabled ; label ; value; 1. selected="selected" sel ...

  8. 【Homebrew】安装

    /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)" 官网安 ...

  9. OSI七层模型与TCP/IP协议

    作者:菘蓝 时间:2022/9/1 ================================================================================== ...

  10. 第五十八篇:webpack的Source Map

    好家伙,Source Map没听过 1.什么是Source Map? 字面意义上来看应该是个好东西 Source Map 就是一个信息文件,里面储存着位置信息. 也就是说,Source Map 文件中 ...