进程管理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("-----------------------------

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

  

原文地址:https://www.cnblogs.com/lsh123/p/8295774.html