thehive_

EarlyBird APC-Injection | Heaven's gate and all the goodies

EarlyBird APC-Injection | Heaven's gate and all the goodies


As a Practical Example for EarlyBird APC-Injection from Malware Evasion Through Injection part2 Episode of REM-Essentials, I found this interesting sample that's not only using EarlyBird APC Injection, but a whole lot of other tricks, since I found a niche in analyzing code, lets dive into this mess.

Sample sha256: 9173b5a1c2ca928dfa821fb1502470c7f13b66ac2a1638361fda141b4547b792

This Sample uses Early-Bird to inject malicious payload into a legitimate windows binary _ svchost.exe _ in this case.


Simple Threat Intel:

The sample starts by injecting into explorer.exe, it drops two binaries, one of the injected payloads in turn injects into svchost.exe .

// Since this sample is in fact a .NET sample, we will quickly unpack it till we get our main dropper.


Quickly unpacking/ deobfuscating 1st stage payload:

1β†’

Firing the Sample in dnSpy we find it's real name: phpv1ph20_cr.exe , stepping into the Main > InitializeComponent() which are just basic Methods for creating Applications in C#

inside InitializeComponent() we see basic layout manipulation methods, then some objects and functions with encrypted names, which in short does the following:

  • Gets a .bitmap image from the resources that's most likely is an encrypted executable. [1`]
  • Gets another resource of size 19bytes, which we can guess is a key. [1``]
  • Saving the .bitmap image into a byte array, and passing the array along with the key into a function that returns a stocuUXlBXJEyFZuoaR object that loaded as Assembly and invoked[1```]

β†’ resources to load and decrypt.

2β†’

Setting breakpoints on each Assembly.Load() / .Invoke() and running the debugger[2`]. We hit the breakpoint before Assembly.Load() and with checking the stocuUXlBXJEyFZuoaR object we see an executable, that's definitely the .bitmap image been decrypted[2``].

3β†’

We will Step Through the Assembly.Load() and let the program load the assembly, Stepping Into .Invoke() and it's relevant InvokeMethodFast() method, we find ourselves executing inside Program() function in stub.exe[3`] . Checking this function we see it performs some anti-analysis checks[3``] and in turn loads a resource and by checking the resources we find a MAIN.bin binary file that's 41kb[3```], so we dump this out and jump to the next analysis step.


Analyzing MAIN.bin:

// The Threat Intel step gave us the information that the sample injects into explorer.exe, drops two PEs into it, and the injected payload inside explorer.exe injects the final payload into svchost.exe

MAIN.bin: 6ad3ca9bb4e9d96c2507934486c013c1f58c0030d503d3b10b58e5d23209429e

1β†’

Basic Static Analysis:

MAIN.bin has sections with self-modifying code[1], two exports RemoteMain(), TestSvchost() [1``] and loads of interesting strings[1```].

// [1```]

// Heaven's Gate?
00000BAC  wow32_64
00000C50  IsWow64Process

00000C60  KERNEL32
00000C6C  explorer.exe
00000C7C  SeDebugPrivilege
00000C90  SimpleMyMain
00000CA0  CreateProcessInternalW
00000CB8  kernel32
00000CC4  Hello from EXPLORER
00000D84  \\.\pipe\mynamedpipe
00000D9C  RemoteMain
00000DA8  TestSvchost
00000E10  Global\%s%d
00000E30  NtAllocateVirtualMemory
00000E48  NtWriteVirtualMemory
00000E60  RtlCreateUserThread

// EARLYBIRD APC Injection
00003E1A  NtQueueApcThread
00003E2E  NtResumeThread

// IoCs
Unicode Strings:
---------------------------------------------------------------------------
00000A70  lfFilePath
00000A88  Software\Microsoft\Notepad
00000AC0  explorer.scr
00000ADC  scr.lnk
00000AEC  Explorer
00000B00  Software\Microsoft\Windows\CurrentVersion\Run
00000B5C  explorer.exe
00000B78  Windows Explorer Command
00000BB8  Mozilla/5.0 (Windows; U; MSIE 8.0; Windows NT 6.0; ru-RU)
00000C34  POST
00000CD6  RNumber
00000CE8  Software\Microsoft\Modules
00000D20  %s\%d
00000D2C  NameHash
00000D40  FileHash
00000D54  Flags
00000D60  Size
00000D6C  Data
00000D78  %s\%s
00000DB8  http://46.105.143.221/next/version.php
00000E1A  dntdll.dll

2β†’

Debugging MAIN.bin:

This sample is pretty tricky and with a mixture of injection techniques/ execution and anti-analysis tricks, I will set a simple flow of its execution and based on it we will debug through the sample with these major steps in mind.

MAIN.bin:
sha256: 6ad3ca9bb4e9d96c2507934486c013c1f58c0030d503d3b10b58e5d23209429e
  A]  // drops a 64bit (first) payload in it's memory space through memcpy
      // hollows wow32_64 native image to contain another (second) 
          // 32bit payload via memcpy this payload is an a copy of the original
          // dropper with a _ possible _ decrypted binary at offset [0x8000]
      // with WriteProcessMemory it injects both payloads into explorer.exe
 B]   // execute the injected payload via a thread as an APC using heaven's gate
   explorer.exe:
        56kb-32bit payload: 055c614c181237a4a64df6346b9631a394f134bf21964f46b5479e927ef31044
        32kb-64bit payload: 49c25a5b8413d98d77722b6fddbc2d9c15a9c7ca4e5aef6acd5d8fd6df1e81e4
  C]    // malicious thread injects into svchost.exe, executes payload as an APC.
       svchost:
           56kb-32bit payload: 9a64c4f2e9c070a7b2593ad276c75aa65a74d4f90c64be60233e0636335c4cec
             // connects to the internet, establishes persistence... etc
             // drops two files in C:\\Users\xxx\Music\
                  explorer.scr: 6ad3ca9bb4e9d96c2507934486c013c1f58c0030d503d3b10b58e5d23209429e
                  scr.lnk: 20cc017c62b884b7f15ce889f93e24b86d7bd6f2ad03267966fdd373ac81724d

A]

1 β†’

After querying running processes with CreateToolhelp32Snapshot()/ Process32First()/ Process32Next() and running the resulted process name pe32.szExeFile over some mangling, comparing it with this string c48947ea , the sample opens explorer.exe to obtain a handle to it.

2 β†’

Through an interesting wrapper function, the sample figures out if it's running under Wow64 or not. It first loads the IsWow64Process() address[2`] then executes it over it's own context[2``].

passing the hProcess of explorer.exe, this wrapper function is executed again[2```], with return value of ZERO meaning the specified process _ target process explorer.exe _ is in fact a 64bit process. that's a good guess that maybe the sample would execute the payload through Heaven's Gate which we will get to later.

3 β†’

The sample then allocates memory at [0x000F0000] in it's own context[3`], then through another wrapper function, an address inside it's memory space is passed, so we might expect a write operation next[3``].

the memory at [0x000F0000] is populated in chunks through a typical memcpy with a binary in the sample's context at [0x013B8000], Next it parses the dropped payload's PE header to check if it's 32bit/ 64bit binary.

dump1: 47092f385933db565b2172cf767c13eaae2724e70e7a96f014a42837fb2a2fa6

After populating the allocated memory with the interesting dump the sample will virtually protect it, at this point we would save it and resolve the imports by fixing mapped offsets.

quickly analyzing the dumped binary we see it's 64-bit code with the name [dll.bin], with 6 exports and self-modifying sections.

4 β†’

For the next payload to be dropped, the sample creates a named file mapping object with CreateFileMappingA() with the name wow32_64 which is a native windows image, yet it passes no hFile to the file mapping object, but must pass a MaxSizeHigh which interestingly enough was [DBDC β†’ 56kb] the sample's own image size, the name of the file mapping object underlying section would be the same wow32_64. and a section is created.

CreateFileMapping( ..., DBDC, &"wow32_64");
      CreateFileMappingNumaW();
                 NtCreateSection( ..., DBDC, ...); 

next the file mapping object along with the created section is mapped in the sample's context by a call to MapViewOfFile() that in turn calls NtMapViewOfSection(), we end up with a mapped empty 56kb section in the sample's process memory.

next the mapped memory block [0x200000] is populated using memcpy again, with the sample's binary at [0x13D0000] size of [DBDC β†’ 56kb].

[ if you happen to notice the offsets different from the past steps, and the next steps, it's because I reloaded the sample a couple of times πŸ™‹πŸ»β€β™€οΈ ]

The sample then checks the written binary if it's 64bit or 32bit by parsing the PE header's IMAGE_FILE_HEADER Machine value [14C / 8664]

The file mapping object is then unmapped along with the underlying section through NtUnmapViewOfFile() β†’ ZwUnmapViewOfSection()

5 β†’

Quickly analyzing the mapped memory block we see it's identical to the sample we are running MAIN.bin yet it actually contains another executable at offset [0x8000] that is the first dump we dumped at step3, with old school binary diffing, we see that this version of MAIN.bin has unpacked what seemed to be an encrypted binary from the sample we're running to a copy of itself, maybe explaining the different PE parsing checks over that mapped memory region.

dump2: c6a7567623a6630866337231e6e9601ae6c7560820ba4f97efe8fa9d2b200f9c

B]

6 β†’

The Injection into explorer.exe involves `Heaven's Gate` which is a technique to inject into 64bit processes from 32bit payloads, this was clearly obvious in this sample as it made couple of IsWow64Process() checks over itself and the opened process explorer.exe .

Since we didn't go this far to only get this far, let's talk a bit about Heaven's Gate explaining how it's done in this sample.

The Sample starts by figuring out it's environment, if it's running on a 32bit or 64bit system, the loader itself is 32bit running under Wow64, again Wow64 is considered a sandbox/interface to run 32bit code inside 64bit system without modifying the 32bit code. for every process/ application there is a SysWow64 version of it.

as confusing as it looks, all 32bit version of windows DLLs and binaries lay in SysWow64 folder and the 64bit version of it is in System32 folder.

In Step2, the Sample figures out the environment it's running on [Wow64 β†’ payload is 32bit] and the target process [explorer.exe β†’ 64bit process], so then it would literally tunnel 32bit code to be executed in 64bit process as we will see next to allocate a block of memory, drop a payload inside it and pass execution to the dropped payload inside the injected target 64bit explorer.exe process.

In order to access the 64bit environment of a process from a 32bit payload, the sample needs to use the 64bit version of DLLs and functions and the appropriate code segment selector, for both 32bit code and 64bit code there are two different segment selectors [0x23 for 32bit code/ 0x33 for 64bit code].

This process happen as follows:

// obtain handle to 64bit DLLs/Functions
// implement the desired function
// push 0x33 segment selector
// push the address of code to be executed
// call RETF: ret far that allows specifying an address to return to 
// + the code segment selector
// i.e. [CALL 0x33:payload.xxxxx]
.
.
.
push 33
call payload.xxxxx
add DWORD PTR ss:[esp], 5
ret far

To witness this happen, we will debug explorer.exe in a 64bit debugger, and as a starter we will set a breakpoint on NtTestAlert() to catch if the injected payload is executed as an APC:

Execution flow for injecting into explorer.exe :

6` β†’

A] Allocate memory inside explorer.exe

B] Write payload inside the allocated memory block at &allocated_mem

C] Pass execution to payload inside explorer.exe with RtlCreateUserThread() specifying the StartAddress of the created thread[C`], which if we jumped to inside the injected payload in explorer.exe we'd find another jump to a function in the payload[C``].

7 β†’

Now we get to the fun part where the main process _ dropper's process _ passes execution to the payload inside explorer.exe and we're left with a dropped payload inside a crucial process like explorer.exe, things will get messy because we are debugging a process that's highly expected to have interrupts, so events outside debugging the intended payload will cause us mega headaches.

Once executing the RtlCreateUserThread() call, the sample's process exits and we hit NtTestAlert() breakpoint[7`] in the debugged explorer.exe that let's our payload _ that is a queued APC _ execute, which is in fact the location specified to jump at for the created thread[7``].

8 β†’

Now we're executing from the injected payload inside explorer.exe and since we're debugging the process, the only active thread now is the malicious thread, so right now anything else depends on explorer.exe freezes since we're debugging it.

thread's offset at 0x2BD0000 β†’ payload's address

Viewing the strings inside the injected payload, we put breakpoints on interesting strings, we also see wow32_64 the same windows native image the original dropper used to write the second payload into.

C]

9 β†’

Following execution inside the dropped payload. we see it parses the PE header of the injected payload, resolves some APIs to use, next it constructs the path to 32bit version of svchost.exe

inside sysWow64 β†’ C:\\windows\syswow64\\svchost.exe

Next the payload creates the 32bit svchost.exe process.

right now, we would set breakpoints on CreateProcessInternalW(), NtResumeThread(), RtlCreateUserThread(), NtQueueApcThread().

10 β†’

On run we hit CreateProcessInternalW() breakpoint with the path to 32bit svchost.exe, creating the process in a suspended state.

The payload then tries to allocate memory inside the spawned svchost.exe with different calls to VirtualAllocEx()/ WriteProcessMemory() to eventually drop the final payload.

Confusingly enough the sample just stops there, the malicious thread inside explorer.exe exits leaving a suspended unmodified svchost.exe, so I guess the injection into svchost.exe involves some anti-analysis checks beforehand.

We should expect svchost.exe to be injected with the final payload, with the main thread executed as an APC, dropping two files on disk.

thread's offset at 0xC0000 β†’ final payload's address


Interestingly enough while debugging I opened Process Hacker under the infected explorer.exe _ that Iam still debugging _ and I suddenly hit NtQueueApcThread() breakpoint in the payload, and I end up with a trojaned Process Hacker πŸ€”πŸ€”πŸ€”

Yet it was injected by the first payload [64bit payload] that's supposedly will do the same thing the dropper did?? I really have no idea what's happening here

Yet from analyzing the dropped payloads' assembly we find both main exports are called via NtQueueApcThread()/ NtResumethread(), though we couldn't catch the APC into svchost.exe, we can quite understand how it happened.


For a closer look into the EarlyBird-APC Injection and how it's done over the resuming of a newly created/ suspended thread, CyberBit has patched the same Sample, to reproduce the EarlyBird-APC Injection in a simple way to catch it on the other end _ svchost.exe _ , Here is the full synopsis of the technique:

https://www.cyberbit.com/blog/endpoint-security/new-early-bird-code-injection-technique-discovered/


Good Hunt!.. and later with another Sample. πŸ‘ΎπŸ‘Ύ