进程管理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 ...
随机推荐
- Linux 命令整理 (有不正确的随时补充)
du 概述: Linux下命令,统计目录(或文件)所占磁盘空间的大小. 语法: du[-abcDhHklmsSx][-L<符号连接>][-X<文件>][--block-size ...
- php redis队列操作
php redis队列操作 rpush/rpushx 有序列表操作,从队列后插入元素:lpush/lpushx 和 rpush/rpushx 的区别是插入到队列的头部,同上,'x'含义是只对已存在的 ...
- 7.mongo python 库 pymongo的安装
1.Python 中如果想要和 MongoDB 进行交互就需要借助于 PyMongo 库,在CMD中使用命令即可[注意此处是pip3,pip无法安装]: pip3 install pymongo 2. ...
- request.getParameter()获取不到数据
HTML中的form表单有一个关键属性 Content-Type=application/x-www-form-urlencoded 或multipart/form-data. 1. Content- ...
- Linux 基础内容
1.linux版本有:redhat(收费),centos,ubuntu,suse(开发使用) 2./目录下的:etc配置文件目录,media挂载点,opt第三方安装目录,boot启动文件,home家, ...
- Jenkins介绍和安装及配合GitLab代码自动部署
Jenkins是什么? 基于JAVA的开源的自动化系统平台 加速自动化CI,CD任务及流水线,所有类型的任务:构建,测试,部署等 丰富的插件生态系统支持功能扩展,1400+插件和SCM,测试,通知,报 ...
- Flex外包公司——案例汇总
Flex做的案例汇总: http://flex.org/showcase/ http://taggraph.com/everybody http://demoprod.informationbuild ...
- 使用excel估计GARCH模型参数——以GARCH(1,1)为例
本文的知识点:使用excel求解GARCH模型的系数,以GARCH模型为例,主要采用的是极大似然估计法MLE. 同时给出了R语言的输出结果作为对照验证. 参考了:http://investex ...
- vue的技巧代码
转载:https://segmentfault.com/a/1190000014085613 第一招:化繁为简的Watchers 场景还原: created(){ this.fetchPostList ...
- Flask之SQLAlchemy,flask_session以及蓝图
数据库操作 ORM ORM 全拼 Object-Relation Mapping,中文意为 对象-关系映射.主要实现模型对象到关系数据库数据的映射 优点 : 只需要面向对象编程, 不需要面向数据库编写 ...