© Abhijit Mohanta, Anoop Saldanha 2020
A. Mohanta, A. SaldanhaMalware Analysis and Detection Engineeringhttps://doi.org/10.1007/978-1-4842-6193-4_10

10. Code Injection, Process Hollowing, and API Hooking

Abhijit Mohanta1  and Anoop Saldanha2
(1)
Independent Cybersecurity Consultant, Bhubaneswar, Odisha, India
(2)
Independent Cybersecurity Consultant, Mangalore, Karnataka, India
 

Malware can drop new files on the system, create new registry keys and values, initiate network connections, create new processes, insert new kernel modules, and so forth. Malware can also force/inject/insert itself into and modify existing running processes, including OS processes and the underlying kernel. But most of these techniques used by the malware for this are not the ones discovered or invented by malware attackers but are techniques used by many of the legitimate software, especially anti-malware products.

In this chapter, we explain various techniques used by malware to inject themselves and execute code in other remote processes running on the system. We also cover in detail various other well-known topics like API hooking and process hollowing.

What Is Code Injection?

Code injection is a technique where a process can insert a part of or all of its code from its own running process into another target process, and get the target process to execute the injected code, as illustrated in Figure 10-1.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig1_HTML.jpg
Figure 10-1

Injector process injecting part or all of its code into the target process and executing it

Code Injection Motives

Code injection is performed in both user mode and kernel mode. Malware mainly uses code injection for the following reasons.
  • Hiding their presence, also known as stealth

  • Process piggybacking

  • Altering functionality of another process or entire OS

Let’s discuss what these motives mean.

Hiding

A malware process wants to avoid easy identification if someone were to check the list of processes running on the system using a Task Manager, and an odd-looking process meets their eye. Similarly, malware might also want to hide from anti-malware products.

To achieve this, the malware process wants to hide its presence, and it does so by injecting all or part of its code into other legitimate processes running on the system (e.g., explorer, svchost, and winlogon) and exiting its primary malware process. Though the primary malware process now has exited, the malware is still running but as a part of another legitimate process via the code it earlier injected. As a result, it now avoids scrutiny and investigation by both users looking at the Task Manager for weird processes, and anti-malware products that might skip investigating and scanning these legitimate system processes, which is illustrated in Figure 10-2.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig2_HTML.jpg
Figure 10-2

Code injection used by malware to provide Stealth/Hiding

Process Piggybacking

If malware wants to connect to the Internet, a firewall on the system might block this from happening, if it tries to connect from its own created process. The reason could be the firewall on the system might allow only a few well-known processes on the system to connect to the Internet. So how can the malware bypass the firewall?

Malware can inject its code and run from other legitimate native processes like explorer, svchost, winlogon, and so forth, which have permission to connect to the Internet. So by piggybacking on the permission and privileges of these other legitimate processes, the malware was able to bypass restrictions put by the OS policies on its own process, as illustrated in Figure 10-3.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig3_HTML.jpg
Figure 10-3

Malware piggybacking other legitimate processes to bypass restrictions by OS

Altering Functionality

Another motive of code injection is to alter the functionality of certain processes or maybe even the entire OS/system. This is largely used by malware for code hooking, rootkits, and API interceptions in attacks such as man-in-the-browser.

Let’s take an example of malware that drops/creates certain files on the system disk, which has the name MalwareFile.exe and it doesn’t want either the user or any anti-malware products to delete it. To delete files on the system, the OS provides the DeleteFile()Win32 API, which is called by the antivirus or users to delete a file on disk.

Now to prevent deletion of its file MalwareFile.exe, all the malware must do is alter the functionality of the DeleteFile() API, and it does by code injection and API hooking. The malware alters DeleteFile() API, thereby hijacking it and then transfer control to its fake version of the API called FakeDeleteFile(). FakeDeleteFile()checks if the user is trying to delete MalwareFile.exe, and if so, it does not delete it. But if the user is trying to delete any other file other than MalwareFile.exe, FakeDeleteFile() doesn’t interfere with the behavior, allowing the system/user to delete the file. This technique is called code hooking , which we explain later in the chapter. The process is illustrated in Figure 10-4.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig4_HTML.jpg
Figure 10-4

Malware carrying out code injection for API hooking to alter API functionality

Code Injection Target

Before injecting code, malware must figure out who and where it wants to inject its code. Malware can inject its code into existing processes running on the system, as well as into the kernel. Alternatively, it can create/spawn a new process off itself in a suspended state and inject code into it.

For user space, we already know that each process has its own private virtual memory space split into user mode and kernel mode address space, as you learned in Chapter 4. The user-mode space of the virtual memory is tampered by another process, even though it is private to the process. If malware injects code into the user-mode part of any other process, only that process is affected by the malware.

Modifying the kernel impacts all processes on the system. But again, injecting into the kernel by adding a kernel module or altering an existing kernel module is not a child’s play. A programmer needs to be extremely careful while playing around with any kernel code, as a small mistake can dramatically impact the system and may lead to a system crash. On the other hand, the kernel is highly protected and not that easy to modify, making it not the most sought-after destination for malware.

Popular Code Injection Techniques

There are various code injection techniques. Some of these techniques are popular. Some of them are a combination of two or more other techniques. Some of the popular terminologies, features, and techniques related to code injection are listed. We go into the technical details of each of these techniques with hands-on exercises in later sections.
  • Process hollowing

  • Thread injection

  • DLL injection
    • Classical DLL injection

    • Reflective DLL injection

  • Shellcode injection

  • Code cave

  • QueueUserAPC

  • Atom bombing

Steps for Code Injection

Code injection is largely handled in the following steps.
  1. 1.

    Locate the target for code injection.

     
  2. 2.
    Inject the code.
    1. a.

      Allocate/create memory/space in the target process of virtual memory.

       
    2. b.

      Write/inject code into the allocated memory/space in the target

       
     
  3. 3.

    Execute the injected code in the target.

     

In the next set of sections, we run through the technical details. We also list various details, tips, and important points we need to remember as analysts so that we can correlate them with similar activity when we analyze malware.

Steps for Process User-Mode Code Injection

User-mode code injection involves all the steps discussed, with the only difference being the target is a process. The target process is often referred to as the remote process or target process. The process that does the injection is often called the injector process . At a high level, the whole process can be described. In the following steps, we use pseudo API names called MemAlloc(), WriteRemoteMemory(), and ExecuteInjectedCode() to simplify your understanding. In the subsequent subsections, we introduce you to and describe the exact APIs used in the code injection process.
  1. 1.

    An injector process selects the target process into which it wants to inject its code, as described by Figure 10-5. You can also see that the current instruction pointer in the target process is pointing to and executing the target process’s code.

     
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig5_HTML.jpg
Figure 10-5

The injector process selects a target process to Inject Into

  1. 2.

    Now that the target process has been figured out, the injector process allocates memory in the target process, and it does so by calling an API MemAlloc() , as seen in Figure 10-6.

     
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig6_HTML.jpg
Figure 10-6

The injector process allocating memory in the remote target process

  1. 3.

    Now that memory has been allocated in the target process, the injector process copies its code into the allocated space using the WriteRemoteMemory()API , as seen in Figure 10-7.

     
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig7_HTML.jpg
Figure 10-7

The injector process copies its code into the remote allocated memory

  1. 4.

    After copying the code into the target process, the injector process needs to make sure that the target process runs its injected code and that the instruction pointer point to its code. It does so by calling the ExecuteInjectedCode() API. As you can see in Figure 10-8, the instruction pointer now points to and executes the injected code.

     
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig8_HTML.jpg
Figure 10-8

The injector process executes the injected code in the remote target process

This should give you a high-level overview of how code injection works in User Space. In the next set of subsections, we go into detailed technical details on how code injection works and work with hands-on exercises to see the whole process in action.

Step 1: Locating the Target Process

Malware may want to inject its code into system processes like Explorer or svchost or browsers like Chrome and Firefox. To inject code into a process, it first needs to open the process using an OpenProcess()Win32 API, which takes the PID of the process as a parameter. But how does the malware know the PID of its target process?

For this, malware uses a set of APIs available on Windows to search for the target process by name and, once found, retrieve its PID. The APIs in question are CreateTool32HelpSnapshot(), Process32First() and Process32Next().

Malware first wants to get a list of all processes running on the system, which it gets using the help of the CreateTool32HelpSnapshot()API. This API returns a linked list of processes, where each node represents details of the process, represented by a structure called PROCESSENTRY32.

The PROCESSENTRY32 structure contains various details of the process, including the name and the PID of the process. The returned linked list of processes is then iterated using the help of the Process32First() and Process32Next()APIs. For each node in the list, if the name of the process matches the name of the process that the malware intends to inject into, the malware uses the PID of that process for its subsequent operations and APIs, including in the call to OpenProcess().

Listing 10-1 shows a sample code excerpt that gets the list of processes running on the system.
HANDLE hSnapshot;
DWORD remote_pid;
hSnapshot= CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
/* PROC_NAME holds the name of the process the malware
 * wants to inject into */
if (Process32FirstW(hSnapshot, &entry)) {
    do {
        if (!_wcsicmp(PROC_NAME, entry.szExeFile)) {
            /* Match found for PROC_NAME. Extract PID */
            remote_pid = entry.th32ProcessID;
            break;
        }
    } while (Process32NextW(hSnapshot, &entry));
}
Listing 10-1

Sample Code Snippet That Obtains the List of Processes Running on the System

Now you can run Sample-10-1 from the samples repo, which utilizes the code in Listing 10-1 and prints the process name and PID of every process running on the system. You must add the .exe extension suffix to the sample file. To run the sample, you can open the command prompt and execute the sample, as seen in Figure 10-9. The partial output of running this sample is seen in Figure 10-9. You can verify the output by opening Process Hacker and comparing the process name and PID value to the ones printed by the sample.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig9_HTML.jpg
Figure 10-9

Sample-10-1 outputs the list of process names and their PID on the system

Instead of the malware picking a target process from a set of existing processes running on a system, malware is also known to spawn/create a new process out of a native clean program on the system but in a suspended state. After creating this suspended process, it then injects its code into this suspended process and then resume the process but from its injected code. In this case, you see two new sets of additional APIs: CreateProcess() or its variations in step 1, and ResumeThread() or its variations in step 4.

The following is a list of the important APIs in step 1 of code injection. As analysts, we need to remember these APIs. It is handy to know them during dynamic analysis, where a detection tool like APIMiner can help you visualize the APIs used by a malware process. Knowing that a malware process uses a certain set of APIs, like the ones listed next, helps us investigate whether the malware process is carrying code injection or not.
  • CreateToolhelp32Snapshot

  • Process32First

  • Process32Next

  • CreateProcessA

  • CreateProcessW

  • CreateProcessInternalW

  • CreateProcessInternalA

Step 2: Allocating Memory in a Remote Target Process

Now that we have the PID, we can open a handle to the remote process. Most operations and API calls to the remote process are against the process handle. Do note that the injector process needs to obtain debug privileges to manipulate the virtual memory of the target process, and hence a handle to the process has to be opened in debug mode (PROCESS_ALL_ACCCESS covers all privilege types). It does this by calling the OpenProcess()API, as seen in Listing 10-2.
/* Opens handle to the process with ALL privileges including
 * debug privileges */
HANDLE remote_process_handle = OpenProcess(PROCESS_ALL_ACCESS,
                                         TRUE,
                                         remote_process_pid);
Listing 10-2

Sample Code That Opens a Handle to a Process with Debug Privileges

You do need to be aware of the fact that every process is treated like an object on Windows. A process object has certain attributes, which include privilege level. A security token is associated with a process that decides which resources a process can access. Certain APIs cannot be successfully called by the process if it does not have the required privileges. The injector process can obtain these privileges by adjusting the security tokens. This is done by the injector process by using a sequence of API calls, which include OpenProcessToken(), LookupPrivilegeValue(), and AdjustTokenPrivileges(). Using these APIs, the injector process can adjust its privilege. For more information on the API, you can look it up on MSDN.

After obtaining the handle to the target process, the injector process now allocates memory in the target process by calling the API VirtualAllocEx(), as seen in Listing 10-3.
LPVOID allocated_adddress;
/* size_to_allocate holds the size of the memory that needs to
 * be allocated in the remote target process
 * process_handle - Handle of the target process from Step2
 * size_to_allocate - Size of the memory that needs to be
 *                    allocated in the target process
 * PAGE_EXECUTE_READWRITE - Permissions for memory allocated
 */
allocated_address = VirtualAllocEx(process_handle,
                                   NULL,
                                   size_to_allocate,
                                   MEM_COMMIT,
                                   PAGE_EXECUTE_READWRITE);
Listing 10-3

Sample Code That Allocates Memory in Remote Process

VirtualAllocEx() allocates memory of the requested size(size_to_allocate) in the remote target process identified by the process HANDLE. Another thing that you may have noticed is the permission of the memory above PAGE_EXECUTE_READWRITE. You learned about page permissions in Chapter 4. When you are specifying VirtualAllocEx() API, you can specify the permissions to assign to the allocated memory or rather to the pages in allocated memory. In this particular case, it is all read, write, and execute permissions because the injector process wants to first write code into the memory; hence, it has write permissions. After that, since it wants to execute the written/injected code, it has execute permissions.

To see the APIs in action, we can now run Sample-10-2, which we illustrated in Figure 10-10. Make sure you add the .exe extension suffix to the sample. The sample is an interactive sample that you need to run from the command prompt. The sample requests you to start Notepad.exe so that it can allocate memory in it. Once you start Notepad.exe, you can obtain the PID using Process Hacker, and enter it when the sample requests you to. You can also enter the size and the permissions of the memory you want to allocate in the remote process. The sample then allocates memory using VirtualAllocEx(), which you can verify in the remote process (Notepad.exe) using Process Hacker.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig10_HTML.jpg
Figure 10-10

Output from interactive Sample-10-2 that allocates memory in a remote process

Note

An alternate method to VirtualAllocEx() and WriteProcessMemory() that is used in steps 2 and 3. In this method, the malware uses sections and views, where it maps a part of its memory to the target process, basically creating a reflection of a part of its memory in the target process. To do so, it uses another set of APIs.

We now verify if the memory is allocated by checking the memory of the Notepad.exe process using Process Hacker, as seen in Figure 10-11. You see a new memory size of 4096 bytes allocated at address 0x1e0000 as described by the sample program output in Figure 10-10. Do note that the output of running the sample might vary on your machine since the address of the memory allocated might be different.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig11_HTML.jpg
Figure 10-11

Verifying that the memory was allocated by Sample-10-2 in Notepad.exe

We recommend that you play around more with Sample-10-2, trying out various other memory permissions (1–5) and memory sizes, and verifying in Process Hacker that memory is allocated in the remote process.

An alternative to setting EXECUTE permissions while allocating memory, the malware can first allocate memory but using just READ_WRITE permissions and later after step 3, but before we enter step 4, manually change the permissions of the allocated memory to EXECUTE as well using the API VirtualProtect(). So while analyzing malware samples, you have to watch out not just for VirtualAllocEx() API but also VirtualProtect(). If you see a combination of these two APIs operating against a remote process, there’s something fishy going on, and it deserves more investigation from the point of view of code injection and malware infection.

The following is a list of the important APIs from step 2 in code injection.
  • OpenProcess

  • VirtualAllocEx

  • LookupPrivilegeValue

  • AdjustTokenPrivileges

  • OpenProcessToken

  • VirtualProtect

Step 3: Writing into Remote Target Memory

After space is allocated, the code that needs to be executed in the target process is copied into the target process using WriteProcessMemory() API , as seen in Listing 10-4.
str = “MALWARE ANALYSIS AND DETECTION ENGINEERING”
WriteProcessMemory(process_handle,
                   allocated_address,
                   str,
                   SIZE_T)(strlen(str) + 1),
                   &numBytesWritten)
Listing 10-4

Sample Code That Allocates Memory in Remote Process

To see the APIs in action, we can now run Sample-10-3, which we have illustrated in Figure 10-12. Don’t forget to add the .exe file suffix extension to the sample. The sample is an interactive sample that you need to run from the command prompt, very similar to Sample-10-2 in the previous section, with the extra addition being it writes into the allocated memory the string MALWARE ANALYSIS AND DETECTION ENGINEERING. The sample uses the WriteProcessMemory() API to write the string into the allocated memory.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig12_HTML.jpg
Figure 10-12

Output from Sample-10-3 that allocates memory and writes into remote process

We now verify if the memory is allocated and the string written to it by checking the contents of the memory location 0x350000 of the Notepad.exe process using Process Hacker, as seen in Figure 10-13. Do note that the address location allocated on your system might vary from the one we have specified here. Please pick the allocated address as indicated by the output of this sample process on your system.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig13_HTML.jpg
Figure 10-13

Verifying that memory was written into Notepad as seen in Sample-10-3 output

The method mentioned in step 2 and step 3, which uses VirtualAllocEx() and WriteProcessMemory() to allocate memory and code into the target process, is quite common in most malware.

There exists another method of allocating memory and copying code from the injector process into the target process, which involves section objects and views. Before we head into step 4, let’s investigate this alternate technique.

Section Object and Section Views

Section objects and views is a provision by Windows in which a portion of virtual memory belonging to a process is shared/mapped with/into other processes.

There are two processes: the injector process and the target process. The injector process wants to map some of its code and data into the target process. To do this, the injector process first starts by creating a Section object by calling the NtCreateSection() API, as seen in Figure 10-14. Creating a section object doesn’t mean any memory is allocated in its virtual memory. Or at least not yet. While creating a Section object, it can also specify its size in bytes.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig14_HTML.jpg
Figure 10-14

The injector process creating a section

Now that the injector process has created a section, it creates a view of this section, which allocates memory for this section in the virtual memory. The injector process using the NTMapViewOfSection() API creates two views of the same section it earlier created: one locally in its own process and another in the target process, as seen in Figure 10-15.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig15_HTML.jpg
Figure 10-15

View of a section in both the Injector and target process

The multiple views created act as a mirror image. If the injector process modifies the contents in its own view, it automatically is reflected in the view of the target process, as illustrated in Figure 10-16.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig16_HTML.jpg
Figure 10-16

Contents of a view automatically are copied into views in other processes

Malware is known to use this feature to inject code into a target process, instead of always relying on APIs like VirtualAllocEx() and WriteProcessMemory(), where malware using sections and views writes its malicious injected code in its own view, and it automatically is copied/reflected in the view of the target process. While any code injection technique can use this method, it is more commonly used in a technique called process hollowing (also called RunPE), which we cover in detail in a later section.

The following is a list of the important APIs from step 3 in code injection. As analysts, we need to remember these APIs come in handy during dynamic analysis.
  • WriteProcessMemory

  • NtUnmapViewOfSection

  • NtCreateSection

  • NtMapViewOfSection

Step 4: Executing Code in Remote Process

Now that the injector process has injected its code into the target process, it now needs to get the target process to run this injected code. Several techniques have been developed to execute the injected code in the target process. The following are the most popular.
  • Remote thread creation APIs. Using APIs like CreateRemoteThread() and other similar APIs, the injector process can create threads in the target process.

  • Asynchronous procedure call (APC) queues

  • Altering thread context. The instruction pointer of an existing current thread in the remote/target process is made to point to the injected code, using the GetThreadContext() and SetThreadContext()APIs.

Remote Thread Creation API
In this technique, the malware spawn/create a brand-new thread in the target process but pointing this thread it to run from its injected code. This is illustrated in Figure 10-17.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig17_HTML.jpg
Figure 10-17

Injector process creating a remote thread in the target process to run injected code

Some of the APIs that are used by malware to create a remote thread are CreateRemoteThread(), RtlCreateUserThread(), and NtCreateThreadEx().

To see this technique in action, you can run Sample-10-4 from the samples repo, whose output from my run is seen in Figure 10-18. Do note to the add the .exe extension suffix to the sample. The sample very similar to the earlier samples takes the PID of the target process in which it creates the remote thread. The sample request you to open Notepad.exe to use it as the target process for the exercise. Once you open Notepad.exe, go down to Process Hacker and make a note of no of threads currently used by the Notepad.exe process, as seen in the top right of Figure 10-18. After fully running the sample, you can then recheck the no of threads in Notepad.exe to observe a newly created thread that was created by the injector process Sample-10-4.exe, as seen in the bottom of Figure 10-19.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig18_HTML.jpg
Figure 10-18

Output from Sample-10-14 which creates a thread in remote process Notepad

../images/491809_1_En_10_Chapter/491809_1_En_10_Fig19_HTML.jpg
Figure 10-19

Verifying the remote thread created in Notepad.exe target process

As seen in Figure 10-19, you can see an extra thread created, which has been created by the injector process.

Asynchronous Procedure Call (APC) Queues

Creating a new thread is sometimes an overhead as new resources need to be allocated to start the thread. Creating a new thread in a remote thread can easily be detected by anti-malware products that are listening to the event log and logs such an event as suspicious.

So instead of creating a remote thread to execute the injected code, we can request one of the existing running threads in the remote target process to run the injected code. This is done using an asynchronous procedure call (APC) queue. Let’s now look at how it works.

APC is a method for already executing threads within an application to take a break from their current tasks and perform another queued task or function asynchronously, and then return and continue from where it left off. But a thread can’t just randomly run these tasks/functions that are queued to it. It can only run these tasks when it enters an alertable state.

A thread enters an alertable state when it calls one of these APIs: SleepEx(), WaitForSingleObjectEx(), WaitForMultipleObjectsEx(), SignalObjectAndWait(), and MsgWaitForMultipleObjects(). When a thread enters an alertable state by calling any of these APIs, it checks its APC queue for any queued task or functions; and if any, it executes them and then returns to where it left off. The APC process is described in Figure 10-20.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig20_HTML.jpg
Figure 10-20

injector process Using APCs to execute injected code in the target process

To queue a task into the APC queue of the target process, the injector process calls the QueueUserAPC()API.

Malware misuses this Windows feature by injecting a malicious code that contains a function in a remote/target process’ memory, then queue that injected function as APC into the remote process’ APC queue.

Altering the Thread Context

Every thread in a process has an EIP or instruction pointer, which holds the address of the code/instruction the thread is currently executing. The EIP of a thread is held in the thread’s context. Once the code is injected into the remote target process, an injector process can reset the EIP of a thread on the target process to point to the injected code, thereby forcing the target process to run its injected code.

The following steps carry this out.
  1. 1.

    The remote thread whose context must be modified should be suspended first. If the thread is not suspended already, it is suspended by calling the SuspendThread()API.

     
  2. 2.

    The current context of the remote thread is obtained using the GetThreadContext()API, which returns the context structure, which holds the context of the thread, including the current EIP of the thread.

     
  3. 3.

    The EIP field in the context structure is modified to point to the address of the injected code that should be executed.

     
  4. 4.

    With the modified context, the injector process then calls SetThreadContext() to reset the instruction pointer of the remote thread to the value set in the EIP field of the context.

     
  5. 5.

    Call ResumeThread() to resume the suspended thread, which now executes from the injected code.

     
Listing 10-5 shows the structure of the CONTEXT struct that holds the context of a thread. It has a field named EIP that points to the address of the current code/instruction that the thread is executing.
typedef struct _CONTEXT
{
    ULONG ContextFlags;
    ..............
    ULONG Ecx;
    ULONG Eax;
    ULONG Ebp;
    ULONG Eip; // Holds instruction pointer
    .........
} CONTEXT, *PCONTEXT;
Listing 10-5

CONTEXT Struct Holds the State of a Thread, Including EIP, the Instruction Pointer

The following is a list of the important APIs from step 4 in code injection.
  • QueueUserAPC

  • SuspendThread

  • ResumeThread

  • CreateRemoteThread

  • RtlCreateUserThread

  • NtCreateThreadEx

  • GetThreadContext

  • SetThreadContext

In the next set of sections, we stitch together what you learned and run more hands-on exercises that detail full-fledged code injection techniques.

Classical DLL Injection

Malware is usually delivered as multiple components, where there is a main component like a downloader/loader whose main job is to download secondary components or payloads either from the C2 server or its own resource section and load/run them. These secondary components are an executable PE file, DLL files, and so forth. If it is an executable PE file, the loader can easily run it. With DLLs, it is not that straightforward. Although there are tools like rundll32.exe that can simulate loading and running a DLL, most often with malware, these secondary payload DLLs are rather injected, loaded, and run from another clean target process.

You learned in Chapter 4 that when a process loads a DLL, a DLL module is loaded in memory at any image base address. Now let’s take the example of two processes—Process1 and Process2, both of which load the same DLL file. If Process1 loads a DLL and it gets loaded at image base address 0x30000, Process2, when it loads the same DLL from disk, it might get loaded at a different image base address 0x40000. The DLLs need not have the same image base address in two or more different processes, as illustrated in Figure 10-21.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig21_HTML.jpg
Figure 10-21

Same DLLs loaded at different image base in different process

But there’s an exception to this rule. There are some system DLLs provided by Windows, which are loaded in all processes at the same image base address. Kernel32.dll is one such DLL. For example, if kernel32.dll is loaded at the 0x30000 address image base in one process, then we can expect that it is loaded at the same image base in every other process’ virtual memory on the system, as illustrated in Figure 10-22.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig22_HTML.jpg
Figure 10-22

Kernel32.dll loaded at the same image base in all process’s virtual memory

The important point about kernel32.dll having the same image base forms the foundation of Classical DLL Injection. With that in mind, the injection of a DLL into a target process is best described by the following steps,
  1. 1.

    DLL lies on the hard disk as a file that needs to be loaded into the target process’s memory.

     
  2. 2.

    The injector process first allocates memory in the target process, with the size of memory allocation, which is equal to the length of the path of the DLL file. For example, if the path of the DLL file on the disk is C:Malware.dll, the size it allocates is 15 characters (including the trailing NULL character in the string).

     
  3. 3.

    It copies the path of the DLL file (i.e., C:Malware.dll) to the memory allocated in the target process from step 2. Figure 10-23 illustrates steps 1, 2, and 3.

     
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig23_HTML.jpg
Figure 10-23

Injector allocates memory in the target and copies the path of the DLL into it

  1. 4.

    The LoadLibrary() API is implemented inside Kernel32.dll, which loads a DLL from disk into a process’s memory. The injector process needs to somehow force the target process to invoke LoadLibrary() while passing to it the path of the DLL so that the DLL is loaded into its address space.

     
  2. 5.

    The injector process exploits the fact that KERNEL32.DLL has the same image base address in both the injector process and target process, which in turn means the address of LoadLibrary() API is the same in both the processes. So the injector process just has to obtain the address of LoadLibrary() API from its own address space.

     
  3. 6.

    The injector process obtains the address of LoadLibrary() API from its own address space using the code in Listing 10-6.

     
HMODULE hKernel32 = GetModuleHandleW(L"kernel32.dll"); PAPCFUNC pLoadLibrary = (PAPCFUNC)GetProcAddress(hKernel32, "LoadLibraryW");.
Listing 10-6

Obtaining the Address of LoadLibrary() API using GetProcessAddress() API

  1. 7.

    Now that the Injector has the address of LoadLibrary(), it can use either CreateRemoteThread() or QueueUserAPC() to force the target process to run LoadLibrary(). An additional argument is also supplied to CreateRemoteThread() or QueueUserAPC() , which in turn pass this argument to LoadLibrary() API when they invoke it. The additional argument that is passed is the memory location/buffer in the target process containing the DLL path from step 2. Figure 10-24 illustrates steps 4–7.

     
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig24_HTML.jpg
Figure 10-24

The injector creates a remote thread in target and makes it invoke LoadLibrary()

Let’s now see DLL Injection in action. Copy Sample-10-5b and Sample-10-5 to the C drive. Add the .dll extension suffix to Sample-10-5b so that it is now named Sample-10-5b.dll. Add the .exe extension to Sample-10-5, making it Sample-10-5.exe. Now, Sample-10-5.exe is the injector program, and Sample-10-5b.dll is the DLL to be injected. Sample-10-5.exe is an interactive program, which takes a dummy process’ PID into which it injects the DLL. For the dummy process, we use Notepad. It also asks the user for the full path of the DLL to inject, which in our case is C:/Sample-10-5b.dll. The sample output from Sample-10-5.exe is seen in Figure 10-25.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig25_HTML.jpg
Figure 10-25

The output from running Sample-10-5.exe, which injects Sample-10-5b.dll into Notepad.exe

Once Sample-10-5.exe finishes execution, you see that Sample-10-5b.dll has been loaded into Notepad.exe’s memory as a module/DLL, as seen in Process Hacker Modules tab of the Notepad.exe process, shown in Figure 10-26.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig26_HTML.jpg
Figure 10-26

Sample-10-5.dll has been loaded into Notepad.exe’s memory

Process Hollowing

One of the big requirements of malware is that they need stealth/hiding. If a malware process runs on its own and if a user casually browses the Task Manager, they notice a weirdly named malware process running, which might raise their suspicions that it is not a benign process. To counter this, the malware might rename itself as svchost.exe, explorer.exe, or with the name of any other system/clean process to beat the scrutiny of a casual observer. But just renaming the malware filename doesn’t change the true properties of the malware. For example, by default, system programs like svchost.exe, are in the C:Windowssystem32 directory. If you verify the properties of any of the malware file which has renamed it as svchost.exe, you still notice that the path of this process is not C:Windowssystem32svchost.exe, because of which a highly observant user or even anti-malware products can easily catch such malware.

To counter this malware, authors devised a new technique called process hollowing, which works by launching one of the existing systems/clean programs but in a suspended state. Once launched in a suspended state, the malware process scoop/hollow out the actual inner code and data of the target system/clean process, and replace it with its own malicious content. Since the process was originally launched from its own system/clean program on disk, the path of the process still points to the original clean/system program on disk. But, it now holds the malware code running from within the process. The whole process is better explained using Figure 10-27.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig27_HTML.jpg
Figure 10-27

High-level overview of the process hollowing technique

Let’s now try out Sample-10-6, which is an interactive sample. Do note that you must add the .exe file suffix extension to the sample. You also need to run the sample from the command prompt. Sample-10-6.exe is an interactive sample that process hollows the calculator process calc.exe, which you might have used various times while you needed to carry out some numerical calculations. You can run the sample using command prompt, the output of which looks similar to Figure 10-28. Do note that the addresses shown in the following figures might vary from what is mapped in your system while you run the sample.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig28_HTML.jpg
Figure 10-28

Sample program that hollows out calc.exe process injects code into it and runs it

To see how it works, re-run the exercise, and perform the following steps.
  1. 1.

    When you run Sample-10-6.exe as in Figure 10-28, it first starts the calculator process calc.exe in suspended mode, as seen in Figure 10-29.

     
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig29_HTML.jpg
Figure 10-29

Sample-10-6.exe starts calc.exe in suspended state as seen in the gray background

  1. 2.

    Press any key to continue. The sample then creates a section and a view of the section in the calc.exe process . As seen in the output of the sample in Figure 10-28, the view is mapped at address 0x3b0000 in Sample-10-6.exe and address 0xa0000 in calc.exe. You can verify this using Process Hacker, as seen in Figure 10-30. Do note that the addresses might be different when you run the sample, and you can obtain your addresses from the output of your sample run (see Figure 10-28). The NtCreateSection() API creates a section and NtMapViewOfSection()creates a view.

     
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig30_HTML.jpg
Figure 10-30

Sample creates two views of the section, one in itself and other in calc.exe

  1. 3.

    You can now press any key to continue. This should continue with the hollowing process, and the sample now copies/injects its code into its local view, which automatically reflects/maps it into the view of calc.exe. Alternatively, do note that the malware can allocate memory in calc.exe and copy/inject its code using VirtualAllocEx() and WriteProcessMemory() , instead of using Section and View.

     
  2. 4.

    With the hollowing process complete and code injection/copying done, the sample now reset the instruction pointer of the suspended process calc.exe by having it point to the newly injected code in its view, after which it resumes the suspended calc.exe process/thread, which should run the injected code. To reset the instruction pointer to the injected code, the sample uses the GetThreadContext() and SetThreadContext() APIs. To resume the suspended thread, it uses the ResumeThread()API .

     
With our injected code now running inside calc.exe, instead of calc.exe’s real calculator program/code running, our injected code will now run which pops up a message box as seen in Figure 10-31. It also creates a file called PROCESS_HOLLOWED_CALCULATOR.txt in the same folder as the sample, which can also be seen in Figure 10-31.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig31_HTML.jpg
Figure 10-31

Injected code running from within calc.exe

Classical Shellcode Injection

In classical DLL injection, the DLL is injected via a LoadLibrary(). The end goal of the injector is to inject a full DLL PE file into the target process. We know that with a DLL PE file, it starts with the PE header, and then the code is located somewhere further down, which is what is executed by the Injector using LoadLibrary(). But at the start of the PE file, it is the PE header before the code that holds the information for LoadLibrary() on how to set up the code in memory, including fixing the import table and relocation table.

Shellcode is simply straight code, like the code in a PE file like a DLL or an executable, but there is no PE header accompanying this shellcode. It can’t be loaded by LoadLibrary() or the Windows loader. It has no headers that contain any information that can help a loader for any address relocations fixes or other API dependencies resolution.

From a technique and APIs usage perspective, classical shellcode injection works very similarly to the injection technique we mentioned in the section steps of code injection or classical DLL injection. Memory is allocated in the target process. The shellcode is copied over instead of a full DLL PE file or an executable PE file, and the shellcode is executed directly in the target process. The injector process after injecting the shellcode must do any relocations, and import table fixes manually since there is no Windows loader to do that job.

Figure 10-32 explains the key difference between DLL injection and shellcode injection. The top shows a full DLL injection, while the bottom shows only shellcode injection. With shellcode injection, the header isn’t injected/copied into the target process.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig32_HTML.jpg
Figure 10-32

Difference between DLL/PE injection vs. shellcode injection

Reflective DLL Injection

Malware consists of multiple components, and usually the primary downloader/loader component of the malware downloads secondary components like a malicious DLL/EXE from the C2 server over the network, or its resource section. These malicious DLLs are then injected into other target processes. But with classical DLL injection, the DLL component injected into the target process is a file on the disk, which is loaded using the LoadLibrary() API. The fact that it is a file on disk and you also use LoadLibrary() API to inject into a target process isn’t very stealthy and is easily caught.

Only if there was a way where after obtaining the DLL PE file over the network or from its resource section the malware downloader/loader component could inject and load it directly into the target process without having to write it to file on the disk and without having to use LoadLibrary(). Yes, this is still possible with another technique called reflective DLL injection.

Reflective DLL injection works by having the downloader/loader, double as a Windows loader. So instead of relying on the Windows loader via the call to LoadLibrary() API, the injector process does the job of loading the DLL as a module in memory of a target process. Also, it needs to carry out two important operations otherwise carried out by the Windows loader—fixing the relocation table and the import table which you learned in Chapter 4. We won’t go into the depths of how each of these steps in reflective DLL injection works. As an exercise, there are various resources on the web that you can refer to, to learn how this technique works.

Important APIs to Remember

As analysts, we can easily catch these malware samples under dynamic analysis. We can catch malware that uses these code injection techniques a lot of times using mere common sense. We cover these techniques more in Chapter 13. But another easy and important way to catch these techniques used by malware is by using the APIs they use. By using an API Logger like APIMiner, we can easily identify the APIs used by the malware and help identify such code injection techniques. It is important to remember all the various APIs that are used by malware for code injection. At the end of this chapter, we cover APIMiner and use it in conjunction with one of the exercises. As an exercise, we recommend running all the exercises in this chapter using APIMiner and inspect the API log files generated by the tool and use these API logs to identify all these various code injection techniques.

In the previous sections, we listed the various APIs that are used by various code injection techniques. The following list aggregates those APIs. Again, analysts need to remember them to identify malware and the various code injection techniques they use. Do note that this list is not comprehensive. Malware might use variants of the following APIs and might use new undocumented techniques that use other APIs. You should read more about the new techniques and APIs that malware uses and builds up your knowledge base to help us quickly identify malware.
  • CreateProcessA

  • CreateProcessW

  • CreateProcessInternalW

  • CreateProcessInternalA

  • Process32Next

  • Process32First

  • CreateToolhelp32Snapshot

  • OpenProcess

  • VirtualAllocEx

  • LookupPrivilegeValue

  • AdjustTokenPrivileges

  • OpenProcessToken

  • VirtualProtect

  • WriteProcessMemory

  • NtUnmapViewOfSection

  • NtCreateSection

  • NtMapViewOfSection

  • QueueUserAPC

  • SuspendThread

  • ResumeThread

  • CreateRemoteThread

  • RtlCreateUserThread

  • NtCreateThreadEx

  • GetThreadContext

  • SetThreadContext

Why Do These Malicious APIs Exist?

You might be wondering why Microsoft and Windows (Win32) have made these APIs that aid techniques like code injection and that is used by malware to meddle with other processes, access their memory, write into their memory. Does Microsoft support writing malware?

The reason why Microsoft provides these APIs is that they are meant for legitimate use by clean software, like debuggers, but unfortunately, these very same APIs are misused by malware. Debuggers use these APIs to manipulate the virtual memory of remote processes so that breakpoints are set, instructions in memory are altered so on and so forth.

In the next section, you learn about one of the most important techniques used by malware that relies on remote code injection and code/API hooking.

Code/API Hooking

One of the motives behind code injection is API hooking, which is a way to intercept a call made to a legitimate API by a program, just like a middle-man. The intention is varied depending on the needs of the malware. For example, malware might want to prevent the deletion of its file, and to do so, it might intercept calls to API that deletes files. It might want to intercept calls that pass credentials to the API. It might want to intercept calls that hide its presence in the list of processes in the Task Manager. The list goes on.

Code/API hooking is split into four major steps.
  1. 1.

    The malware that is the injector process first identifies the target process whose APIs it wants to intercept/hook.

     
  2. 2.

    Now that the target process has been identified, the malware/injector process first injects its code into the target process using code injection. This is where code injection techniques come in.

     
  3. 3.

    The injected code is run within the target process.

     
  4. 4.

    The injected code, which is now run inside the target process, locates various APIs within the target process and places hooks into them. After placing the hooks, all the calls made to those hooked APIs by the target process are redirected to the malware’s injected code.

     

Identify Hooking Point/Target

You learned about identifying the hooking point or location to place the hook for Interception, basically step 4 from the previous section. Let’s take the example of a Win32 API call made by your program—DeleteFile(), as illustrated in Figure 10-33.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig33_HTML.jpg
Figure 10-33

Flow of control from a Win32 call made by our program all the way to the kernel

When our process makes a call to a Win32 API (DeleteFile() in our case), it takes multiple hops via its own IAT, which holds the address of the DeleteFile() function located in Kernel32.dll. This DLL then redirects it to another function, NtDeleteFile(), located in ntdll.dll. This DLL then redirects it into the kernel via a syscall, which finally talks to the file system driver.

Now there are multiple locations where a hook is placed. It is highlighted in yellow: 1, 2, 3, 4, 5, and 6. At a high level, locations 1, 2, and 3 are user space hook locations and 4, 5, and 6 are kernel space hook locations.

In the next section, we explain the various techniques of placing hooks in the user space.

Placing Hooks in User Space

In the previous section, we identified various points where hooks can be placed in the user space in the code flow of an API call. Let’s look at how these hooks are created. There are two main techniques for placing hooks in the user space.
  • IAT hooking

  • Inline hooking

Before we dig into these two techniques, let’s revisit how a normal API call is placed by using Figure 10-34 as an example.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig34_HTML.jpg
Figure 10-34

Flow of control from a Win32 API call made to the actual function code for the API

As you can see in the diagram, when a process calls an API like DeleteFile(), which is located in another module (Kernel32.dll), the process obtains the address of Kernel32.DeleteFile() by referring to its IAT (import address table). The IAT acts like a jump table. Using the address obtained from the IAT, the process can jump and reach the function code for DeleteFile() located in Kernel32.dll.

This is pretty much how the code flows for every API call. Now let’s investigate the two hooking techniques that malware can use to plug itself into the code flow to place its hook.

IAT Hooking

With IAT hooking , all the malware does is replace the address of DeleteFile() in the IAT table to the address of a fake malicious DeleteFile() that the malware provides in its injected code. Now when the process calls DeleteFile() API and refers its IAT, the address of DeleteFile() in IAT points to the fake malware DeleteFile(), thereby redirecting all DeleteFile() API calls to the malicious DeleteFile() in the injected malware code. Figure 10-35 shows IAT hooking in action. You can use Figure 10-34 as a reference and compare it to the changes made by IAT hooking in Figure 10-35.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig35_HTML.jpg
Figure 10-35

IAT hooking for API code hooking

Inline Hooking

One of the defects of IAT hooking is that sometimes the code in a process might call an API in another DLL without needing to obtain the address of the API it needs from the IAT. So malware modifying the IAT with the address of its malicious code is useless. This defect can be solved by using inline hooking.

With inline hooking, the malware modifies the first few instructions in the real Kernel32.DeleteFile() API by inserting new instructions that effectively transfer the code flow to the malware injected code. This is best illustrated in Figure 10-36.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig36_HTML.jpg
Figure 10-36

Inline hooking for API Code hooking

An alternate illustration of how the Hooked API Function Code looks after inline API hooking is seen in Figure 10-37.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig37_HTML.jpg
Figure 10-37

How the modified API looks post inline API hooking

So far, we have seen now how the code hooks can be placed in user mode. But code hooks can also be placed in kernel mode. For user-mode hooks, the injector process first injects code into the target process, and when the injected code runs in the target process, it places the hooks. For kernel-mode hooks, similarly, a kernel module needs to be injected into the kernel, which creates the hooks in kernel space. We cover kernel-mode hooks in Chapter 11.

Why a Malware Hooks?

Processes perform a lot of operations on the system. Here are some of those.
  1. 1.
    File Operation
    1. a.

      File Creation

       
    2. b.

      File Deletion

       
    3. c.

      Writing to file

       
     
  2. 2.
    Registry Operations
    1. a.

      Registry Key Creation

       
    2. b.

      Registry Key Deletion

       
    3. c.

      Setting a value in the registry key

       
     
  3. 3.
    Process Operations
    1. a.

      Process Creation

       
    2. b.

      Process Termination

       
    3. c.

      Thread Creation

       
    4. d.

      Thread Termination

       
     
  4. 4.
    Network Communication
    1. a.

      Sending data

       
    2. b.

      Receiving data

       
     

All these operations can be intercepted and manipulated by API hooking. Let’s see some of the implications. We give you the list of APIs as well that are commonly hooked by malware for each of the malware use cases.

Self-Protection

self-protection is important to malware. Malware wants to protect its files, processes, and registry entries. For example, the DeleteFile() malware hook and any file deletion APIs to prevent the deletion of its files. Malware is known to hook the TerminateProcess() API and other variants of this API in Windows Task Manager, that terminates/kills a process so that a user is not able to kill any of its processes via the Task Manager.

Rootkits/Stealth

Rootkits are techniques used by malware to hide their presence and presence of any of their artifacts like files, registry keys, processes, DLLs, network connections created by the malware. Most of the rootkit mechanisms use some form of API hooking to achieve stealth. The next chapter talks about rootkits in detail.

Data Stealing

Win32 APIs implement a lot of functionality on Windows by all kinds of software. All kinds of activities—like pressing a key, copying to clipboard, or browsing the Internet—involve a Win32 API in some way. Malware is known to intercept these APIs to steal data, for example, to monitor our keystrokes, steal our banking credentials. Table 10-1 lists some of the APIs which are usually used (not all of them are hooked since you can log keystrokes without the needing to hook APIs) by keylogger malware, which tries to steal keystrokes of a user.
Table 10-1

Some of the Win32 APIs used by KeyLogger Malware

DLL name

API Name

user32.dll

TranslateMessage

user32.dll

DispatchMessage

user32.dll

getAsyncKeyState

user32.dll

GetKeyBoardState

user32.dll

PeekMessage

user32.dll

GetMessage

Intercept Network Communication

We obviously can’t leave out network communication. Network APIs can be hooked to intercept the data sent over to the network by legitimate applications. Most of the network communication APIs on Windows resides in the DLL ws2_32.dll, wininet.dll, and wsock32.dll.

DNS traffic can be modified by hooking the APIs listed in Table 10-2. Malware can hook these APIs to modify the IP address returned by these names to redirect the user and legitimate applications to their malicious sites. Similarly, malware can hook these applications to block security software from being able to talk to their website by intercepting their DNS traffic.
Table 10-2

Some Network-Related Win32 APIs Hooked by Malware to Intercept DNS Traffic

DLL name

API Name

ws2_32.dll

gethostbyname

ws2_32.dll

getaddrinfo

It does not end at intercepting DNS traffic. Malware is known to hook various other network-related Win32 APIs that are used by legitimate applications to exchange their data with another computer. Table 10-3 lists some of these APIs.
Table 10-3

Other Network Related Win32 APIs Hooked to Intercept Network Communication

DLL name

API Name

ws2_32.dll

send

ws2_32.dll

connect

ws2_32.dll

WSASend

wsock32.dll

send

wsock32.dll

connect

Wininet.dll

InternetConnectA

Wininet.dll

InternetConnectW

Man in Browser Attacks: The Banking Malware

Very similar to network communication, banking transactions are done through web browsers using an HTTP protocol. To carry out an HTTP transaction, the web browser which is the client that we use, uses a sequence of API calls like InternetOpen(), InternetConnect(), HttpOpenRequest(), HttpSendRequest() and InternetReadFile().

HTTPSendRequest() is the API used to carry the data from the user and the browser to the banking server, including our valuable credentials (i.e., the username and password). So if malware wants to tap the credentials sent to the server from the browser, it hooks HTTPSendRequest() API. When a victim tries to log in to the banking site using his credentials, the API now hooked by the malware be intercepted by the malware, which gets the banking credentials from the intercepted data. The malware keeps a copy of the credentials before passing on the data to the server, oblivious to the user. The stolen credentials from the malware are then shared by the malware with its attacker for other nefarious purposes. This technique is called form grabbing.

There is a similar kind of attack tactic called Web Inject. InternetReadFile() that the API used by the web browser to receive the data sends from the server to the user. Very similar to the form grabbing technique, malware can hook this API to intercept the data sent back from the server before it can reach you in the browser. The goal of intercepting this data is to modify the data/web_page_contents before handing it off the browser where you view it. Can you think of why it modifies the received response data/web_page from the server?

Well, one well-known example is when the victim tries to open a banking website, the first thing the browser does is, it sends an HTTP/HTTPS request to the banking website, and the server responds with a login web page which has fields for the user’s banking credentials. Malware is known to intercept this login page sent back from the server to the user/browser through the InternetReadFile()hook it has placed and modify the login page before passing it on to the browser. The modifications can include extra fields, like ATM PIN. Now inside the browser, the victim sees the fields for the user credentials and, in addition to that, sees the extra field for ATM PIN added by the malware via the hook interception. Now when the user fills in the data including the ATM PIN, the malware again intercepts the data, including the much sought after ATM PIN by intercepting the communication via the HTTPSendRequest() API like it did earlier.

Table 10-4 lists some of the APIs that you should primarily keep an eye on, which are notably hooked by banking trojans to intercept banking communication.
Table 10-4

Network Win32 APIs Hooked to Intercept Web Communication in Internet Explorer

DLL Name

API Name

wininet.dll

InternetConnectA

wininet.dll

InternetConnectW

wininet.dll

HttpOpenRequestA

wininet.dll

HttpOpenRequestW

wininet.dll

HttpSendRequestA

wininet.dll

HttpSendRequestW

wininet.dll

HttpSendRequestExA

wininet.dll

HttpSendRequestExW

wininet.dll

InternetReadFile

wininet.dll

InternetReadFileExA

The APIs in Table 10-4 are hooked mainly by malware in the Internet Explorer browser, but Firefox and Chrome browsers use other APIs that are targeted by malware. Some of them are listed in Table 10-5.
Table 10-5

Networking APIs Hooked to Intercept Web Communication in Chrome and Firefox

DLL name

API Name

nspr4.dll

PR_OpenTCPSocket

nspr4.dll

PR_Connect

nspr4.dll

PR_Close

nspr4.dll

PR_Write

nspr4.dll

PR_Read

chrome.dll

ssl_read

chrome.dll

ssl_write

Now you might be wondering that using a secure protocol like HTTPS can protect your data even though the malware can intercept it via hooks. This is not true. HTTPS is useful to protect the traffic after encryption of the data, thereby preventing any snooping of the traffic even if they manage to intercept it. But malware can always intercept the traffic via hooks even before they are even encrypted by your browser, rendering HTTPS useless to main-in-the-browser attacks.

Application of Hooks in Security Software

Security software needs to monitor system activities for any malware infections. Very similar to malware, many of the antiviruses and anti-malware products hook on APIs to monitor file, registry, and network activity. Security software also needs to protect themselves from getting deleted, or their processes getting killed, or their processes being injected by malware code. All these require these anti-malware products to hook APIs in both user and kernel space by using the same hooking procedures we explained earlier.

Apart from products like antiviruses, another well-known tool that uses hooks extensively is an API logger like APIMiner. API loggers hook both user space Win32 APIs, and also system calls in kernel space to identify the various APIs used by a process. API loggers are largely used by malware sandboxes to identify the behavior of malware by logging the Win32 APIs the malware uses. Some of the well known free and open source API loggers are APIMiner and Cuckoo Sandbox.

Hook Scanning Tools

Most of the tools called rootkit scanners are actually hook scanners. GMER is one of the most popular ones. Another popular one is the Ring3 API Hook Scanner from www.novirusthanks.com. The installation of both tools was covered in Chapter 2. Running these hook scanner tools can help us identify if any of the APIs in the system are hooked and thereby identify any malware infection that relies on API hooking.

As we described in the previous section, an important point to remember is that many security software, as well as malware analysis tools, may create hooks in the system. Running your hook scanning tools might pop up these hooks from this security software on your system, which are real hooks, but they can be ignored. It’s good practice to take note of these hook entries from these clean software in case you are performing forensic analysis so that you can learn to ignore them when you look at these entries later on when you are analyzing a malware infection.

These hook scanning tools may bring up some false positives as well. Figure 10-38 displays the scan results for the GMER tool on a clean VM that is running Internet Explorer. As an exercise, please start the Internet Explorer browser and run the GMER tool.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig38_HTML.jpg
Figure 10-38

GMER hook scanning tools when running with Internet Explorer running

The screenshot from GMER shows that Internet Explorer is hooked even though it may not be, or it might be hooked—not by malware, but by one of its own components as a security measure. You need to learn to identify these otherwise benign entries in GMER and ignore them when you analyze a real malware which hooks Internet Explorer and other processes on the system. Let's now dissect the structure of GMER logs, as seen in Figure 10-39.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig39_HTML.jpg
Figure 10-39

Structure of GMER hook scanning tools logs

Here are some of the fields you can look for in the logs
  • Process image path This the path of the image of the hooked process

  • PID PID of the hooked process

  • DLL Name of the DLL in the process whose API is hooked

  • API This is the name of the hooked API in the DLL

  • API address This is the address of the hooked API

  • Jump target This the address of the memory location where the hook redirects the API to

  • Jump module This is the module where the jump target hook is located. This displays the location of the DLL module on disk. If this is not displayed, then it is an unknown module and may lie in injected code in memory, which you can use as a method to identify malicious code injected hooks.

The GMER logs on your system might be different from the one you see in the screenshot.

The right way to use hook scanning tools like GMER and Ring3 API Hook Scanner is to first run these tools before you execute malware to analyze it, make a note of the GMER logs and save the logs. Now you run the malware and re-run GMER and save the logs. Now compare the difference in GMER logs before and after running the malware to identify any hooks by the malware.

You can now retry the steps to see how the Ring3 API Hook Scanner logs look in comparison to GMER.

Case Study: DeleteFile() Hooked

Now let’s run Sample-10-7. Rename this file by adding the .exe file suffix extension. Also, make sure the same folder containing Sample-10-7.exe also has the file Sample-10-7-module.dll. In the same folder, create new text files: hello.txt and malware.txt. The folder contents should look like Figure 10-40.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig40_HTML.jpg
Figure 10-40

Contents of the folder for running Sample-10-7.exe hook case study

Double-click Sample-10-7.exe to run it. Sample-10-7 is a hooking sample that injects code into the Explorer.exe process of your system. You might remember that Explorer.exe is the Windows file browser that you use to browse the files on your system. To view a folder’s contents, you use the Windows file browser.

Sample-10-7.exe injects code into Explorer.exe using one of the code injection techniques we covered earlier in the chapter and then inline hooks the DeleteFileW() API in Kernel32.dll module in Explorer.exe. With the hook in place, it redirects all API calls to Kernel32.DeleteFileW() to its own version of FakeDeleteFile() that checks if the user is trying to delete a file that has the word malware in it. If it does, it blocks the user from deleting the file. If the user tries to delete any file that doesn’t have the word malware in it, it allows the user to delete the file.

To test it, try deleting the malware.txt file that you created earlier (see Figure 10-40). To delete the file, don’t use the Delete button on your keyboard. Also, do not right-click the file and click Delete. These techniques do not permanently delete the file; they only move it to the Recycle Bin. Instead, you want to permanently delete the file, and you can do so by selecting the file and simultaneously pressing Shift+Delete on your keyboard. Doing this for malware.txt results in the system opening a message box informing you that it is about to permanently delete the file, as seen in Figure 10-41.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig41_HTML.jpg
Figure 10-41

Shift+Delete on malware.txt shows a message box to permanently delete the file

But although you clicked Yes to permanently delete the file, the hook that Sample-10-7.exe has put in place intercepts the API call to DeleteFileW() and blocks deletion of the file as seen in Figure 10-42.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig42_HTML.jpg
Figure 10-42

The hook put in place by Sample-10-7.exe blocks deletion of malware.txt

Now you can try deleting hello.txt from the same folder using Shift+Delete as before, and the hook doesn’t block it from being permanently deleted, as seen in Figure 10-43, where hello.txt is no longer shown since Explorer.exe has deleted it.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig43_HTML.jpg
Figure 10-43

The hook put in place by Sample-10-7.exe doesn’t block deletion of hello.txt

Now run the Ring3 API Hook Scanner tool, which scans the system and shows that Explorer.exe has been hooked by our Sample-10-7.exe as seen in Figure 10-44.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig44_HTML.jpg
Figure 10-44

Ring3 API Hook Scanner detects the hook in Explorer.exe put by Sample-10-7.exe

Case Study: Internet Explorer Hooked

Let’s now explore a malware sample that hooks some network related APIs in the Internet Explorer browser. You can open the text file Sample-10-8.txt from the samples repo. This is just a text file that contains the hash and instructions on how to download the actual malware sample from various sources on the web. Once you download the malware sample, rename it as Sample-10-8.exe. Please note all downloads of malware and handling of these samples should be done inside your analysis VM only.

Before you can run the malware executable Sample-10-8.exe, please launch the Internet Explorer browser inside your analysis VM. Now run Sample-10-8.exe. Now run the GMER tool and start the scan. Figure 10-45 displays the scan results of GMER on our system. Do note that the results might vary when compared to the scan results on your system.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig45_HTML.jpg
Figure 10-45

GMER tool scan showing the hooks after running Sample-10-8.exe

Figure 10-46 is an enlarged view of the logs. Not all the hook entries shown by GMER are from the malware. Most of them are false positives that you should learn to ignore. But you can note the actual hook as highlighted in the bottom two rows.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig46_HTML.jpg
Figure 10-46

GMER tool scan showing the identified malware hooks after running Sample-10-8.exe

We give you hints on which of the GMER entries are actual hooks placed by the malware, and the rest are just false positives. But as you gain more experience, you learn to skim through these entries and easily identify the malicious hooks from GMER and other such tools’ logs.

To scan GMER looks and try to identify hooks that are not from the malware Sample-10-8.exe, look for jump targets that don’t lie in an unknown module. Also another way to find the actual hooks is by the process of elimination (i.e., you run GMER with Internet Explorer open before you run the malware sample, obtain the logs and save them). Now execute the malware sample with Internet Explorer open and re-run GMER and save the logs and compare it with the logs you saved earlier. The new entries point to hooks placed by the malware sample you ran.

We found that the hooks are in the HTTPSendRequestA and HTTPSendRequestW APIs, and it possibly indicates that we are dealing with malware, which is some sort of banking trojan that possibly intercepts user credentials via these hooks. More accurate details about the malware can only be found out by reverse-engineering the sample.

Now that we have identified the hook, let’s look at the memory location where the malware hook jumps into after intercepting an API call. The addresses as seen in Figure 10-46 are 0x01E816C0 and 0x01E817A0. Please do note the addresses might be different in your GMER logs. If we open the memory tab in process hacker for Internet Explorer, these addresses lie in a memory block that starts from 0x1e80000, as seen in Figure 10-47.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig47_HTML.jpg
Figure 10-47

Identifying injected code in Internet Explorer using Process Hacker

Note that the memory block has RWX (read, write, and execute) permissions. You learned that malware that injects code allocates memory with RWX permissions, thereby indicating that this memory block must be the injected code by Sample-10-8.exe.

APIMiner

APIMiner is a tool developed by us that you can use to log APIs used by malware samples. As opposed to sandboxes like Cuckoo, you can instead use APIMiner in your existing analysis VM to inspect malware samples. APIMiner is a command-line, and we have covered its installation in your analysis VM in Chapter 2. APIMiner is used via the command prompt by using the command line shown in Figure 10-48, where you supply the path to the sample that you want to analyze, as an argument to the --app option. APIMiner hooks the Win32 APIs in the sample process and logs the APIs used by the sample process into log files in the same directory, which starts with the apiminer_traces filename prefix.
../images/491809_1_En_10_Chapter/491809_1_En_10_Fig48_HTML.jpg
Figure 10-48

APIMiner to log APIs used by Sample-10-2.exe

As an exercise, let’s reanalyze Sample-10-2.exe from earlier in the chapter using APIMiner, as seen in Figure 10-48. Run the command and go through the whole exercise. Make sure you have an instance of notepad.exe process running while running the command, since Sample-10-2.exe needs it. After running the whole exercise, you can see an API log file starting with apiminer_traces in the same directory where the sample is located.

Open this log file, and as you can see, APIMiner has logged the various APIs used by this sample. As you learned in the Sample-10-2.exe exercise, this sample calls the VirtualAllocEx Win32 API to allocate memory in the notepad.exe process that you have started. In the API logs file, you can see the call to the NtAllocateVirtualMemory API, which is the NT API version invoked by the VirtualAllocEx (APIMiner logs NT APIs) API called by the sample.

../images/491809_1_En_10_Chapter/491809_1_En_10_Figa_HTML.jpg

Using APIMiner, you can easily analyze malware samples and log the APIs used by it, helping you easily identify any form of code injection. As an exercise, run all the exercises in this chapter using APIMiner, and examine the API logs and identify all the APIs that are used by the sample for code injection.

Summary

Code injection is one of the most common techniques used by malware. It helps analysts identify and classify the malware in question. In this chapter, you learned about code injection using various hands-on samples. We covered the different types of code injection techniques that are prevalent in malware these days. We also covered process hollowing, a notorious code injection technique used primarily for stealth. You also learned about API hooking, a primary motive for malware to inject code. Using hands-on exercises and samples, we investigated how API hooking works and the implications of using it. You also learned about anti-malware hook scanning tools like GMER And Ring3 API Hook Scanner for detecting any hooks that malware placed on a system.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.141.41.187