| PEB block for any process is usually found at address 0x7ffdf000. 
		However there is standard way to get this address. There is undocumented 
		function ZwQueryInformationProcess from NTDLL.DLL which can be used to 
		retrieve the PROCESS_BASIC_INFORMATION. The PBI structure is shown 
		below. | 
	
		| struct _PROCESS_BASIC_INFORMATION
 {
 PVOID Reserved1;
 PPEB PebBaseAddress;
 PVOID Reserved2[2];
 ULONG_PTR UniqueProcessId;
 PVOID Reserved3;
 } PROCESS_BASIC_INFORMATION;
 
 
 | 
	
		| The second member PebBaseAddress contains the address of PEB which 
		can be used to get the list of loaded modules. 
 
 | 
	
		
	
	
		| Once you get the address of PEB, you can use use ReadProcessMemory 
		API to read the PEB from the target process. | 
	
		| PEB peb;
 ReadProcessMemory(hprocess, pbi.PebBaseAddress, &peb, 16, &dwSize)
 
 
 | 
	
		| PEB is a big structure hence I cannot dump it here. One of the 
		member that is interesting to us is PPEB_LDR_DATA which is pointer to 
		loader data structure containing linked list of loaded modules. Now from 
		PEB, you can get PEB_LDR_DATA structure as follows. | 
	
		| PEB_LDR_DATA peb_ldr_data;
 ReadProcessMemory(hprocess, peb.Ldr, &peb_ldr_data, sizeof(peb_ldr_data), 
		&dwSize);
 
 struct _PEB_LDR_DATA
 {
 ULONG Length;
 UCHAR Initialized;
 PVOID SsHandle;
 LIST_ENTRY InLoadOrderModuleList;
 LIST_ENTRY InMemoryOrderModuleList;
 LIST_ENTRY InInitializationOrderModuleList;
 PVOID EntryInProgress;
 } PEB_LDR_DATA, *PPEB_LDR_DATA;
 
 
 | 
	
		| PEB_LDR_DATA structure contains the pointers to 3 linked lists each 
		of which list the modules in different order. Now its just a matter of 
		going through each module by following one of this linked list. 
 
 | 
	
		
	
	
		| Now we will go through each of the modules by following the 
		InLoadOrderModuleList pointer. Information about each of these modules 
		is retrieved using ReadProcessMemory function. The structure LDR_MODULE 
		representing each module is given below. | 
	
		| struct _LDR_MODULE
 {
 LIST_ENTRY InLoadOrderModuleList;
 LIST_ENTRY InMemoryOrderModuleList;
 LIST_ENTRY InInitializationOrderModuleList;
 PVOID BaseAddress;
 PVOID EntryPoint;
 ULONG SizeOfImage;
 UNICODE_STRING FullDllName;
 UNICODE_STRING BaseDllName;
 ULONG Flags;
 USHORT LoadCount;
 USHORT TlsIndex;
 LIST_ENTRY HashTableEntry;
 ULONG TimeDateStamp;
 } LDR_MODULE, *PLDR_MODULE;
 
 
 | 
	
		| It contains lot of information about a module which you don't get using 
		high level APIs. One of the member is LoadCount which is nothing but the reference 
		count of the DLL. | 
	
		| LDR_MODULE peb_ldr_module;
 void *readAddr = (void*) peb_ldr_data.InLoadOrderModuleList.Flink;
 
 // Go through each modules one by one in their load order.
 while( ReadProcessMemory(hprocess, readAddr, &peb_ldr_module,
		sizeof(peb_ldr_module), &dwSize) )
 {
 // Get the reference count of the DLL
 loadCount = (signed short)peb_ldr_module.LoadCount;
 
 readAddr = (void *) peb_ldr_module.InLoadOrderModuleList.Flink;
 }
 
 
 | 
	
		| If load count for a 
		DLL is -1 then the DLL is statically linked otherwise its dynamically 
		loaded. | 
	
		|  |