/REM-Essentials/Windows: Malware Evasion through Injection Part-1


  

Malware use Injection as a Common Evasion Tactic as it allows to hide and execute Malicious Code inside legitimate processes or inside malware's own process hence evading common AV detection. Injection also allows malware to gain access to other processes, e.g Banking Trojans gaining access to browsers to steal credentials, Or Malware gaining access to crucial Windows Services for Persistence.

 

There are a number of ways Malwares use to inject itself or inject a Malicious Payload in other Processes, this post will only focus on Memory/ Process Manipulation where a Sample directly injects an executable into memory rather than loading it as a DLL as in the old DLL Injection technique, So the Sample will have it's Malicious Payload Packed inside itself rather than loading it from disk. which of course is more stealthier than regular DLL Injection which is not effective anymore. This is mostly called Dropping a Malicious Payload, as the binary used to perform this is called a Dropper. Droppers must be stealthy as much as possible and in some cases they delete themselves after Dropping their accomplices. 

 

 

This Episode's Flow:

[+] Self-Injection

[+] PE-Injection

[+] PE-Injection w/WriteProcessMemory

[+] Process-Hollowing

[+] Process-Doppleganging 

 

//Other Injection methods like DLL-Injection and APC-Injection are discussed in future posts.

                

 

Self-Injection

 

 

Commonly used in Packers, where a packed executable has a region of memory containing the Code responsible for unpacking the executable to its actual/real form, This Code is called The Unpackng Stub, the Unpacking stub is responsible for decrypting Shellcode that is in turn responsible for decrypting/unpacking _not necessarily_ the final payload and overwriting the executable with it.

For a Closer look into Packers, Check Malware Unpacking Episode in the REM-Essentials Series.

 

 

 

//Spotting Self-Injection:

 

This is fairly straight-foraward, The packed binary will allocate a region of memory in it's own process, first to write the Unpacking Stub which will allocate another regions of memory, and by watching these allocated regions of memory, at some point an executable will be written into it. Next the executable will either _call_ the Upacked Payload's Original Entry Point, or _jmp_ to it.

 

Helpful APIs:

[+] VirtualAlloc()/ LocalAlloc()

[+] VirtualProtect()

 

 

 

Practical Example for Self-Injection: Unpacking Dridex

 

                  

 

PE-Injection

 

 

PE-Injection Involves Injecting the Malicious Payload into a Remote Process, there are Multiple ways to achieve this with different levels of Stealth. Almost all Straightforward PE-Injection Techniques are now detectable by Anti-Virtus Scanners, yet as we will encounter later on, Malware can make a Mix of these techniques to make it harder to detect it injecting into legitimate binaries, they could use lower-level NTDLL calls or twisting a Legitimate Windows Development Components into their own use.

We will discuss these three main PE-Injection Techniques:

-> Regular PE-Injection with WriteProcessMemory.

-> Process Hollowing with NtMapViewOfSection.

-> Process Doppleganging with CreateFileTranscatedW.

 

 

         

1->

PE-Injection w/ WriteProcessMemory:

 

The idea behind a regular PE Injection is to Simply allocate a region of memory in a remote process, write an Executable or Shellcode in this allocated region of Memory and Continue Executing from there. This technique is very easy to spot by AV as it involves direct calls to WriteProcessMemory. This Technique is very similar to DLL Injection _which we discuss in another post_ but instead of loading the Malicious DLL, the sample will be writing the Malicious Executable directly into Memory.

 

 

 

//Spotting PE-Injection:

 

The Sample might start with Spawning another process _could be a legitimate process or even it's own process as a childin a suspended state, then it will allocate a region of Memory with the Size of the Malicious Executable or Size of Shellcode then it will write it's malicious code into the allocated region of memory, if the Malicious Code is an Executable, the Sample has to Map it into Memory i.e. replicate the functions of the Windows Loader, Then the Packed Sample will have to Overwrite/Patch the entry point of the Remote Process, Setup the Process/ Thread Objects' Parameters to execute either the Injected Shellcode or the Malicious Executable.

 

 

 

Implementing Regular PE-Injection:

 

// create a remote process to inject into, usually a legit windows binary
CreateProcessW();

// retrieving information about the process's memory blocks, figuring out offsets..etc
NtQueryVirtualMemory(hProcess,...);

// allocate a region of memory with the size of malicious code
VirtualAllocEx(hProcess, &address, SIZE_OF_MALICIOUS_CODE, ...);

// write malicious code into remote process
WriteProcessMemory(hProcess, ..., SIZE_OF_MALICIOUS_PAYLOAD, ...);

// update PEB with Malicious Code's entrypoint
NtWriteVirtualMemory(hProcess, &PEB, MALICIOUS_ENTRY_POINT, ...);

// resume execution from the remote process
NtResumeThread(hProcess);

 

 

Helpful APIs:

[+] WriteProcessMemory()

[+] NtVirtualAllocEx()

 

 

 

Practical Example: Unpacking Parallax

          

 

 

 

2->

PE-Injection w/ NtUnMapViewOfSection | Process Hollowing:

 

Process Hollowing is meant to be more stealthier than a regular use of WriteProcessMemory, Since it uses low-level NTDLL calls to perform the Injection into the Remote Process. After spawning the target process, the Sample will query the binary to figure out it's offsets, then it will deallocate/Unmap Memory Blocks inside the target process that it literally Hollows the binary so it has a space to write it's Malicious Code into, then it will allocate regions of memory inside the Hollowed binary with the size of the Malicious Payload _either an Executable or ShellCode_ and with low level calls to NtWriteVirtualMemory it will write the Malicious Payload into the reallocated regions of memory. With an Executable written, this region of memory must be mapped correctly in order to execute, so again the Sample will emulate the Windows Loader and update the PEB with the Patched entry point. As for an Analyst looking for a regular WriteProcessMemory implementation, it would be easy to be tricked.

 

 

 

 

// Spotting Process Hollowing:

 

Although this Technique meant to be more stealthier than regular PE-Injection it's still very Noisy and easy to detect with AVs.  The Sample starts with spawning the target process in a suspended state, then it queries the process's memory blocks to find offsets, the Sample will call NtUmapViewOfSection over the legitimate binary's memory block to wip it out, then a call to VirtualAllocEx with the size of the Malicious Payload to reallocate Memory into the Target Process's Memory Space, then the Malicious Payload is written with NtWriteVirtualMemory that is also used to redirect the entry point of the target process, and we end up with a Trojaned Windows Binary.

 

// create target process
CreateProcessW(NAME, ..., CREATE_SUSPENDED, ...);

// figure out target process offsets
NtQueryVirtualMemory(hProcess);

// wiping out the legit binary memory blocks
NtUnMapViewOfSection(hProcess, &base_address);
.
.
.


// reallocating memory blocks inside the process memory space w/ size of the malicious payload
VirtualAllocEx(hProcess, ..., SIZE_OF_MALICIOUS_PAYLOAD);

// writing malicious payload into newly allocated memory
NtWriteVirtualMemory(hProcess, &base_address, &buffer, ...);

// mapping the malicious payload into memory and virtual protect it
NtMapViewOfSection(hProcess, ...);
VirtualProtectEx(hProcess, ...);

// continue execution from the trojan binary 
NtResumeThread(hProcess);

 

 

Helpful APIs:

[+] NtUnMapViewOfSection() / NtMapViewOfSection() : Functions to Map/Unmap sepcified part of Section into/off Process Memory.

[+] NtWriteVirtualMemory() : Low-Level API to write data into a speficied process memory.

[+] VirtualAllocEx()

 

 

 

Practical Example: Unpacking SmokeLoader

          

 

 

 

3->

PE-Injection w/ CreateFileTransactedW | Process Doppleganging:

 

Process Doppleganging  is a Process Injection Method that was Published by Security Researchers in BlackHat conference, this techniques elevates the use of NTFS Transactions to inject a Malicious Binary into a Remote Process without ever touching the disk, so it's a Fileless injection technique that was Undetectable back then when Anti-Virus Scanners didn't know how to catch it. It is not Pretty Common in the World of Malware to use Process Doppleganging, but one of the Interesting Cases was the Dropper for The Osiris Banking Trojan which is the Practical Example for this Injection Method. The Malware makes use of Creating a Transaction in Memory to write a file _Malicious File_ into, in this case and Out of the Transaction, a Section is created in the Process Memory and a Process is Spawned off of the Created Section. For Legitimate Windows Development, Applications use NTFS Transactions to make changes in the File System without breaking the Integrity of the Data, So it Increases the Application Reliability by protecting the data on disk from unexpected errors, Unless the changes made in the Transaction is Commited, no changes will be witnessed on Disk.  

 

 

 

 

// Typical NTFS Transaction Implenetation:

 

// creating an empty transaction
hTransaction = CreateTransaction(NULL,...);

// create a file | open a file inside the transaction
hFile - CreateFileTransacted(FILE_NAME, hTransaction);

// make changes in the file within the transaction
WriteFile(hFile);

// save the changes made on disk
CommitTransaction(hTransaction);

// close FileTransacted && close Transction
closeHandle(hFile);
CloseHandle(hTransaction);

 

For Malware the goal is to be stealthy, so a clear difference in the API Implentation to create a Transaction is noted, No Commits will be made, but rather a Rollback to wipe any changes and not leave a detectabe Malicious File on disk, So the Malicious Binary only exists in Memory with the Illusion that it was executed from a non-existent File/ non-executable File or even a total innocent File.

 

 

 

 

// Malicious Implementation of NTFS-Transaction:

 

/* The Malware will start by creating a Transaction
  and open a file or a windows binary inside the Transaction,
  then it will write/inject a Malicious Code inside the TransactedFile,
  hence the changes are present in the Transaction only.
  Out of the Transaction a Section is Created to contain all information 
  _Malicious Code_ inside the Transaction, 
  This Section is Created so a Process is Created off of it,
  this is done in a non-trivial way using low-level API calls
  _NtCreateProcessEx_ that takes a hSection as a Parameter to Create
  the Process out of it's Content _which is a Malicious EXE_.
  The Malware then would have to Manually set the Process Parameters 
  for it to execute successfully, patch the PEB to redirect 
  to the Malicious Entry Point and Create a Thread inside 
  the created Process to start execution from the patched Entry Point.
*/

// create an empty Transaction
hTransaction = CreateTransaction(NULL, ...);

// open a file inside the Transaction _either a non-exe file or a legitimate binary_
hFileTransacted = CreateFileTransacted(FILE_NAME, ..., hTransaction);

// write the Malicious Payload inside the FileTransacted
WriteFile(hFileTransacted, MALICIOUS_PAYLOAD, SIZE_OF_MALICIOUS_PAYLOAD, ...);

// create a Section out of the Transacted File
hSection = NtCreateSection(&hSection, ..., hTransactedFile);

// rollback changes made in the Transaction
RtlRollbackTransaction(hTransaction);

// create a process using NtCreateProcessEx that takes a hSection containing an EXE
hProcess = NtCreateProcessEx(&hProcess, ..., hSection, ...);

// create a thread object for the newly created process
hThread = NtCreateThreadEx(&hThread, ..., hProcess, MALICIOUS_ENTRY_POINT, ...);

/* Malware will Set up Process Parameters Manually, Patch the PEB to redirect to the MALICIOUS_ENTRY_POINT ..etc */

// execute the process
NtResumeThread(hThread);

         

 

 

 

Process Doppleganging/ Process Hollowing Hybrid:

 

This Typical Process Doppleganging technique is not really common in the wild, but for our Practical Example, The Dropper for the Osiris Banking Trojan used a Hybrid of Process Hollowing and Process Doppleganging, in which the Sample created a non-exe file inside a transaction and injected the Malicious Payload inside it, with a Section made off of the Transacted File, Osiris used Process Hollowing to Map that Section inside a legitimate windows process that is spwaned as a remote process, The Dropper then sets up the process parameters to start executing the thread containing The Malicious Payload.

 

/* Pseudo-Code for Process Doppleganging, Process Hollowing Hybrid used in Osiris Banking Trojan to drop the first stage payload */


/* The Process Hollowing Part involves creating a remote process in a suspended state */
// create a remote process of a legitimate wermgr.exe
hRemoteProcess = CreateProcessW('wermgr.exe', ..., ..., ..., ..., CREATE_SUSPENDED, ...);

/* Osiris would need it's own copy of wermgr.exe 
  to query it's memory blocks and figure out offsets.
  so a smart way to have a mapped copy of wermgr.exe is to open it as a file,
  create a section out of the file, allocate memory with the size of the file 
  and map it inside it's process memory.
*/

hFile = NtCreateFile('wermgr.exe', ...);
hSection = NtCreateSection(&hSection, ..., hFile);
NtMapViewofSection(hSection, FFFFFFFF, ...); // Map the Section inside it's own context

/*--------------------------------------------------------------*/
/* The Process Doppleganging part where Osiris will create a Transaction to
  write Malicious Payload into and Map it into the Remote _Suspended_ Process.
*/

hTransaction = CreateTransaction();

// create and write a file inside the Transaction, this is done by lower level calls
// RtlSetCurrentTransaction instead of CreateFileTransacted

RtlSetFileTransaction(); 
NtCreateFile(); // in Osiris case the file is `Liebert.bmp`

// write Malicious Payload inside TransactedFile
RtlSetCurrentTransaction();
NtWriteFile(hFile, MALICIOUS_PAYLOAD, SIZE_OF_MALICIOUS_PAYLOAD);

// create a Section out of the FileTransacted
hSection = NtCreateSection(&hSection, ..., hFileTransacted, ...);

// rollback transaction and close FileTransacted/ Transaction Handles
ZwRollbackTransaction(hTransaction);
ZwClose();

/* This part reverts to the typical Process Hollowing way where a Section containing an
  EXE will be mapped inside a remote suspended process
*/
// Map the Section Containing Malicious Payload inside remote Process
NtMapViewOfSection(hSection, hRemoteProcess, &BaseAddress, ...);

// process set up , redirection of entrypoint 
// resuming the remote thread
ZwResumeThread(hRemoteProcess);
 

 

 

 

 

// Spotting Process Doppleganging:

 

The existance of a TmTx/TxF is enough, but usually the sample will do a good job in using unhooked APIs as in Osiris Sample where the Dropper mapped it's own copies of NTDLL to evade AV hooks, So eventually tracing into the execution would be the final resort to identify custom implementations of important functions like CreateFileTransactedW.

 

 

Helpful APIs:

[+] CreateTransaction

[+] RollbackTransaction

[+] NtCreateSection

[+] NtCreateProcessEx: Create Process from a Section containing an Executable.

 

 

 

Practical Example: Unpacking Osiris

         

 

 


Malware leverages code injection to perform actions from within the context of another process. By doing so, the malware can force a legitimate process to perform actions on its behalf, such as downloading additional trojans or stealing information from the system. Attackers can inject code into a process in many ways, such as writing to the remote process’s memory directly or adding a registry key that makes new processes load a DLL of the attacker’s choice.

 

[Malware Analyst's Cookbook]