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枚举进程所有模块的更多相关文章

  1. Python::OS 模块 -- 进程管理

    os模块的简介参看 Python::OS 模块 -- 简介 os模块的文件相关操作参看 Python::OS 模块 -- 文件和目录操作 os模块的进程参数 Python::OS 模块 -- 进程参数 ...

  2. Nginx学习笔记1-Nginx功能模块以及进程管理

    1.         功能 1.1.           功能描述 使用缓存加速反向代理,简单负载均衡和容错: 使用缓存机制加速远程FastCGI服务器的访问: 模块化结构: 基本的HTTP功能: 邮 ...

  3. Swoole 进程管理模块 Process 之单进程的使用

    PHP 自带的 pcntl,存在很多不足,如: 没有提供进程间通信的功能: 不支持重定向标准输入和输出: 只提供了 fork 这样原始的接口,容易使用错误: Swoole\Process 提供了如下特 ...

  4. Node.js进程管理之Process模块

    在前面Node.js事件运行机制也有提到,Node.js应用在单个线程运行,但是现在大部分服务器都是多处理器,为了方便使用多个进程,Node.js提供了3个模块.Process模块提供了访问正在运行的 ...

  5. Supervisor (进程管理利器) 使用说明 - 运维笔记

    一.Supervisor简单介绍supervisor是一个 Client/Server模式的系统,允许用户在类unix操作系统上监视和控制多个进程,或者可以说是多个程序.supervisor与laun ...

  6. Linux操作系统的进程管理

    Linux操作系统的进程管理 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.进程相关概念 1>.进程概述 内核的功用: 进程管理.文件系统.网络功能.内存管理.驱动程序. ...

  7. Linux进程管理——查看内存的工具

    Linux进程管理——查看内存的工具 一查看内存的工具vmstat vmstat命令:虚拟内存信息vmstat [options] [delay [count]]vmstat 2 5 [root@ce ...

  8. JDK9新特性-改进进程管理 API

    Java 9 这个版本对进程管理方面的改进也是相当大的.在为数不多的几次 Java 项目中,有偶尔用到多线程,但对多进程和进程方面的了解还真是太少. 我想,大部分人应该跟我一样,在编程之外知道有进程的 ...

  9. python进程管理工具Supervisor

    一.Supervisor简单介绍 supervisor是一个 Client/Server模式的系统,允许用户在类unix操作系统上监视和控制多个进程,或者可以说是多个程序.supervisor与lau ...

随机推荐

  1. linux下sublime输入中文

    title: linux下sublime输入中文 date: 2017-11-09 20:54:43 tags: sublime categories: 开发工具 archlinux系统 下载文件 g ...

  2. 【运维技术】redis(一主两从三哨兵模式搭建)记录

    redis(一主两从三哨兵模式搭建)记录 目的: 让看看这篇文章的的人能够知道:软件架构.软件的安装.配置.基本运维的操作.高可用测试.也包含我自己,能够节省对应的时间. 软件架构: 生产环境使用三台 ...

  3. 【BCFTOOLS】按样本拆分VCF文件

    在对vcf的操作有这样三个软件: Vcftools:主要用于群体分析,文本处理的功能不是很强大,虽然这个软件也可以拆分样本,但是这种拆分不涉及文件的处理,只是保留在分析流程里. GATK .x:这个软 ...

  4. P2472 [SCOI2007]蜥蜴(网络流)

    P2472 [SCOI2007]蜥蜴 把每个点拆成2个点,两点之间连边的边权为石柱高度 新建虚拟源点$S$和汇点$T$ $S$向所有有蜥蜴的点连边,边权1 其他边都连$inf$ 剩下就是裸的$dini ...

  5. UI自动化(三)css优先级

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  6. 6_linux用户及权限(1)

    ------------用户管理: useradd,userdel,usermod,passwd,chsh,chfn,finger,id,chage组管理: groupadd,groupdel,gro ...

  7. hdu 4277 USACO ORZ dfs+hash

    USACO ORZ Time Limit: 5000/1500 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Proble ...

  8. mockjs学习

    mockjs简单学习与应用,可以满足工作所需就行.*************************************************************************** ...

  9. 第 8 章 容器网络 - 065 - 容器在 Weave 中如何通信和隔离?

    首先在host2 执行如下命令: weave launch 10.12.31.22 这里必须指定 host1 的 IP 10.12.31.22,这样 host1 和 host2 才能加入到同一个 we ...

  10. fcn+caffe+voc2012实验记录

    参考博客: http://blog.csdn.net/haoji007/article/details/77148374 http://blog.csdn.net/jacke121/article/d ...