Lists all module information loaded by a process
The first method is CreateToolhelp32Snapshot
The first method: use the process snapshot CreateToolhelp32Snapshot} API.
Steps:
1. Create process snapshot
CreateToolhelp32Snapshot (process, module, heap...)
2. Traverse the first module
BOOL WINAPI Module32First(
HANDLE hSnapshot, snapshot handle
LPMODULEENTRY32 lpme} module information structure
) ;
3. Traverse the next process
BOOL WINAPI Process32Next(
HANDLE hSnapshot, snapshot handle of the process
LPPROCESSENTRY32 lppe# process information structure
);
The 32-bit process cannot get the module information of the 64 bit process
Disadvantages: when we want to obtain the module information list loaded by the process in the 32-bit program on the 64 bit system, we can only obtain the modules of the 32-bit process, but not the modules of the 64 bit process, because the address PEB is wrong. You will get 299 errors in the CreateToolhelp32Snapshot} API. Return error code ERROR_PARTIAL_COPY (299).
When we forcibly use EnumProcessModules to list all the modules loaded by the process, we will find that many processes cannot obtain the information of the process module.
If necessary, use 64 bit to compile the program. In addition, if you want to list 32-bit or 64 bit processes separately, you can use the EnumProcessModulesEx method.
The second method is NtQueryInformationProcess
This function is also used when the 32-bit process cannot get the module information of the 64 bit process.
Use the NtQueryInformationProcess} function to retrieve information about the specified process
Ntdll for Windows NT/2000 system The DLL contains many unpublished API functions.
NtQueryInformationProcess is Microsoft ntdll DLL contains one of the unpublished {API s.
With NtQueryInformationProcess, you can specify parameters, obtain the process information of the specified structure type, and copy it to the buffer. Its prototype is as follows:
NTSYSAPI NTSTATUS NTAPI NtQueryInformationProcess ( IN HANDLE ProcessHandle, // Process handle to get information IN PROCESSINFOCLASS InformationClass, // Type of process information to get OUT PVOID ProcessInformation, // Buffer pointer IN ULONG ProcessInformationLength, // Buffer size in bytes OUT PULONG ReturnLength OPTIONAL // Number of bytes written to buffer );
The first parameter is the process handle to get information, which must be in PROCESS_QUERY_INFORMATION mode access. In order to obtain the process handle, we must use the OpenProcess function as follows:
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION,FALSE,dwProcessID);
The second parameter is the type of request information. This parameter can have many values. In this example, ProcessBasicInformation (value 0) will be used
Use ntdll DLL export function NtQueryInformationProcess, query the ProcessBasicInformation information of the process, and obtain PROCESS_BASIC_INFORMATION structure.
PROCESS_BASIC_INFORMATION:
typedef struct { DWORD ExitStatus; // Receive process termination status DWORD PebBaseAddress; // Receive process environment block address DWORD AffinityMask; // Receive process affinity mask DWORD BasePriority; // Priority class of receiving process ULONG UniqueProcessId; // Receive process ID ULONG InheritedFromUniqueProcessId; //Receive parent process ID } PROCESS_BASIC_INFORMATION; typedef struct _PROCESS_BASIC_INFORMATION { NTSTATUS ExitStatus; PPEB PebBaseAddress; //peb address ULONG_PTR AffinityMask; KPRIORITY BasePriority; ULONG_PTR UniqueProcessId; ULONG_PTR InheritedFromUniqueProcessId; } PROCESS_BASIC_INFORMATION,*PPROCESS_BASIC_INFORMATION;
Read the PEB structure according to PebBaseAddress. The 0x0c offset of PEB is PEB_LDR_DATA structure, in which the three chain headers are the list of modules loaded by the process, and each LIST_ENTRY corresponds to LDR_DATA_TABLE_ENTRY structure, which is also referenced multiple times in wrk.
Solution: NtWow64QueryInformationProcess64
Use NtWow64QueryInformationProcess64 in ntdll
WOW64 obtains the 32 / 64 bit process module information through PEB. This is a function to obtain the modules loaded in the 64 process on a 32-bit machine and in a 32-bit process.
From my love https://www.52pojie.cn/forum.php?mod=viewthread&tid=872501
#include <stdio.h> #include "windows.h" #define NT_SUCCESS(x) ((x) >= 0) #define ProcessBasicInformation 0 typedef NTSTATUS(NTAPI *pfnNtWow64QueryInformationProcess64)( IN HANDLE ProcessHandle, IN ULONG ProcessInformationClass, OUT PVOID ProcessInformation, IN ULONG ProcessInformationLength, OUT PULONG ReturnLength OPTIONAL ); typedef NTSTATUS(NTAPI *pfnNtWow64ReadVirtualMemory64)( IN HANDLE ProcessHandle, IN PVOID64 BaseAddress, OUT PVOID Buffer, IN ULONG64 Size, OUT PULONG64 NumberOfBytesRead ); typedef NTSTATUS(WINAPI *pfnNtQueryInformationProcess) (HANDLE ProcessHandle, ULONG ProcessInformationClass, PVOID ProcessInformation, UINT32 ProcessInformationLength, UINT32* ReturnLength); typedef struct _PROCESS_BASIC_INFORMATION32 { NTSTATUS ExitStatus; UINT32 PebBaseAddress; UINT32 AffinityMask; UINT32 BasePriority; UINT32 UniqueProcessId; UINT32 InheritedFromUniqueProcessId; } PROCESS_BASIC_INFORMATION32; typedef struct _UNICODE_STRING32 { USHORT Length; USHORT MaximumLength; PWSTR Buffer; } UNICODE_STRING32, *PUNICODE_STRING32; typedef struct _PEB32 { UCHAR InheritedAddressSpace; UCHAR ReadImageFileExecOptions; UCHAR BeingDebugged; UCHAR BitField; ULONG Mutant; ULONG ImageBaseAddress; ULONG Ldr; ULONG ProcessParameters; ULONG SubSystemData; ULONG ProcessHeap; ULONG FastPebLock; ULONG AtlThunkSListPtr; ULONG IFEOKey; ULONG CrossProcessFlags; ULONG UserSharedInfoPtr; ULONG SystemReserved; ULONG AtlThunkSListPtr32; ULONG ApiSetMap; } PEB32, *PPEB32; typedef struct _PEB_LDR_DATA32 { ULONG Length; BOOLEAN Initialized; ULONG SsHandle; LIST_ENTRY32 InLoadOrderModuleList; LIST_ENTRY32 InMemoryOrderModuleList; LIST_ENTRY32 InInitializationOrderModuleList; ULONG EntryInProgress; } PEB_LDR_DATA32, *PPEB_LDR_DATA32; typedef struct _LDR_DATA_TABLE_ENTRY32 { LIST_ENTRY32 InLoadOrderLinks; LIST_ENTRY32 InMemoryOrderModuleList; LIST_ENTRY32 InInitializationOrderModuleList; ULONG DllBase; ULONG EntryPoint; ULONG SizeOfImage; UNICODE_STRING32 FullDllName; UNICODE_STRING32 BaseDllName; ULONG Flags; USHORT LoadCount; USHORT TlsIndex; union { LIST_ENTRY32 HashLinks; ULONG SectionPointer; }; ULONG CheckSum; union { ULONG TimeDateStamp; ULONG LoadedImports; }; ULONG EntryPointActivationContext; ULONG PatchInformation; } LDR_DATA_TABLE_ENTRY32, *PLDR_DATA_TABLE_ENTRY32; typedef struct _PROCESS_BASIC_INFORMATION64 { NTSTATUS ExitStatus; UINT32 Reserved0; UINT64 PebBaseAddress; UINT64 AffinityMask; UINT32 BasePriority; UINT32 Reserved1; UINT64 UniqueProcessId; UINT64 InheritedFromUniqueProcessId; } PROCESS_BASIC_INFORMATION64; typedef struct _PEB64 { UCHAR InheritedAddressSpace; UCHAR ReadImageFileExecOptions; UCHAR BeingDebugged; UCHAR BitField; ULONG64 Mutant; ULONG64 ImageBaseAddress; ULONG64 Ldr; ULONG64 ProcessParameters; ULONG64 SubSystemData; ULONG64 ProcessHeap; ULONG64 FastPebLock; ULONG64 AtlThunkSListPtr; ULONG64 IFEOKey; ULONG64 CrossProcessFlags; ULONG64 UserSharedInfoPtr; ULONG SystemReserved; ULONG AtlThunkSListPtr32; ULONG64 ApiSetMap; } PEB64, *PPEB64; typedef struct _PEB_LDR_DATA64 { ULONG Length; BOOLEAN Initialized; ULONG64 SsHandle; LIST_ENTRY64 InLoadOrderModuleList; LIST_ENTRY64 InMemoryOrderModuleList; LIST_ENTRY64 InInitializationOrderModuleList; ULONG64 EntryInProgress; } PEB_LDR_DATA64, *PPEB_LDR_DATA64; typedef struct _UNICODE_STRING64 { USHORT Length; USHORT MaximumLength; ULONG64 Buffer; } UNICODE_STRING64, *PUNICODE_STRING64; typedef struct _LDR_DATA_TABLE_ENTRY64 { LIST_ENTRY64 InLoadOrderLinks; LIST_ENTRY64 InMemoryOrderModuleList; LIST_ENTRY64 InInitializationOrderModuleList; ULONG64 DllBase; ULONG64 EntryPoint; ULONG SizeOfImage; UNICODE_STRING64 FullDllName; UNICODE_STRING64 BaseDllName; ULONG Flags; USHORT LoadCount; USHORT TlsIndex; union { LIST_ENTRY64 HashLinks; ULONG64 SectionPointer; }; ULONG CheckSum; union { ULONG TimeDateStamp; ULONG64 LoadedImports; }; ULONG64 EntryPointActivationContext; ULONG64 PatchInformation; } LDR_DATA_TABLE_ENTRY64, *PLDR_DATA_TABLE_ENTRY64; int main() { DWORD dwPid = 2280; HANDLE m_ProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid); BOOL bTarget = FALSE; BOOL bSource = FALSE; IsWow64Process(GetCurrentProcess(), &bSource); IsWow64Process(m_ProcessHandle, &bTarget); SYSTEM_INFO si; GetSystemInfo(&si); if (bTarget == FALSE && bSource == TRUE) { HMODULE NtdllModule = GetModuleHandle(L"ntdll.dll"); pfnNtWow64QueryInformationProcess64 NtWow64QueryInformationProcess64 = (pfnNtWow64QueryInformationProcess64)GetProcAddress(NtdllModule, "NtWow64QueryInformationProcess64"); pfnNtWow64ReadVirtualMemory64 NtWow64ReadVirtualMemory64 = (pfnNtWow64ReadVirtualMemory64)GetProcAddress(NtdllModule, "NtWow64ReadVirtualMemory64"); PROCESS_BASIC_INFORMATION64 pbi64 = { 0 }; if (NT_SUCCESS(NtWow64QueryInformationProcess64(m_ProcessHandle, ProcessBasicInformation, &pbi64, sizeof(pbi64), NULL))) { DWORD64 Ldr64 = 0; LIST_ENTRY64 ListEntry64 = { 0 }; LDR_DATA_TABLE_ENTRY64 LDTE64 = { 0 }; wchar_t ProPath64[256]; if (NT_SUCCESS(NtWow64ReadVirtualMemory64(m_ProcessHandle, (PVOID64)(pbi64.PebBaseAddress + offsetof(PEB64, Ldr)), &Ldr64, sizeof(Ldr64), NULL))) { if (NT_SUCCESS(NtWow64ReadVirtualMemory64(m_ProcessHandle, (PVOID64)(Ldr64 + offsetof(PEB_LDR_DATA64, InLoadOrderModuleList)), &ListEntry64, sizeof(LIST_ENTRY64), NULL))) { if (NT_SUCCESS(NtWow64ReadVirtualMemory64(m_ProcessHandle, (PVOID64)(ListEntry64.Flink), &LDTE64, sizeof(_LDR_DATA_TABLE_ENTRY64), NULL))) { while (1) { if (LDTE64.InLoadOrderLinks.Flink == ListEntry64.Flink) break; if (NT_SUCCESS(NtWow64ReadVirtualMemory64(m_ProcessHandle, (PVOID64)LDTE64.FullDllName.Buffer, ProPath64, sizeof(ProPath64), NULL))) { printf("Module base address:0x%llX\n Module size:0x%X\n Module path:%ls\n", LDTE64.DllBase, LDTE64.SizeOfImage, ProPath64); } if (!NT_SUCCESS(NtWow64ReadVirtualMemory64(m_ProcessHandle, (PVOID64)LDTE64.InLoadOrderLinks.Flink, &LDTE64, sizeof(_LDR_DATA_TABLE_ENTRY64), NULL))) break; } } } } } } else if (bTarget == TRUE && bSource == TRUE || si.wProcessorArchitecture != PROCESSOR_ARCHITECTURE_AMD64 || si.wProcessorArchitecture != PROCESSOR_ARCHITECTURE_IA64) { HMODULE NtdllModule = GetModuleHandle(L"ntdll.dll"); pfnNtQueryInformationProcess NtQueryInformationProcess = (pfnNtQueryInformationProcess)GetProcAddress(NtdllModule, "NtQueryInformationProcess"); PROCESS_BASIC_INFORMATION32 pbi32 = { 0 }; if (NT_SUCCESS(NtQueryInformationProcess(m_ProcessHandle, ProcessBasicInformation, &pbi32, sizeof(pbi32), NULL))) { DWORD Ldr32 = 0; LIST_ENTRY32 ListEntry32 = { 0 }; LDR_DATA_TABLE_ENTRY32 LDTE32 = { 0 }; wchar_t ProPath32[256]; if (ReadProcessMemory(m_ProcessHandle, (PVOID)(pbi32.PebBaseAddress + offsetof(PEB32, Ldr)), &Ldr32, sizeof(Ldr32), NULL)) { if (ReadProcessMemory(m_ProcessHandle, (PVOID)(Ldr32 + offsetof(PEB_LDR_DATA32, InLoadOrderModuleList)), &ListEntry32, sizeof(LIST_ENTRY32), NULL)) { if (ReadProcessMemory(m_ProcessHandle, (PVOID)(ListEntry32.Flink), &LDTE32, sizeof(_LDR_DATA_TABLE_ENTRY32), NULL)) { while (1) { if (LDTE32.InLoadOrderLinks.Flink == ListEntry32.Flink) break; if (ReadProcessMemory(m_ProcessHandle, (PVOID)LDTE32.FullDllName.Buffer, ProPath32, sizeof(ProPath32), NULL)) { printf("Module base address:0x%X\n Module size:0x%X\n Module path:%ls\n",LDTE32.DllBase,LDTE32.SizeOfImage,ProPath32); } if (!ReadProcessMemory(m_ProcessHandle, (PVOID)LDTE32.InLoadOrderLinks.Flink, &LDTE32, sizeof(_LDR_DATA_TABLE_ENTRY32), NULL)) break; } } } } } } CloseHandle(m_ProcessHandle); getchar(); }