Process injection is an age old technique used by malware for 3 main reasons: Running without a process, placing user-mode hooks for a rootkit or formgrabber, and bypassing antivirus / firewalls by injecting whitelisted processes. The most common method of process injection is DLL Injection, which is popular due to how easy it is. A program can simply drop a DLL to the disk and then use "CreateRemoteThread" to call "LoadLibrary" in the target process, the loader will then take care of the rest. PE Injection is generally favored over DLL Injection by malware, because it does not require dropping any files to the disk.
Portable Executable Basics
When running in memory most, but not all, portable executables make use of 2 structures we need to know about: IAT (Import Address Table), and Reloc (Base Relocation Table). I will briefly explain their purpose, without going into unnecessary detail.
Import Address Table
When a DLL is loaded into memory it is not guaranteed to be loaded at the same address every time, to deal with this: the application makes use of an Import Address Table. The IAT simply allows for the addresses of DLL functions to be set by the PE loader, without having to modify the code of the application. It does this by having all calls to dll functions point to a jump in the processes's own jump table, the IAT then allows the address the jumps targets to easily be found and changed by the PE loader.
Base Relocation Table
As with DLLs, it is also possible that the application itself is not loaded at the same address every time. For the most part this isn't a problem because the application uses relative addressing, however because absolute addresses will need to be changed if the process base address changes, whenever an absolute address is used, it must be easily located. The Base Relocation Table is a table of pointers to every absolute address used in the code. During process initialization, if the process is not being loaded at its base address, the PE loader will modify all the absolute addresses to work with the new base address.
Portable Executable Injection
The Import Address Table and Reloc Table remain in memory once the process initialization is finished, this makes for a very easy way to inject a process. With the ability to be loaded at any base address and use DLLs at any address, the process can simply get its current base address and image size from the PE header, and copy itself to any region of memory in almost any process. Here is the entire procedure broken down.
- Get the current images base address and size (usually from the PE header).
- Allocate enough memory for the image inside the processes own address space (VirtualAlloc).
- Have the process copy its own image into the locally allocated memory (memcpy).
- Allocate memory large enough to fit the image in the target process (VirtualAllocEx).
- Calculate the offset of the reloc table for the image that was copied into the local memory.
- Iterate the reloc table of the local image and modify all absolute addresses to work at the address returned by VirtualAllocEx.
- Copy the local image into the memory region allocated in the target process (WriteProcessMemory).
- Calculate the remote address of the function to be executed in the remote process by subtracting the address of the function in the current process by the base address of the current process, then adding it to the address of the allocated memory in the target process.
- Create a new thread with the start address set to the remote address of the function (CreateRemoteThread).
- In some cases once the image is executed in the remote process, it may have to fix its own IAT so that it can call functions imported from DLLs, however; DLLs are usually at the same address in all processes, so this wouldn't be necessary.
It is usually fairly easy to identify an executable that is attempting to inject into another. There are a few telltale signs to look for. The below tips are just guidelines and can lead to false positives, they also cannot be relied on to identify 100% of all injecting malware.
- A processes allocating memory inside another process (NtAllocateVirtualMemory, VirtualAllocEx, NtMapViewOfSection), especially if the memory is allocated with the PAGE_EXECUTE flag.
- A process setting the PAGE_EXECUTE flag of a memory region in another process (NtProtectVirtualMemory, VirtualProtectEx).
- A process creating a thread in another process (NtCreateThread(Ex), RtlCreateUserThread, CreateRemoteThread), especially if the thread points to code within a memory region, which was also allocated by the same process.
- A process appending code to shared sections.
I will likely extend this article at a later date, possibly even add it to a series of articles about all the different injection methods. I'll also read over the article when I'm less tired and correct any stupid mistakes.