Created
June 13, 2025 09:05
-
-
Save DarkCoderSc/1d0473394fd55c3e0b25f3a5ba56a5a1 to your computer and use it in GitHub Desktop.
Enumerate Remote Process Modules Via PEB - Malware Gallery
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
uses | |
System.SysUtils, Winapi.Windows, Generics.Collections; | |
// ... | |
type | |
TProcessInformationClass = ( | |
// ... | |
ProcessBasicInformation = 0 | |
// ... | |
); | |
// ... | |
function NtQueryInformationProcess( | |
ProcessHandle : THandle; | |
ProcessInformationClass : TProcessInformationClass; | |
ProcessInformation : Pointer; | |
ProcessInformationLength : ULONG; | |
var ReturnLength : ULONG | |
) : NTSTATUS; stdcall; external 'NTDLL.DLL'; | |
// ... | |
type | |
PPEB = Pointer; | |
_PROCESS_BASIC_INFORMATION = record | |
Reserved1 : PVOID; | |
PebBaseAddress : PPEB; | |
Reserved2 : array[0..1] of PVOID; | |
UniqueProcessId : ULONG_PTR; | |
Reserved3 : PVOID; | |
end; | |
TProcessBasicInformation = _PROCESS_BASIC_INFORMATION; | |
PProcessBasicInformation = ^TProcessBasicInformation; | |
_LDR_DATA_TABLE_ENTRY = record | |
InLoadOrderLinks : TListEntry; | |
InMemoryOrderLinks : TListEntry; | |
InInitializationOrderLinkes : TListEntry; | |
DllBase : PVOID; | |
EntryPoint : PVOID; | |
SizeOfImage : ULONG; | |
FullDllName : TUnicodeString; | |
BaseDllName : TUnicodeString; | |
end; | |
TLdrDataTableEntry = _LDR_DATA_TABLE_ENTRY; | |
PLdrDataTableEntry = ^TLdrDataTableEntry; | |
// ... | |
(* TModuleInformation *) | |
type | |
TModuleInformation = class | |
private | |
FImagePath : String; | |
FBaseAddress : NativeUInt; | |
FEntryPoint : NativeUInt; | |
FSizeOfImage : Cardinal; | |
public | |
{@C} | |
constructor Create(const AImagePath : String; const ABaseAddress, AEntryPoint: NativeUInt; const ASizeOfImage : Cardinal); | |
{@G} | |
property ImagePath : String read FImagePath; | |
property BaseAddress : NativeUInt read FBaseAddress; | |
property EntryPoint : NativeUInt read FEntryPoint; | |
property SizeOfImage : Cardinal read FSizeOfImage; | |
end; | |
// ... | |
constructor TModuleInformation.Create(const AImagePath : String; const ABaseAddress, AEntryPoint: NativeUInt; const ASizeOfImage : Cardinal); | |
begin | |
inherited Create(); | |
/// | |
FImagePath := AImagePath; | |
FBaseAddress := ABaseAddress; | |
FEntryPoint := AEntryPoint; | |
FSizeOfImage := ASizeOfImage; | |
end; | |
(* Local *) | |
function EnumerateProcessModules(const ATargetProcessId : Cardinal; var AList : TObjectList<TModuleInformation>) : Cardinal; | |
begin | |
result := 0; | |
/// | |
if not Assigned(AList) then | |
AList := TObjectList<TModuleInformation>.Create(True) | |
else begin | |
AList.Clear(); | |
/// | |
if not AList.OwnsObjects then | |
AList.OwnsObjects := True; | |
end; | |
/// | |
var hProcess := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, ATargetProcessId); | |
if hProcess = 0 then | |
raise EWindowsException.Create('OpenProcess'); | |
try | |
var AProcessBasicInformation : TProcessBasicInformation; | |
var AReturnLength : Cardinal; | |
var ARet := NtQueryInformationProcess( | |
hProcess, | |
ProcessBasicInformation, | |
@AProcessBasicInformation, | |
SizeOf(TProcessBasicInformation), | |
AReturnLength | |
); | |
if ARet < 0 then | |
raise Exception.Create('Could not retrieve target process PEB address.'); | |
/// | |
var ppPEBLdrData := Pointer(NativeUInt(AProcessBasicInformation.PebBaseAddress) + {$IFDEF WIN64}$00000018{$ELSE}$0000000c{$ENDIF}); | |
var pPEBLdrData : Pointer; | |
var ABytesRead : SIZE_T; | |
if not ReadProcessMemory(hProcess, ppPEBLdrData, @pPEBLdrData, SizeOf(Pointer), ABytesRead) then | |
raise EWindowsException.Create('ReadProcessMemory(1)'); | |
var AEntry : TListEntry; | |
var pFirstEntryOffset := Pointer(NativeUInt(pPEBLdrData) + {$IFDEF WIN64}$00000010{$ELSE}$0000000c{$ENDIF}); | |
if not ReadProcessMemory(hProcess, pFirstEntryOffset, @AEntry, SizeOf(TListEntry), ABytesRead) then | |
raise EWindowsException.Create('ReadProcessMemory(2)'); | |
var pEntryOffset := AEntry.Flink; | |
var ADataTableEntry : TLdrDataTableEntry; | |
repeat | |
if not ReadProcessMemory(hProcess, pEntryOffset, @ADataTableEntry, SizeOf(TLdrDataTableEntry), ABytesRead) then | |
raise EWindowsException.Create(Format('ReadProcessMemory(3), Index: %d', [AList.Count])); | |
var pImageFileName : PWideChar; | |
var pImageFileNameSize := ADataTableEntry.FullDllName.Length * SizeOf(WideChar); | |
GetMem(pImageFileName, pImageFileNameSize); | |
try | |
if not ReadProcessMemory(hProcess, ADataTableEntry.FullDllName.Buffer, pImageFileName, pImageFileNameSize, ABytesRead) then | |
raise EWindowsException.Create(Format('ReadProcessMemory(4), Index: %d', [AList.Count])); | |
/// | |
AList.Add(TModuleInformation.Create( | |
string(pImageFileName), | |
NativeUInt(ADataTableEntry.DllBase), | |
NativeUInt(ADataTableEntry.EntryPoint), | |
ADataTableEntry.SizeOfImage | |
)); | |
finally | |
FreeMem(pImageFileName, pImageFileNameSize); | |
end; | |
/// | |
pEntryOffset := ADataTableEntry.InLoadOrderLinks.Flink; | |
until pFirstEntryOffset = ADataTableEntry.InLoadOrderLinks.Flink; | |
finally | |
CloseHandle(hProcess); | |
end; | |
/// | |
result := AList.Count; | |
end; | |
// ... | |
begin | |
try | |
var AList := TObjectList<TModuleInformation>.Create(True); | |
try | |
EnumerateProcessModules(<target_process_id>, AList); | |
/// | |
for var AModuleEntry in AList do | |
WriteLn(Format('Base:[0x%p], EP:[0x%p], Size:[0x%p] -> %s', [ | |
Pointer(AModuleEntry.BaseAddress), | |
Pointer(AModuleEntry.EntryPoint), | |
Pointer(AModuleEntry.SizeOfImage), | |
AModuleEntry.ImagePath | |
])); | |
finally | |
FreeAndNil(AList); | |
end; | |
// ... |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment