进程管理02 通过PEB枚举进程所有模块
0x01 结构探究
先在win7 x86下通过windbg来探究通过peb来得到进程模块的步骤:
命令!process 0 0 exeplorer.exe 先获取到explorer.exe的EPROCESS的地址,如图我们可以看到EPROCESS的地址为:0x87782d40 ,PEB的地址为:0x7ffdf000

使用 .process /p /r 87ede940 命令切换到explorer.exe进程后才能够访问它的peb用户地址空间:

切换到explorer.exe后,使用命令dt _EPROCESS 877822d40 查看EPROCESS,可以看到在偏移0x1a8的位置就是_PEB,地址为0x7ffdf000

继续查看_PEB结构,使用命令 dt _PEB 0x7ffdf000查看PEB的信息,可以看到在偏移0x00c的位置就是_PEB_LDR_DATA,地址为: 0x77697880:

继续查看_PEB_LDR_DATA结构,使用命令dt _PEB_LDR_DATA 0x77697880 查看_PEB_LDR_DATA结构,可以看到一共有3个_LIST_ENTRY,这三个链表只是结点的排列顺序不一样,总的内容是相同的。我利用的是第一个InLoadOrderModuleList:

现在再来看一个最后的关键结构:_LDR_DATA_TABLE_ENTRY
使用命令dt _LDR_DATA_TABLE_ENTRY查看_LDR_DATA_TABLE_ENTRY的结构:

从结构中可以看到InLoadOrderModuleList位于结构体的首部,所以我们获取到的_LIST_ENTRY地址就直接指向了_LDR_DATA_TABLE_ENTRY!(这就是为什么选择InLoadOrderModuleList这条链表的原因。)
回头看一下眼链表的第一个结点的地址位0x3316a8,使用命令dt _LDR_DATA_TABLE_ENTRY 0x3316a8查看检验一下:

可以看到看到explore.exe这个进程本身的完整路径!因为InLoadOrderModuleList这条链表是按照模块加载顺序遍历的,所以第一个模块儿就是进程本身了,加上0x80的偏移向后看一个进行检验:dt _LDR_DATA_TABLE_ENTRY 0x331ae8

大功告成~
0x02 步骤实现
1.先通过NtQueryInformationProcess函数根据传入的进程句柄找到进程的ProcessBasicInformation,就得到ProcessBasicInfo.PebBaseAddress,再传入ProcessBasicInfo.PebBaseAddress借由ReadProcessMemory函数读取出peb结构。
(附:获得peb的方法有其他,比如去读fs的0x30处等:
__asm
{
//1、通过fs:[30h]获取当前进程的_PEB结构
mov eax,dword ptr fs:[30h];
mov pPeb,eax
}
)
2.得到peb之后,传入peb的成员_PEB_LDR_DATA的基地址,通过ReadProcessMemory函数得到_PEB_LDR_DATA
3.再次使用ReadProcessMemory函数得到_PEB_LDR_DATA的成员变量InLoadOrderModuleList链表进行遍历,由于InLoadOrderModuleList的基地址也是_LDR_DATA_TABLE_ENTRY的第一成员,所以InLoadOrderModuleList的基地址也就是_LDR_DATA_TABLE_ENTRY的基地址。_LDR_DATA_TABLE_ENTRY中就含有进程加载模块的名称和完整路径,分别是FullDllName和BaseDlllName两个成员。
介绍一下ReadProcessMemory函数:
BOOL ReadProcessMemory(
HANDLE hProcess,
LPCVOID lpBaseAddress,
LPVOID lpBuffer,
DWORD nSize,
LPDWORD lpNumberOfBytesRead );
参数
hProcess
目标进程的句柄,该句柄必须对目标进程具有PROCESS_VM_READ
的访问权限。
lpBaseAddress
从目标进程中读取数据的起始地址。 在读取数据前,系统将先检验该地址的数据是否可读,如果不可读,函数将调用失败。
lpBuffer
用来接收数据的缓存区地址。
nSize
从目标进程读取数据的字节数。
lpNumberOfBytesRead
记录实际读取的字节数的变量地址。如果对这个值 不关心,填入NULL即可。
返回值
如果函数执行成功,返回值非零。
如果函数执行失败,返回值为零。调用
GetLastError 函数可以获取该函数执行错误的信息。
如果要读取一个进程中不可访问空间的数据,该函数就会失败。
注意:ReadProcessMemory 函数从目标进程复制指定大小的数据到自己进程的缓存区,任何拥有PROCESS_VM_READ
权限句柄的进程都可以调用该函数,目标进程的地址空间很显然要是可读的,但也并不是必须的,如果目标进程处于被调试状态的话。
0x03 代码
头文件
#pragma once
#include <windows.h>
#include <winternl.h>
#include <ntstatus.h>
#include <TlHelp32.h>
#include <Psapi.h>
#include <vector>
using namespace std; enum MODULE_TYPE
{
MODULE_X86,
MODULE_X64,
};
struct _PROCESS_MODULE_INFORMATION_
{
ULONG64 ModuleBase; //操作系统中可能存在64位与32位的程序
size_t ModuleSize;
WCHAR ModuleFullPathData[MAX_PATH];
MODULE_TYPE ModuleType;
};
template <typename T>
struct _LIST_ENTRY_
{
T Flink;
T Blink;
}; template <typename T>
struct _UNICODE_STRING_
{
WORD BufferLength;
WORD MaximumLength;
T BufferData;
}; template <typename T, typename NGF, int A>
struct _PEB_
{
typedef T type; union
{
struct
{
BYTE InheritedAddressSpace;
BYTE ReadImageFileExecOptions;
BYTE BeingDebugged;
BYTE BitField;
};
T dummy01;
};
T Mutant;
T ImageBaseAddress;
T Ldr;
T ProcessParameters;
T SubSystemData;
T ProcessHeap;
T FastPebLock;
T AtlThunkSListPtr;
T IFEOKey;
T CrossProcessFlags;
T UserSharedInfoPtr;
DWORD SystemReserved;
DWORD AtlThunkSListPtr32;
T ApiSetMap;
T TlsExpansionCounter;
T TlsBitmap;
DWORD TlsBitmapBits[2];
T ReadOnlySharedMemoryBase;
T HotpatchInformation;
T ReadOnlyStaticServerData;
T AnsiCodePageData;
T OemCodePageData;
T UnicodeCaseTableData;
DWORD NumberOfProcessors;
union
{
DWORD NtGlobalFlag;
NGF dummy02;
};
LARGE_INTEGER CriticalSectionTimeout;
T HeapSegmentReserve;
T HeapSegmentCommit;
T HeapDeCommitTotalFreeThreshold;
T HeapDeCommitFreeBlockThreshold;
DWORD NumberOfHeaps;
DWORD MaximumNumberOfHeaps;
T ProcessHeaps;
T GdiSharedHandleTable;
T ProcessStarterHelper;
T GdiDCAttributeList;
T LoaderLock;
DWORD OSMajorVersion;
DWORD OSMinorVersion;
WORD OSBuildNumber;
WORD OSCSDVersion;
DWORD OSPlatformId;
DWORD ImageSubsystem;
DWORD ImageSubsystemMajorVersion;
T ImageSubsystemMinorVersion;
T ActiveProcessAffinityMask;
T GdiHandleBuffer[A];
T PostProcessInitRoutine;
T TlsExpansionBitmap;
DWORD TlsExpansionBitmapBits[32];
T SessionId;
ULARGE_INTEGER AppCompatFlags;
ULARGE_INTEGER AppCompatFlagsUser;
T pShimData;
T AppCompatInfo;
_UNICODE_STRING_<T> CSDVersion;
T ActivationContextData;
T ProcessAssemblyStorageMap;
T SystemDefaultActivationContextData;
T SystemAssemblyStorageMap;
T MinimumStackCommit;
T FlsCallback;
_LIST_ENTRY_<T> FlsListHead;
T FlsBitmap;
DWORD FlsBitmapBits[4];
T FlsHighIndex;
T WerRegistrationData;
T WerShipAssertPtr;
T pContextData;
T pImageHeaderHash;
T TracingFlags;
T CsrServerReadOnlySharedMemoryBase;
};
typedef _PEB_<DWORD, DWORD64, 34> _PEB32_;
typedef _PEB_<DWORD64, DWORD, 30> _PEB64_;
template<typename T>
struct _PEB_T
{
typedef typename std::conditional<std::is_same<T, DWORD>::value, _PEB32_, _PEB64_>::type type;
}; template<typename T>
struct _PEB_LDR_DATA_
{
unsigned long Length;
unsigned char Initialized;
T SsHandle;
_LIST_ENTRY_<T> InLoadOrderModuleList;
_LIST_ENTRY_<T> InMemoryOrderModuleList;
_LIST_ENTRY_<T> InInitializationOrderModuleList;
T EntryInProgress;
unsigned char ShutdownInProgress;
T ShutdownThreadId;
}; template<typename T>
struct _LDR_DATA_TABLE_ENTRY_
{
_LIST_ENTRY_<T> InLoadOrderLinks;
_LIST_ENTRY_<T> InMemoryOrderLinks;
_LIST_ENTRY_<T> InInitializationOrderLinks;
T DllBase;
T EntryPoint;
unsigned long SizeOfImage;
_UNICODE_STRING_<T> FullDllName;
_UNICODE_STRING_<T> BaseDllName;
unsigned long Flags;
unsigned short LoadCount;
unsigned short TlsIndex;
_LIST_ENTRY_<T> HashLinks;
unsigned long TimeDateStamp;
T EntryPointActivationContext;
T PatchInformation;
};
template<typename T>
struct _PROCESS_BASIC_INFORMATION_
{
NTSTATUS ExitStatus;
ULONG Reserved0;
T PebBaseAddress;
T AffinityMask;
LONG BasePriority;
ULONG Reserved1;
T UniqueProcessId;
T InheritedFromUniqueProcessId;
}; typedef decltype(&NtQueryInformationProcess) LPFN_NTQUERYINFORMATIONPROCESS; typedef NTSTATUS(NTAPI *LPFN_NTWOW64QUERYINFORMATIONPROCESS64)(
IN HANDLE ProcessHandle,
IN ULONG ProcessInformationClass,
OUT PVOID ProcessInformation,
IN ULONG ProcessInformationLength,
OUT PULONG ReturnLength OPTIONAL); typedef NTSTATUS(NTAPI *LPFN_NTWOW64READVIRTUALMEMORY64)(
IN HANDLE ProcessHandle,
IN ULONG64 BaseAddress,
OUT PVOID BufferData,
IN ULONG64 BufferLength,
OUT PULONG64 ReturnLength OPTIONAL);
struct _PROCESS_INFORMATION_
{
ULONG ProcessID;
char ImageNameData[MAX_PATH];
char ProcessFullPathData[MAX_PATH];
};
typedef struct
{
DWORD ExitStatus;
DWORD PebBaseAddress;
DWORD AffinityMask;
DWORD BasePriority;
ULONG UniqueProcessId;
ULONG InheritedFromUniqueProcessId;
} __PROCESS_BASIC_INFORMATION__; typedef LONG(__stdcall *PROCNTQSIP)(HANDLE, UINT, PVOID, ULONG, PULONG); SIZE_T SeEnumProcessModuleList(ULONG ProcessID, vector<_PROCESS_MODULE_INFORMATION_>& ProcessModuleInfo);
SIZE_T SeEnumModuleInfoByPeb(ULONG ProcessID, vector<_PROCESS_MODULE_INFORMATION_>& ProcessModuleInfo);
template<typename T>
SIZE_T EnumModuleInfoByPeb(HANDLE ProcessHandle, vector<_PROCESS_MODULE_INFORMATION_>& ProcessModuleInfo);
ULONG64 GetPeb(HANDLE ProcessHandle, _PEB64_* Peb);
ULONG32 GetPeb(HANDLE ProcessHandle, _PEB32_* Peb);
BOOL SeReadProcessMemory(HANDLE ProcessHandle, DWORD BaseAddress, LPVOID BufferData, size_t BufferLength, DWORD64* ReturnLength);
BOOL SeReadProcessMemory(HANDLE ProcessHandle, DWORD64 BaseAddress, LPVOID BufferData, size_t BufferLength, DWORD64 *ReturnLength);
源文件:
BOOL EnumDllLoaderedProcess(vector<_PROCESS_INFORMATION_> ProcessInfo, string DllName)
{
OnInitMember();
vector<_PROCESS_INFORMATION_>::iterator i;
string DllFullPath;
int j = 0;
for (i = ProcessInfo.begin(); i != ProcessInfo.end(); i++)
{
ULONG ProcessID = i->ProcessID;
vector<_PROCESS_MODULE_INFORMATION_>ProcessModuleInfomationVector;
SeEnumProcessModuleList(ProcessID, ProcessModuleInfomationVector);
int index = 0;
vector<_PROCESS_MODULE_INFORMATION_>::iterator m; for (m = ProcessModuleInfomationVector.begin(); m != ProcessModuleInfomationVector.end(); m++)
{ DllFullPath = SeUtf16ToUtf8(m->ModuleFullPathData);
index = DllFullPath.find(DllName);
if (index == -1)
{
continue;
}
else
{
printf("%s", i->ProcessFullPathData);
printf("-----------------------------\n\n");
break;
}
} }
return TRUE;
} SIZE_T SeEnumProcessModuleList(ULONG ProcessID, vector<_PROCESS_MODULE_INFORMATION_>& ProcessModuleInfo)
{
SeEnumModuleInfoByPeb(ProcessID, ProcessModuleInfo); return ProcessModuleInfo.size();
}
SIZE_T SeEnumModuleInfoByPeb(ULONG ProcessID, vector<_PROCESS_MODULE_INFORMATION_>& ProcessModuleInfo)
{
HANDLE ProcessHandle = NULL;
BOOL IsWow64 = FALSE;
ProcessHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, ProcessID);
int a = GetLastError();
if (ProcessHandle == NULL)
{
goto Error;
}
IsWow64Process(ProcessHandle, &IsWow64); if (IsWow64 == TRUE)
{
EnumModuleInfoByPeb<DWORD>(ProcessHandle, ProcessModuleInfo);
}
else
{
EnumModuleInfoByPeb<DWORD64>(ProcessHandle, ProcessModuleInfo);
}
Error:
if (ProcessHandle != NULL)
{
CloseHandle(ProcessHandle);
ProcessHandle = NULL;
}
return ProcessModuleInfo.size();
}
template<typename T>
SIZE_T EnumModuleInfoByPeb(HANDLE ProcessHandle, vector<_PROCESS_MODULE_INFORMATION_>& ProcessModuleInfo)
{
typename _PEB_T<T>::type Peb = { { { 0 } } };
_PEB_LDR_DATA_<T> PebLdrData = { 0 }; ProcessModuleInfo.clear(); if (GetPeb(ProcessHandle, &Peb) != 0 && SeReadProcessMemory(ProcessHandle,
Peb.Ldr, &PebLdrData, sizeof(PebLdrData), 0) == TRUE)
{
for (T CheckPtr = PebLdrData.InLoadOrderModuleList.Flink;
CheckPtr != (Peb.Ldr + FIELD_OFFSET(_PEB_LDR_DATA_<T>, InLoadOrderModuleList));
SeReadProcessMemory(ProcessHandle, static_cast<ULONG64>(CheckPtr), &CheckPtr, sizeof(CheckPtr), 0))
{
_PROCESS_MODULE_INFORMATION_ v1;
wchar_t ModuleFullPathData[MAX_PATH] = { 0 };
_LDR_DATA_TABLE_ENTRY_<T> LdrDataTableEntry = { { 0 } }; SeReadProcessMemory(ProcessHandle, CheckPtr, &LdrDataTableEntry, sizeof(LdrDataTableEntry), 0);
SeReadProcessMemory(ProcessHandle, LdrDataTableEntry.FullDllName.BufferData, ModuleFullPathData,
LdrDataTableEntry.FullDllName.BufferLength, 0); v1.ModuleBase = LdrDataTableEntry.DllBase;
v1.ModuleSize = LdrDataTableEntry.SizeOfImage;
wmemcpy(v1.ModuleFullPathData, ModuleFullPathData, MAX_PATH);
printf("%ls\n", v1.ModuleFullPathData); v1.ModuleType = std::is_same<T, DWORD>::value ? MODULE_X86 : MODULE_X64; ProcessModuleInfo.emplace_back(v1);
}
} return ProcessModuleInfo.size();
}
ULONG64 GetPeb(HANDLE ProcessHandle, _PEB64_* Peb)
{
_PROCESS_BASIC_INFORMATION_<DWORD64> ProcessBasicInfo = { 0 };
ULONG ReturnLength = 0;
if (NT_SUCCESS(__NtWow64QueryInformationProcess64(ProcessHandle, ProcessBasicInformation, &ProcessBasicInfo,
(ULONG)sizeof(ProcessBasicInfo), &ReturnLength)) && Peb)
{
__NtWow64ReadVirtualMemory64(ProcessHandle, ProcessBasicInfo.PebBaseAddress, Peb, sizeof(_PEB64_), NULL);
} return ProcessBasicInfo.PebBaseAddress;
}
ULONG32 GetPeb(HANDLE ProcessHandle, _PEB32_* Peb)
{
PROCESS_BASIC_INFORMATION ProcessBasicInfo = { 0 };
ULONG ReturnLength = 0; if (NT_SUCCESS(__NtQueryInformationProcess(ProcessHandle, ProcessBasicInformation, &ProcessBasicInfo,
(ULONG)sizeof(ProcessBasicInfo), &ReturnLength)) && Peb)
{
ReadProcessMemory(ProcessHandle, ProcessBasicInfo.PebBaseAddress, Peb, sizeof(_PEB32_), NULL);
}
return reinterpret_cast<ULONG32>(ProcessBasicInfo.PebBaseAddress);
}
BOOL SeReadProcessMemory(HANDLE ProcessHandle, DWORD BaseAddress, LPVOID BufferData, size_t BufferLength, DWORD64* ReturnLength)
{
return ReadProcessMemory(ProcessHandle, reinterpret_cast<LPVOID>(BaseAddress), BufferData,
BufferLength, reinterpret_cast<SIZE_T*>(ReturnLength)); }
BOOL SeReadProcessMemory(HANDLE ProcessHandle, DWORD64 BaseAddress, LPVOID BufferData, size_t BufferLength, DWORD64 *ReturnLength)
{
if (__NtWow64ReadVirtualMemory64(ProcessHandle,
BaseAddress, BufferData, BufferLength, ReturnLength) != STATUS_SUCCESS)
{
return FALSE;
} return TRUE;
} BOOL OnInitMember()
{
HMODULE NtdllModuleBase = NULL;
NtdllModuleBase = GetModuleHandle("Ntdll.dll");
if (NtdllModuleBase == NULL)
{
return FALSE;
}
__NtWow64QueryInformationProcess64 = (LPFN_NTWOW64QUERYINFORMATIONPROCESS64)GetProcAddress(NtdllModuleBase,
"NtWow64QueryInformationProcess64");
__NtWow64ReadVirtualMemory64 = (LPFN_NTWOW64READVIRTUALMEMORY64)GetProcAddress(NtdllModuleBase,
"NtWow64ReadVirtualMemory64");
__NtQueryInformationProcess = (LPFN_NTQUERYINFORMATIONPROCESS)GetProcAddress(NtdllModuleBase,
"NtQueryInformationProcess");
if (__NtWow64QueryInformationProcess64 == NULL || __NtWow64ReadVirtualMemory64 == NULL || __NtQueryInformationProcess == NULL)
{
return FALSE;
}
return TRUE;
}
进程管理02 通过PEB枚举进程所有模块的更多相关文章
- Python::OS 模块 -- 进程管理
os模块的简介参看 Python::OS 模块 -- 简介 os模块的文件相关操作参看 Python::OS 模块 -- 文件和目录操作 os模块的进程参数 Python::OS 模块 -- 进程参数 ...
- Nginx学习笔记1-Nginx功能模块以及进程管理
1. 功能 1.1. 功能描述 使用缓存加速反向代理,简单负载均衡和容错: 使用缓存机制加速远程FastCGI服务器的访问: 模块化结构: 基本的HTTP功能: 邮 ...
- Swoole 进程管理模块 Process 之单进程的使用
PHP 自带的 pcntl,存在很多不足,如: 没有提供进程间通信的功能: 不支持重定向标准输入和输出: 只提供了 fork 这样原始的接口,容易使用错误: Swoole\Process 提供了如下特 ...
- Node.js进程管理之Process模块
在前面Node.js事件运行机制也有提到,Node.js应用在单个线程运行,但是现在大部分服务器都是多处理器,为了方便使用多个进程,Node.js提供了3个模块.Process模块提供了访问正在运行的 ...
- Supervisor (进程管理利器) 使用说明 - 运维笔记
一.Supervisor简单介绍supervisor是一个 Client/Server模式的系统,允许用户在类unix操作系统上监视和控制多个进程,或者可以说是多个程序.supervisor与laun ...
- Linux操作系统的进程管理
Linux操作系统的进程管理 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.进程相关概念 1>.进程概述 内核的功用: 进程管理.文件系统.网络功能.内存管理.驱动程序. ...
- Linux进程管理——查看内存的工具
Linux进程管理——查看内存的工具 一查看内存的工具vmstat vmstat命令:虚拟内存信息vmstat [options] [delay [count]]vmstat 2 5 [root@ce ...
- JDK9新特性-改进进程管理 API
Java 9 这个版本对进程管理方面的改进也是相当大的.在为数不多的几次 Java 项目中,有偶尔用到多线程,但对多进程和进程方面的了解还真是太少. 我想,大部分人应该跟我一样,在编程之外知道有进程的 ...
- python进程管理工具Supervisor
一.Supervisor简单介绍 supervisor是一个 Client/Server模式的系统,允许用户在类unix操作系统上监视和控制多个进程,或者可以说是多个程序.supervisor与lau ...
随机推荐
- c#中退出WinForm程序包括有很多方法,如:this.Close(); Application.Exit();Application.ExitThread(); System.Environment.Exit(0);
本文实例总结了C#中WinForm程序退出方法技巧.分享给大家供大家参考.具体分析如下: 在c#中退出WinForm程序包括有很多方法,如:this.Close(); Application.Exit ...
- 第三方jar上传至公司maven仓库(私库)解决办法
在实际开发过程中,我们经常会遇到需要引用的jar依赖,在我们公司的maven仓库不存在,这个时候我们就需要把jar上传上去,在项目中添加对应依赖就OK了. 步骤1:下载jar 在http://mvnr ...
- Python RabbitMQ消息队列
python内的队列queue 线程 queue:不同线程交互,不能夸进程 进程 queue:只能用于父进程与子进程,或者同一父进程下的多个子进程,进行交互 注:不同的两个独立进程是不能交互的. ...
- ubuntu kylin18 安装NVIDIA驱动
这几天装系统快被折腾死了,事情的起因是这样的. 这件事情发生之前那两天一直在调试oled屏幕.我自己做转接板,1.3寸30针fpc的接口. 由于没有使用fpc专用转接座子,导致焊接特别困难,索性最后牺 ...
- Codeforces 1045B Space Isaac - 数论 - Hash
题目传送门 传送门I 传送门II 传送门III 题目大意 给定将$\left \{ 0, 1, \dots, m - 1\right \}$分成了不相交的两个非空集合$A$和$B$,给定$A$,问存在 ...
- day02编程语言,Python语言介绍,Python解释器安装,环境变量,Python代码执行,pip,应用程序使用文件的三步骤,变量,变量的三大组成,比较,pycharm
复习 重点: 1.进制转换:二进制 与十六进制 2.内存分布:栈区 与堆区 # 二进制1111转换十六进制 => 8 4 2 1 => f 10101100111011 => 2a7 ...
- 利用jQuery实现用户名片小动画
我爱撸码,撸码使我感到快乐!大家好,我是Counter.下面给大家介绍利用jQuery实现的小动画,非常的简便,如果有原生js操作的话,那么就不止这么多行了.至于CSS,个人觉得,这边CSS布局也蛮重 ...
- Paper Read: Convolutional Image Captioning
Convolutional Image Captioning 2018-11-04 20:42:07 Paper: http://openaccess.thecvf.com/content_cvpr_ ...
- (转载)【Unity3D学习】获取鼠标点击所对应的GameObject
刚开始学习Unity 3D,新手遇到的坑都是泪对自由的抗争.直入主题~ 首先,为GameObject需要添加组件“Box Collider”. 然后,在脚本中的Update方法中添加如下代码. if( ...
- C++类的大小计算汇总
C++中类涉及到虚函数成员.静态成员.虚继承.多继承.空类等. 类,作为一种类型定义,是没有大小可言的. 类的大小,指的是类的对象所占的大小.因此,用sizeof对一个类型名操作,得到的是具有该类型实 ...