xorl %eax, %eax

Fileless malware and PEB enumeration

leave a comment »

I was reverse engineering a fileless (meaning the malicious payload is only in the system’s memory) malware sample and I came across this technique which apparently is quite popular in fileless malware. So, this is what this post will be about. How fileless malware take advantage of PEB (Process Environment Block) enumeration to work. You can see the PEB structure as defined in Winternl.h header file below.

typedef struct _PEB {
  BYTE                          Reserved1[2];
  BYTE                          BeingDebugged;
  BYTE                          Reserved2[1];
  PVOID                         Reserved3[2];
  PPEB_LDR_DATA                 Ldr;
  PRTL_USER_PROCESS_PARAMETERS  ProcessParameters;
  BYTE                          Reserved4[104];
  PVOID                         Reserved5[52];
  PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
  BYTE                          Reserved6[128];
  PVOID                         Reserved7[1];
  ULONG                         SessionId;
} PEB, *PPEB;

When a malware injects a payload into memory it needs to somehow find which API calls to use. This means it has to find where those are located in memory. A common method to do this is using PEB which is always located at the same offset. Specifically, at offset 0x30 from the “fs” register. The assembly instructions you see below will load the PEB pointer to the “edx” register.

xor edx, edx          ; Make sure edx is empty
mov edx, fs:[edx+30h] ; Get the address of PEB

Now that the malware has a starting point, it can get advantage of the “Ldr” pointer which is PEB. “Ldr” is technically a pointer to a “PEB_LDR_DATA” structure which contains a linked list (InMemoryOrderModuleList) of the loaded modules. Here you can see how this is defined in Winternl.h header file.

typedef struct _PEB_LDR_DATA {
  BYTE       Reserved1[8];
  PVOID      Reserved2[3];
  LIST_ENTRY InMemoryOrderModuleList;
} PEB_LDR_DATA, *PPEB_LDR_DATA;

And below you can see the equivalent assembly instructions that will help us find the “Ldr” pointer. We are just using the PEB pointer that we discovered above and add 0x0C to it which will lead us to the location of the “Ldr” pointer, and we store its value in the “edx” register.

xor edx, edx          ; Make sure edx is empty
mov edx, fs:[edx+30h] ; Get the address of PEB
mov edx, [edx+0Ch]    ; Get the address of PEB->Ldr

Within the “Ldr” as you saw from the type definition above, there is a doubly-linked list named “InMemoryOrderModuleList”. This doubly-linked list contains the modules that are loaded in this process. Once again, the “LIST_ENTRY” data type is defined in the Winternl.h header file and you can see it here.

 typedef struct _LIST_ENTRY
{
   struct _LIST_ENTRY  *Flink;
   struct _LIST_ENTRY  *Blink;
}LIST_ENTRY, *PLIST_ENTRY;

The code can now just iterate through the “InMemoryOrderModuleList” linked list to enumerate the loaded modules that are available. You can see the equivalent assembly code below which is similar to the above. However, now “edx” register points to the first module (specifically a pointer to a “LDR_DATA_TABLE_ENTRY” structure) that is available. By increasing the offset we can iterate through all of them.

xor edx, edx          ; Make sure edx is empty
mov edx, fs:[edx+30h] ; Get the address of PEB
mov edx, [edx+0Ch]    ; Get the address of PEB->Ldr
mov edx, [edx+14h]    ; Get the PEB->Ldr->InMemoryOrderModuleList

From this point on, the malware can identify the modules it needs to use and reference them directly. This method is very popular in fileless malware as it can be used to dynamically discover loaded modules when a payload is injected in memory and executed via another process. For example, a common method is to use the third entry of the list (which includes the base address of kernel32.dll) and enumerate the export table of kernel32.dll to find LoadLibrary() and start loading arbitrary DLLs required for its operation. Here is a sample code that gets the base address of kernel32.dll which can be used to discover LoadLibrary() to be able to load modules dynamically.

xor edx, edx          ; Make sure edx is empty
mov edx, fs:[edx+30h] ; Get the address of PEB
mov edx, [edx+0Ch]    ; Get the address of PEB->Ldr
mov edx, [edx+14h]    ; Get the PEB->Ldr->InMemoryOrderModuleList
mov edx, [edx]        ; Second entry in PEB->Ldr->InMemoryOrderModuleList
mov edx, [edx]        ; Third entry (kernel32.dll) in PEB->Ldr->InMemoryOrderModuleList
mov edx, [edx+10h]    ; The base address of the third entry (kernel32.dll)

Written by xorl

December 6, 2017 at 01:08

Posted in Windows

Leave a comment