Files
wavestone-cdt-edrsandblast/EDRSandblast/Utils/RemotePEBBrowser.c
T
2023-10-06 16:12:52 +02:00

213 lines
8.2 KiB
C

#include "PrintFunctions.h"
#include "RemotePEBBrowser.h"
#include "SW2_Syscalls.h"
PVOID GetRVA(ULONG_PTR baseAddress, ULONG_PTR RVA) {
return (PVOID)(baseAddress + RVA);
}
// Return a pointer to the target process (PEB) Ldr's InMemoryOrderModuleList.
PLDR_DATA_TABLE_ENTRY getPebLdrAddress(HANDLE hProcess) {
// Get target process PEB address.
PROCESS_BASIC_INFORMATION basicInfo = { 0 };
basicInfo.PebBaseAddress = 0;
PROCESSINFOCLASS ProcessInformationClass = 0;
NTSTATUS status = NtQueryInformationProcess(hProcess, ProcessInformationClass, &basicInfo, sizeof(PROCESS_BASIC_INFORMATION), NULL);
if (!NT_SUCCESS(status)) {
_tprintf_or_not(TEXT("[-] Module parsing failed: couldn't get target process PEB address\n"));
return NULL;
}
#if _WIN64
PVOID pPebLdrAddress = (PVOID)((ULONG_PTR) basicInfo.PebBaseAddress + offsetof(PEB64, Ldr));
#else
PVOID pPebLdrAddress = (PVOID)((ULONG_PTR) basicInfo.PebBaseAddress + offsetof(PEB, Ldr));
#endif
PPEB_LDR_DATA pprocessLdr = NULL;
status = NtReadVirtualMemory(hProcess, pPebLdrAddress, &pprocessLdr, sizeof(PPEB_LDR_DATA), NULL);
if (!NT_SUCCESS(status)) {
_tprintf_or_not(TEXT("[-] Module parsing failed: couldn't get target process Ldr address (NtReadVirtualMemory error 0x%x).\n"), status);
return NULL;
}
// As PLDR_DATA_TABLE_ENTRY starts with InLoadOrderLinks while PEB_LDR_DATA's InLoadOrderModuleList is at offset 0x0C.
return (PLDR_DATA_TABLE_ENTRY)(((PBYTE)pprocessLdr) + offsetof(PEB_LDR_DATA, InLoadOrderModuleList));
}
PMODULE_INFO createModuleInfo(HANDLE hProcess, PLDR_DATA_TABLE_ENTRY ldrEntry) {
PMODULE_INFO newModuleInfo = calloc(1, sizeof(MODULE_INFO));
if (!newModuleInfo) {
_tprintf_or_not(TEXT("[-] Module parsing failed: couldn't allocate new module info\n"));
return NULL;
}
newModuleInfo->next = NULL;
newModuleInfo->dllBase = (ULONG64)(ULONG_PTR) ldrEntry->DllBase;
newModuleInfo->ImageSize = ldrEntry->SizeOfImage;
newModuleInfo->timeDateStamp = ldrEntry->TimeDateStampOrLoadedImports.TimeDateStamp;
newModuleInfo->checkSum = ldrEntry->HashLinksOrSectionPointerAndCheckSum.SectionPointerAndCheckSum.CheckSum;
// read the full path of the DLL
NTSTATUS status = NtReadVirtualMemory(hProcess, (PVOID) ldrEntry->FullDllName.Buffer, newModuleInfo->dllName, ldrEntry->FullDllName.Length, NULL);
if (!NT_SUCCESS(status)) {
_tprintf_or_not(TEXT("[-] Module parsing failed: couldn't retrieve dllName from Ldr entry (NtReadVirtualMemory error 0x%x).\n"), status);
return NULL;
}
return newModuleInfo;
}
PMODULE_INFO getModulesInLdrByInMemoryOrder(HANDLE hProcess) {
PMODULE_INFO pmoduleList = NULL;
NTSTATUS status = FALSE;
// Retrieve the remote process Ldr address as pseudo PLDR_DATA_TABLE_ENTRY.
PLDR_DATA_TABLE_ENTRY pLdrAddressInPeb = getPebLdrAddress(hProcess);
if (!pLdrAddressInPeb) {
return NULL;
}
// Iterate over the linked list by InMemoryOrderModuleList order.
LDR_DATA_TABLE_ENTRY LdrCurrentEntry;
PLDR_DATA_TABLE_ENTRY pLdrCurrentEntryAddress = pLdrAddressInPeb;
while (TRUE) {
// Add InMemoryOrderLinks offset to iterate on InMemoryOrderLinks order (by retrieving the ptr at InMemoryOrderLinks).
status = NtReadVirtualMemory(hProcess, ((PBYTE) pLdrCurrentEntryAddress) + offsetof(LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks), &pLdrCurrentEntryAddress, sizeof(PLDR_DATA_TABLE_ENTRY), NULL);
if (!NT_SUCCESS(status)) {
_tprintf_or_not(TEXT("[-] Module parsing failed: couldn't get Ldr InLoadOrderModuleList first element address (NtReadVirtualMemory error 0x%x).\n"), status);
return NULL;
}
// Substract InMemoryOrderLinks offset to be at the top of the LDR_DATA_TABLE_ENTRY struct.
pLdrCurrentEntryAddress = (PLDR_DATA_TABLE_ENTRY)(((PBYTE)pLdrCurrentEntryAddress) - offsetof(LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks));
// Looped back to the first entry.
if (pLdrAddressInPeb == pLdrCurrentEntryAddress) {
break;
}
// Read LDR_DATA_TABLE_ENTRY data for the current element.
status = NtReadVirtualMemory(hProcess, pLdrCurrentEntryAddress, &LdrCurrentEntry, sizeof(LDR_DATA_TABLE_ENTRY), NULL);
if (!NT_SUCCESS(status)) {
_tprintf_or_not(TEXT("[-] Module parsing failed: couldn't get Ldr InLoadOrderModuleList next element (NtReadVirtualMemory error 0x%x).\n"), status);
return NULL;
}
// Create module info for list using the current LDR_DATA_TABLE_ENTRY entry.
PMODULE_INFO pnewModuleInfo = createModuleInfo(hProcess, &LdrCurrentEntry);
if (!pnewModuleInfo) {
return NULL;
}
// Insert the new module info element to the module list.
if (!pmoduleList) {
pmoduleList = pnewModuleInfo;
}
else {
PMODULE_INFO plastModule = pmoduleList;
while (plastModule->next) {
plastModule = plastModule->next;
}
plastModule->next = pnewModuleInfo;
}
}
return pmoduleList;
}
PMEMORY_PAGE_INFO getMemoryPagesInfo(HANDLE hProcess, BOOL filterPage) {
PMEMORY_PAGE_INFO prangesList = NULL;
PMEMORY_PAGE_INFO newRange = NULL;
PVOID baseAddress = NULL;
PVOID currentAddress = NULL;
ULONG64 regionSize = 0;
MEMORY_INFORMATION_CLASS memoryInfoClass = { 0 };
MEMORY_BASIC_INFORMATION memoryBasicInfo = { 0 };
NTSTATUS status = STATUS_UNSUCCESSFUL;
while (TRUE) {
status = NtQueryVirtualMemory(hProcess, (PVOID)currentAddress, memoryInfoClass, &memoryBasicInfo, sizeof(memoryBasicInfo), NULL);
// The specified base address is outside the range of accessible addresses, iteration is finished.
if (status == STATUS_INVALID_PARAMETER) {
break;
}
else if (!NT_SUCCESS(status)) {
_tprintf_or_not(TEXT("[-] Memory pages info retrieval failed: couldn't query memory page (NtQueryVirtualMemory error 0x%x).\n"), status);
return NULL;
}
baseAddress = memoryBasicInfo.BaseAddress;
regionSize = memoryBasicInfo.RegionSize;
// Overflow.
if (((ULONG_PTR) baseAddress + regionSize) < (ULONG_PTR) baseAddress) {
break;
}
// Next memory range.
currentAddress = (PVOID) GetRVA((ULONG_PTR) baseAddress, (ULONG_PTR) regionSize);
if (filterPage) {
// Ignore non-commited pages.
if (memoryBasicInfo.State != MEM_COMMIT) {
continue;
}
// Ignore mapped pages.
if (memoryBasicInfo.Type == MEM_MAPPED) {
continue;
}
// Ignore pages with PAGE_NOACCESS. {
if ((memoryBasicInfo.Protect & PAGE_NOACCESS) == PAGE_NOACCESS) {
continue;
}
// Ignore pages with PAGE_GUARD.
if ((memoryBasicInfo.Protect & PAGE_GUARD) == PAGE_GUARD) {
continue;
}
// Ignore pages with PAGE_EXECUTE. {
if ((memoryBasicInfo.Protect & PAGE_EXECUTE) == PAGE_EXECUTE) {
continue;
}
}
newRange = calloc(1, sizeof(MEMORY_PAGE_INFO));
if (!newRange) {
_tprintf_or_not(TEXT("[-] Memory pages info retrieval failed: couldn't allocate memory for new MEMORY_RANGE_INFO"));
return NULL;
}
newRange->next = NULL;
newRange->startOfMemoryPage = (ULONG_PTR)baseAddress;
newRange->dataSize = regionSize;
newRange->state = memoryBasicInfo.State;
newRange->protect = memoryBasicInfo.Protect;
newRange->type = memoryBasicInfo.Type;
if (!prangesList) {
prangesList = newRange;
}
else {
PMEMORY_PAGE_INFO lastRange = prangesList;
while (lastRange->next) {
lastRange = lastRange->next;
}
lastRange->next = newRange;
}
}
if (!prangesList) {
_tprintf_or_not(TEXT("[-] Memory pages info retrieval failed: couldn't retrieve any page"));
return NULL;
}
return prangesList;
}