/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:
//Other Injection methods like DLL-Injection and APC-Injection are discussed in future posts.
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.
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.
Practical Example for Self-Injection: Unpacking Dridex
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.
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.
The Sample might start with Spawning another process _could be a legitimate process or even it's own process as a child_ in 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);
Practical Example: Unpacking Parallax
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);
[+] 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.
Practical Example: Unpacking SmokeLoader
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.
[+] 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]