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. if语句实现考试成绩划分和用if语句替换三元运算符

    语句练习 指定考试成绩,判断成绩的等级. 90-100 优秀 80-89 好 70-79 良 60-69 及格 60以下 不及格 代码: public static void main(String[ ...

  2. 多线程与高并发(三)—— 源码解析 AQS 原理

    一.前言 AQS 是一个同步框架,关于同步在操作系统(一)-- 进程同步 中对进程同步做了些概念性的介绍,我们了解到进程(线程同理,本文基于 JVM 讲解,故下文只称线程)同步的工具有很多:Mutex ...

  3. 基于Python3(Autosub)以及Ffmpeg配合GoogleTranslation(谷歌)为你的影片实现双语版字幕(逐字稿)

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_169 为影片加字幕其实是一件非常耗费时间的事情,尤其是对于打字慢的朋友来说.当然不光为影片加字幕,在其他领域,类似的逐字稿也是工作 ...

  4. Vue ref属性 && props配置项

    1 // # ref属性: 2 // # 1.用来给元素或者子组件注册引用信息(id的替代者) 3 // # 2.应用在html标签上获取的是真实的DOM元素,应用在组件标签上是组件实例对象(vc) ...

  5. 羽夏看Linux内核——启动那些事

    写在前面   此系列是本人一个字一个字码出来的,包括示例和实验截图.如有好的建议,欢迎反馈.码字不易,如果本篇文章有帮助你的,如有闲钱,可以打赏支持我的创作.如想转载,请把我的转载信息附在文章后面,并 ...

  6. 最新MongoDB安装,学习笔记

    MongoDB 导读 作者还在陆续更新中,如果喜欢作者的笔记,觉得可以学习到有帮助,后面会不断学习新内容,就点个关注吧,如果觉得文章有关注可以点个赞,谢谢: 官网:https://www.mongod ...

  7. 一文带你掌握Spring Web异常处理方式

    一.前言 大家好,我是 去哪里吃鱼 ,也叫小张. 最近从单位离职了,离开了五年多来朝朝夕夕皆灯火辉煌的某网,激情也好悲凉也罢,觥筹场上屡屡物是人非,调转过事业部以为能换种情绪,岂料和下了周五的班的前同 ...

  8. centos/windows服务器,Mysql数据库表结构损坏-已解决

    [问题原因]服务器突然断电 [故障报告]数据库表结构损坏 [解决思路]进入强制恢复模式,备份库表及数据重建 故障发现 周末公司断电,周一启动数据库就直接报错了 查看日志 上面标记的log,明确表示是非 ...

  9. java-运算符与判断

    运算符: 1)算术运算符:+-*/%,++,-- 进行加.减.乘.除.取余数.自增.自减 2)关系运算符:>,<,>=,<=,==,!=    boolean类型 判断两个整形 ...

  10. MySQL数据库授权的两种方式

    方法一:grant命令创建用户并授权(针对只修改权限) grant命令简单语法如下: grant all privileges on dbname.* to username@localhost id ...