For more info see ...
Each process has a Process Environment Block so this method can be used to read the loaded modules in other processes (the only trick required is that you need to determine the PEB address in the remote process, but there are ways to do this), but for this sample i've just got it enumerating within its own process.
It also shows how to access other members of the PEB, for example the BeingDebugged byte which the Windows API function IsDebuggerPresent directly references, as you can see in a disassembly of its code:
! mov eax, dword ptr fs:[18]
! mov eax, dword ptr [eax+30]
! movzx eax, byte ptr [eax+2] <-- PEB.BeingDebugged
! retn
Code updated - José Roca was correct in quickly spotting that array members in my PB translation of the PEB were 1 extra, i've since corrected the code, cheers José!
Each process has a Process Environment Block so this method can be used to read the loaded modules in other processes (the only trick required is that you need to determine the PEB address in the remote process, but there are ways to do this), but for this sample i've just got it enumerating within its own process.
It also shows how to access other members of the PEB, for example the BeingDebugged byte which the Windows API function IsDebuggerPresent directly references, as you can see in a disassembly of its code:
! mov eax, dword ptr fs:[18]
! mov eax, dword ptr [eax+30]
! movzx eax, byte ptr [eax+2] <-- PEB.BeingDebugged
! retn
Code updated - José Roca was correct in quickly spotting that array members in my PB translation of the PEB were 1 extra, i've since corrected the code, cheers José!
Code:
#COMPILE EXE #INCLUDE "win32api.inc" TYPE UNICODE_STRING Length AS WORD MaximumLength AS WORD ptrBuffer AS DWORD END TYPE FUNCTION UniStrToAnsi (UNI_STR AS UNICODE_STRING) AS STRING 'Convert Unicode to ANSI ON ERROR RESUME NEXT DIM Buffer AS STRING Buffer = SPACE$(UNI_STR.Length / 2) WideCharToMultiByte %CP_ACP, _ ' code page %NULL, _ ' performance and mapping flags BYVAL UNI_STR.ptrBuffer, _ ' Unicode string to convert UNI_STR.Length, _ ' len of Unicode string BYVAL STRPTR(Buffer), _ ' buffer for ANSI string UNI_STR.Length / 2, _ ' len of ANSI buffer BYVAL %NULL, _ ' default for unmappable chars BYVAL %NULL ' default flag FUNCTION = LEFT$(Buffer, UNI_STR.Length / 2) END FUNCTION TYPE LARGE_INTEGER dwLo AS DWORD dwHi AS DWORD END TYPE TYPE RTL_DRIVE_LETTER_CURDIR Flags AS DWORD Length AS DWORD TimeStamp AS DWORD DosPath AS UNICODE_STRING END TYPE TYPE RTL_USER_PROCESS_PARAMETERS MaximumLength AS DWORD Length AS DWORD Flags AS DWORD DebugFlags AS DWORD ConsoleHandle AS DWORD ConsoleFlags AS DWORD StdInputHandle AS DWORD StdOutputHandle AS DWORD StdErrorHandle AS DWORD CurrentDirectoryPath AS UNICODE_STRING CurrentDirectoryHandle AS DWORD DllPath AS UNICODE_STRING ImagePathName AS UNICODE_STRING CommandLine AS UNICODE_STRING Environment AS DWORD StartingPositionLeft AS DWORD StartingPositionTop AS DWORD dwWidth AS DWORD dwHeight AS DWORD CharWidth AS DWORD CharHeight AS DWORD ConsoleTextAttributes AS DWORD WindowFlags AS DWORD ShowWindowFlags AS DWORD WindowTitle AS UNICODE_STRING DesktopName AS UNICODE_STRING ShellInfo AS UNICODE_STRING RuntimeData AS UNICODE_STRING DLCurrentDirectory(31) AS RTL_DRIVE_LETTER_CURDIR END TYPE TYPE PEB_LDR_DATA dwLength AS DWORD Initialized AS DWORD SsHandle AS DWORD InLoadOrderModuleList AS LIST_ENTRY InMemoryOrderModuleList AS LIST_ENTRY InInitializationOrderModule AS LIST_ENTRY END TYPE TYPE LDR_MODULE InLoadOrderModuleList AS LIST_ENTRY InMemoryOrderModuleList AS LIST_ENTRY InInitializationOrderModule AS LIST_ENTRY BaseAddress AS DWORD EntryPoint AS DWORD SizeOfImage AS DWORD FullDllName AS UNICODE_STRING BaseDllName AS UNICODE_STRING Flags AS DWORD LoadCount AS WORD TlsIndex AS WORD HashTableEntry AS LIST_ENTRY TimeDateStamp AS DWORD END TYPE TYPE PEB InheritedAddressSpace AS BYTE ReadImageFileExecOptions AS BYTE BeingDebugged AS BYTE Spare AS BYTE Mutant AS DWORD ImageBaseAddress AS DWORD LoaderData AS PEB_LDR_DATA PTR ProcessParameters AS RTL_USER_PROCESS_PARAMETERS PTR SubSystemData AS DWORD ProcessHeap AS DWORD FastPebLock AS DWORD FastPebLockRoutine AS DWORD '//PPEBLOCKROUTINE FastPebUnlockRoutine AS DWORD '//PPEBLOCKROUTINE EnvironmentUpdateCount AS DWORD KernelCallbackTable AS DWORD EventLogSection AS DWORD EventLog AS DWORD FreeList AS DWORD '//PPEB_FREE_BLOCK TlsExpansionCounter AS DWORD TlsBitmap AS DWORD TlsBitmapBits(1) AS DWORD ReadOnlySharedMemoryBase AS DWORD ReadOnlySharedMemoryHeap AS DWORD ReadOnlyStaticServerData AS DWORD AnsiCodePageData AS DWORD OemCodePageData AS DWORD UnicodeCaseTableData AS DWORD NumberOfProcessors AS DWORD NtGlobalFlag AS DWORD Spare2(3) AS BYTE CriticalSectionTimeout AS LARGE_INTEGER HeapSegmentReserve AS DWORD HeapSegmentCommit AS DWORD HeapDeCommitTotalFreeThreshold AS DWORD HeapDeCommitFreeBlockThreshold AS DWORD NumberOfHeaps AS DWORD MaximumNumberOfHeaps AS DWORD ProcessHeaps AS DWORD GdiSharedHandleTable AS DWORD ProcessStarterHelper AS DWORD GdiDCAttributeList AS DWORD LoaderLock AS DWORD OSMajorVersion AS DWORD OSMinorVersion AS DWORD OSBuildNumber AS DWORD OSPlatformId AS DWORD ImageSubSystem AS DWORD ImageSubSystemMajorVersion AS DWORD ImageSubSystemMinorVersion AS DWORD GdiHandleBuffer(33) AS DWORD PostProcessInitRoutine AS DWORD TlsExpansionBitmap AS DWORD TlsExpansionBitmapBits(127) AS BYTE SessionId AS DWORD END TYPE FUNCTION PBMAIN() AS LONG LOCAL pPEB AS PEB PTR, pModule AS LDR_MODULE PTR, dwPEB AS DWORD, FirstModule AS DWORD ! mov dwPEB, fs:[&h30] ;Get PEB pPEB = dwPEB STDOUT "ImageBaseAddress=0x" & HEX$(@pPEB.ImageBaseAddress,8) STDOUT "BeingDebugged=" & HEX$(@pPEB.BeingDebugged) STDOUT "CurrentDirectoryPath=" & UniStrToAnsi(@[email protected]) STDOUT "ImagePathName=" & UniStrToAnsi(@[email protected]) '// Enum modules pModule = @[email protected] DO IF @pModule.BaseAddress = 0 THEN EXIT DO STDOUT "Module: " & HEX$(@pModule.BaseAddress,8) & " " & UniStrToAnsi(@pModule.FullDllName) pModule = @pModule.InLoadOrderModuleList.FLink LOOP WAITKEY$ END FUNCTION
Comment