Code injection via return-oriented programming

2012-10-10

Wayne Low

F-Secure, Finland
Editor: Helen Martin

Abstract

Code injection first became popular in game cheats, where it was used to change the program’s course of execution. Wayne Low looks at a piece of malware that takes advantage of the Windows messages flaw to perform code injection.


Code injection first became popular in game cheats, where it was used to change the program’s course of execution. The technique has since been adapted for use in the malware world, where it is used in various ways to disguise the presence of malicious code on a machine, for example by injecting and running the code in a legitimate process.

This analysis focuses on a piece of malware found on a customer’s machine which had reportedly been infected with ransomware. Behavioural analysis showed that this malware did not behave like typical ransomware and it appeared to be an ordinary backdoor. Out of curiosity, we decided to investigate it to determine whether there were any hidden characteristics that could possibly indicate that the malware really was ransomware, as the customer claimed. Further investigation disclosed a couple of interesting details. So the story begins.

The results of the investigation are as follows:

  1. We believe it to be the first malware found to be related to the well-known ‘Windows messaging shatter attack’, which was first discovered by Brett Moore in 2004 [1] (proof-of-concepts were available in his whitepaper [2] demonstrating how the attack worked).

  2. This malware uses an exploitation technique to bypass Data Execution Prevention (DEP) in conjunction with the Windows shatter attack technique in order to perform code injection.

We believe the author intended to name the malware ‘sdropper32’ (Shellcode Dropper) as this term can be found in a DLL name from the image export table, IMAGE_EXPORT_DIRECTORY->Name. From now on, we will refer to the malware as Sdropper.

Overly verbose with a bunch of debug strings

It is always helpful for the analyst when a malware sample comes with debug information, as it gives us hints about the malware and makes analysing it easier, even if the information is not the full symbol table of the API functions used in the code. On first looking at the debug strings from the binary, we can deduce the following information:

  • The programming language used by the sample

  • The logging information that will be sent to the malware’s command-and-control (C&C) server

  • The functionality of some important modules used in the sample

  • The error handling messages.

    Excerpt of output debug strings found in the sample.

    Figure 1. Excerpt of output debug strings found in the sample.

Based on the debug information, it is very easy to identify the main payload of this sample, but what caught our attention was the exploit string – which made us wonder what else was going on. We decided to investigate further to see if some sort of exploit was really implemented.

A memory injection approach without using the classic memory injection technique

Our initial analysis showed that the malware didn’t use the usual memory injection method, so we first had to understand how it implements code injection.

The classic memory injection technique used by many traditional malware families will first allocate a block of memory using the VirtualAllocEx API function to hold the code instructions, which will then be written to the address space of the remote process using the WriteProcessMemory API function. Since this is a popular method [3] for writing/injecting code into a remote process, it is easily identified by anti-virus software through a Host Intrusion Prevention System (HIPS). For this reason, Sdropper utilized an alternative and intelligent method, without using any memory manipulation APIs.

First, the malware attempts to find a global file mapping object in the system, which can be found using one of the following section objects:

  1. \BaseNamedObjects\ShimSharedMemory

  2. \BaseNamedObjects\windows_shell_global_counters

  3. \BaseNamedObjects\MSCTF.Shared.SFM.MIH

  4. \BaseNamedObjects\MSCTF.Shared.SFM.AMF

  5. \BaseNamedObjects\UrlZonesSM_Administrator

    Global section objects found in Windows Explorer on the test machine.

    Figure 2. Global section objects found in Windows Explorer on the test machine.

If the section object can be opened successfully for SECTION_MAP_READ and SECTION_MAP_WRITE, it will create a mapped view with protection level PAGE_READWRITE using ZwMapViewOfSection in the malware’s process address space. In my test environment, I was unable to see section objects from 2 to 4, so ZwOpenSection will return STATUS_OBJECT_NAME_NOT_FOUND if it tries to open one of these section objects.

List of sections that have global names on the infected machine.

Figure 3. List of sections that have global names on the infected machine.

The mapped view returned by ZwMapViewOfSection can be shared with other processes. In other words, the sample can write code and store contents in this mapped view and share it with the explorer.exe address space as well [4].

Shared memory between malware address space and explorer.exe address space.

Figure 4. Shared memory between malware address space and explorer.exe address space.

(For a larger version of the image shown in Figure 4 click here.)

As shown in Figure 4, the committed memory is marked as read-write only. How did the malware manage to execute code in this memory region? And how did the malware trigger the code written in this page? We find a clue in its export directory table:

  1. 004065A3 DownloadRunExeId

  2. 00406536 DownloadRunExeUrl

  3. 004065FC DownloadRunModId

  4. 00406676 DownloadUpdateMain

  5. 00404D4E InjectApcRoutine

  6. 00404D33 InjectNormalRoutine

  7. 00405ADB InjectedShellCodeEnd

  8. 00405A8A InjectedShellCodeStart

  9. 00406721 SendLogs

  10. 0040670C WriteConfigString

The highlighted text shows that it has a shellcode routine and its name, InjectedShellCodeStart, indicates that this shellcode will be injected somehow into the shared memory. In the next section, we will investigate how important this shellcode is in this memory injection method.

Determines architecture before building loader code

On initial execution, the malware will generate the platform-specific loader code, together with the custom shellcode mentioned in the previous section. To do so, Sdropper checks the architecture of the infected machine using IsWow64Process.

Checks platform architecture using IsWow64Process.

Figure 5. Checks platform architecture using IsWow64Process.

Sdropper customizes the loader shellcode.

Figure 6. Sdropper customizes the loader shellcode.

(For a larger version of the image shown in Figure 6 click here.)

While building the loader, Sdropper will simultaneously copy the code to the memory regions shared with explorer.exe.

Preparation of loader code

The author wrote his own GetProcAddress function (which I refer to as _MyGetProcAddress), which has the following function prototype:

_MyGetProcAddress(HMODULE hModule, CHAR *szFuncName, BOOLEAN IsRVA)

This function is able to provide the relative virtual address, if IsRVA is set to true; otherwise, it will return the virtual address of the specified function name that is similar to GetProcAddress.

To start building the loader code, Sdropper attempts to locate the address of the shellcode from the dropper’s export table. It also needs to get the size of the shellcode by calculating the delta value between InjectedShellCodeStart and InjectedShellCodeEnd. It then resolves the following API functions, which will be called or used later in the shellcode:

  • CloseHandle

  • MapViewOfFile

  • OpenFileMappingA

  • CreateThread

  • SetWindowLong

The resolved API function address and shellcode are copied to the mapped view that was obtained previously. You may notice that it also gets the address of SetWindowLong, so why on earth does it use the Windows GUI API function? We will examine this further later in the article.

Figure 7 shows how the loader code looks at this point.

Memory view of incomplete loader code with user-mode APIs and shellcode.

Figure 7. Memory view of incomplete loader code with user-mode APIs and shellcode.

Preparation of loader code with return-oriented payload

In order to locate the targeted shared memory address in the explorer.exe address space, Sdropper will explore all the memory regions available in the process using VirtualQueryEx. For each memory region in explorer.exe, it reads the whole memory region as a buffer using ReadProcessMemory, with the memory size obtained from MEMORY_BASIC_INFORMATION.RegionSize. It then finds the shellcode buffer using RtlCompareMemory. Once Sdropper gets the shared memory address in explorer.exe containing the shellcode, it will start building the main component in the loader code.

The same loader code can be found in explorer.exe shared memory and in the malware’s mapped view.

Figure 8. The same loader code can be found in explorer.exe shared memory and in the malware’s mapped view.

(For a larger version of the image shown in Figure 8 click here.)

One of the questions we asked earlier was: how does Sdropper execute the shellcode with only PAGE_READWRITE level protection? The answer is Return-Oriented Programming (ROP), also known as return-to-libc, which enables the loader to execute the shellcode flawlessly. The malware will create the following ROP gadgets (on x86 architecture):

  1. Gadget 1

    • std;

    • retn;

  2. Gadget 2

    • cld;

    • retn;

  3. Gadget 3

    • pop eax;

    • retn;

  4. Gadget 4

    • jmp eax;

  5. Gadget 5

    • mov ecx, 94h;

    • rep movs [edi], [esi];

    • pop edi;

    • xor eax, eax;

    • pop esi;

    • pop ebp;

    • retn 8;

The malware author has also considered the limitations imposed by Address Space Layout Randomization (ASLR) on a potentially infected machine. When ASLR is enabled, a module will have a dynamic image base address when loaded by the operating system. This is a security mechanism designed to make exploit code development more challenging. In order to mitigate ASLR protection, Sdropper uses the following algorithm to look for the ROP gadgets among the common dynamic link libraries (DLL) loaded into explorer.exe:

  1. Uses EnumProcessModules to get a list of module handles loaded in explorer.exe.

  2. Reads 1,024 bytes from the starting address of the module that usually contains the PE structure information.

  3. Makes sure the module is a valid executable by checking the MZ header and PE signature from the structure.

  4. Goes through the section table from the structure and looks for the ‘.text’ section, which normally stores the executable code.

  5. As checking the ‘.text’ string name alone is not enough, it also ensures that the section has the IMAGE_SCN_MEM_EXECUTE attribute, which indicates that the section can be executed as code.

  6. If all the conditions match, it searches for the ROP gadget from the code section and retrieves its virtual address location.

  7. The ROP gadget virtual address is then saved to the loader code.

Figure 9 shows the layout of the incomplete loader code with partial ROP gadgets set up. In the final stage, Sdropper will look for ROP gadget 4 and also hijack a function that will be used to store the shellcode contents. It chooses Ntdll!atan, probably because the function is unlikely to be used by explorer.exe as it will crash the Windows desktop, which may in turn alert the user to the malware’s existence.

Memory view of incomplete loader code with ROP gadgets.

Figure 9. Memory view of incomplete loader code with ROP gadgets.

Besides the ROP gadgets, Sdropper also saves the necessary parameters for WriteProcessMemory into the shared memory. Since the ROP gadget is a chain of instructions, WriteProcessMemory will be executed in the chain at some point, and will eventually write the shellcode contents to the targeted function address, followed by a return instruction that will transfer execution to the shellcode. We will discuss how the shellcode is executed in the next section.

Get Ntdll!atan (as a placeholder that will be overwritten with shellcode contents) and get ROP gadget 4.

Figure 10. Get Ntdll!atan (as a placeholder that will be overwritten with shellcode contents) and get ROP gadget 4.

Memory view of loader code with complete ROP gadgets.

Figure 11. Memory view of loader code with complete ROP gadgets.

Loader code wrap up

After the ROP gadgets set-up is completed, Sdropper tries to locate the main payload address, that is, the typical malware routines such as dropping and creating files, adding and modifying registry keys, and downloading and executing additional malware components. This main payload can be found in InjectNormalRoutine, and similarly to InjectedShellcodeStart, it can be retrieved from one of the exported functions stored in the binary.

Sdropper creates an exclusive file mapping object (to store the contents of the original executable) using the object name obtained from the registry key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography and the first 10 characters from the data stored in MachineGuid. Keep in mind that the malware will open and retrieve the same exclusive file mapping object in order to get the address of InjectNormalRoutine. This will be covered in the last section of this article.

The malware also gets and stores the original handle value of a specified Windows class object and the return value of DWL_MSGRESULT by calling the FindWindow and GetLongWindow APIs, respectively. The similar Windows GUI API functions, SetWindowLong and SendNotifyMessage, will be used in order to start the loader.

This technique is very similar to the known Windows shatter attack, which replaces the look-up table with a custom look-up table containing shellcode, as we mentioned at the beginning of this article. The malware also does a similar thing by replacing the look-up table returned by GetLongWindow with its own table containing a pointer to the loader code generated earlier.

This vulnerability is believed to be a design flaw in Windows messaging; however, a detailed description of the flaw is outside the scope of this article. Nevertheless, this is an interesting approach compared with the conventional code injection method. In the next section, we will cover how Sdropper manages to execute the shellcode located in the shared memory.

Routine that triggers the loader code using a similar approach to the Windows shatter attack.

Figure 12. Routine that triggers the loader code using a similar approach to the Windows shatter attack.

(For a larger version of the image shown in Figure 12 click here.)

Shellcode execution roadmap

The final loader is ready to be executed via SetWindowLong.

Memory view of complete loader code.

Figure 13. Memory view of complete loader code.

When the Windows messaging API has successfully been exploited, explorer.exe will first execute the following ROP gadget instructions from the loader in sequence:

Gadget 1:

ntdll!RtlQueryAtomInAtomTable+0x110:
7c92c104 fd              std
7c92c105 c3              ret

Gadget 5:

SHELL32!CFileSysBindData::GetFindData+0x10:
7c9ee84e b994000000      mov     ecx,94h
7c9ee853 f3a5            rep movs dword ptr es:[edi],dword ptr [esi]
7c9ee855 5f              pop     edi
7c9ee856 33c0            xor     eax,eax
7c9ee858 5e              pop     esi
7c9ee859 5d              pop     ebp
7c9ee85a c20800          ret     8

Gadget 2:

Explorer!CTray::_MigrateOldBrowserSettings+0xd5:
0101c2b0 fc              cld
0101c2b1 c3              ret

The first gadget will set the Direction Flag (DF) of the flags register so that the data will be copied into the stack in a backwards direction. After the copy operation is completed, it will reset the DF flag. This activity can be illustrated with the following diagram:

Overwrite the stack with ROP gadgets.

Figure 14. Overwrite the stack with ROP gadgets.

Now the stack contains the return-oriented payload. The next thing it needs to do is to perform a stack pivot through a sequence of ‘xchg eax, esp; retn;’ instructions. The stack pivot can be found in the Ntdll!_chkstk:

ntdll!_chkstk:
001b:7c901a09 3d00100000      cmp     eax,1000h
001b:7c901a0e 730e            jae     ntdll!_alloca_probe+0x15 (7c901a1e)
001b:7c901a10 f7d8            neg     eax
001b:7c901a12 03c4            add     eax,esp
001b:7c901a14 83c004          add     eax,4
001b:7c901a17 8500            test    dword ptr [eax],eax
001b:7c901a19 94              xchg    eax,esp
001b:7c901a1a 8b00            mov     eax,dword ptr [eax]
001b:7c901a1c 50              push    eax
001b:7c901a1d c3              ret

This routine will adjust the stack pointer to point to the stack frame that consists of arguments required by WriteProcessMemory. This function will be executed immediately upon returning from Ntdll!_chkstk. As described earlier, the main goal for the WriteProcessMemory API call is to hijack the content in Ntdll!atan with Sdropper’s shellcode. The malware has successfully bypassed DEP when the shellcode is injected into Ntdll!atan. It will then execute the last couple of gadgets in order to pass control to the hijacked function:

Gadget 3:

Explorer!SpecialFolderList::ReadIconSize+0x2:
01013874 58              pop     eax
01013875 c3              ret

Gadget 4:

Explorer!DefSubclassProc+0x27:
01002240 ffe0            jmp     eax {ntdll!atan (7c901d75)}

The diagram in Figure 15 clarifies the whole roadmap of shellcode execution.

Shellcode execution roadmap.

Figure 15. Shellcode execution roadmap.

(For a larger version of the image shown in Figure 15 click here.)

The final destination

Finally, we reach the shellcode. Although it does not do anything fancy like the return-oriented payload, it is an important entry point for Sdropper to achieve its goal. It first tries to open the existing malware-specific file mapping object, which as mentioned earlier, is needed to obtain the malware’s main payload. After the main payload routine has been determined, the malware passes it as a thread routine to the CreateThread API, so that the main payload is run in the process context of explorer.exe.

The shellcode will execute the malware’s main payload.

Figure 16. The shellcode will execute the malware’s main payload.

(For a larger version of the image shown in Figure 16 click here.)

There are a couple of tasks that Sdropper performs once the main payload is executed in the process context of explorer.exe:

  1. It creates a mutex name, unique to every machine, based on the registry key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\MachineGuid. The MachineGuid data is used to form the malware’s infection marker:

    Infection_Marker: {MachineGuid}gfdgfdgdfg

    If no MachineGuid is found on the infected machine, it will form the following infection marker instead:

    Infection_Marker: {MachineGuid}fgfdggfd

    The mutex name is then combined with the infection marker, as well as the hexadecimal value of the process ID of explorer.exe:

    Mutex name: Global\{Infection_Marker}{HexVal_Explorer_Pid}
    Example: Global\ebb80e80-143c-4014-8ca5-6b5a7894ec2agfdgfdgdfg708
  2. The malware will also store the infection marker to the registry key, and will use the infection marker generated above to form a global infection marker:

    Global_Infection_Marker: {AlphaCharacterOnlyFromMachineGuid}gfdgfdgdfg
    Example: ebbeccabaecagfdgfdgdfg

    After the global infection marker has been determined, it will save it to the following registry key:

    Key: HKEY_CURRENT_USER\Software\{GlobalInfectionMarker}
    Value: CurrentPath
    Data: Data: %COMMONAPPDATA%\{GlobalInfectcionMarker}.exe
  3. It creates and drops a copy of itself to %COMMONAPPDATA%, using the global infection marker as the filename.

    %COMMONAPPDATA%\{GlobalInfectionMarker}.exe
    Example: C:\Documents and Settings\All Users\Application Data\ebbeccabaecagfdgfdgdfg.exe

    It then creates a start-up registry key pointing to the file %COMMONAPPDATA%\{GlobalInfectionMarker}.exe to ensure that Sdropper will survive after the system restarts:

    Key: HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run
    Value: {GlobalInfectionMarker}
    Data: Data: %COMMONAPPDATA%\{GlobalInfectcionMarker}.exe
    

    It also determines whether it is running in the context of explorer.exe. If it is, it attempts to create two persistent threads running in explorer.exe. One of the threads is a simple protection mechanism, responsible for monitoring and protecting the dropped executable in %COMMONAPPDATA%\{GlobalInfectionMarker}.exe and its start-up registry key from being removed from the infected machine.

    The other thread is responsible for establishing a connection between the malware and the C&C server. Sdropper (at this point, the client backdoor program) starts sending requests to the C&C server in order to retrieve additional commands from the attacker for execution. The botnet client will send a request to the C&C server at 10-minute intervals.

    The C&C configuration information can be found in the ‘.cfg’ section of the malware binary’s sections:

    C&C server configuration information

    Figure 17. C&C server configuration information

    The first DWORD value from this section represents the offset value to the embedded MZ, while the next DWORD value represents the size of the embedded binary file. This malware supports x64 architecture, and this embedded binary is compiled specifically for machines running on the x64 platform.

    The configuration file will be saved as %COMMONAPPDATA%\{GlobalInfectionMarker}.cfg. It is locked for exclusive access by the malware, via the Windows LockFileEx API function.

    The malware uses the same custom RC4 algorithm encryption scheme for the configuration file on disk and the data sent to the C&C server. The RC4 encryption/decryption key can be either:

    1. The hostname of the C&C server, if the data is going to be sent to the remote server.

    2. The infection marker, if the data is going to be stored on the disk.

    The diagram in Figure 18 shows a few lines of code to clarify the custom RC4 algorithm (reversed from the binary):

    A few lines of code to clarify the custom RC4 algorithm.

    Figure 18. A few lines of code to clarify the custom RC4 algorithm.

  4. It also performs an inline hook to the function NtResumeThread/ZwResumeThread found in explorer.exe. This results in code injection into a newly created process; however, it only targets the following processes:

    • explorer.exe

    • iexplorer.exe

    • firefox.exe

    • mozilla.exe

    Inside the hook function, it will determine whether there is an associated thread handle from the newly created process. If there isn’t, it will call either the CreateRemoteThread (x86) API or RtlCreateuserThread (x64) API, with the handle of the process to execute the thread routine InjectNormalRoutine (i.e. the malware’s main payload). Otherwise, it will call the NtQueueApcThread (both x86/x64) API with the handle of the thread to start another thread routine, InjectApcRoutine. Both these routines perform a similar operation.

    InjectNormalRoutine vs. InjectApcRoutine.

    Figure 19. InjectNormalRoutine vs. InjectApcRoutine.

Conclusion

This is probably the first malware that takes advantage of the Windows messages flaw to perform code injection. By injecting code using this vulnerability, the malware is able to evade HIPS-based detection. This is why the author has designed the malware to execute its typical malware routines only after the flaw has successfully been exploited. However, Sdropper does unintentionally leave traces during the initial execution that can easily be used to detect the malware’s presence before it causes further havoc on the machine. Regardless of whether or not the vulnerability exploitation fails (or if the vulnerability has been patched on the machine), the malware also has an alternative approach to perform code injection by using a traditional code injection method; fortunately, this approach is not complicated and will cause an anti-virus product to issue an alert, leaving the malware nowhere to hide.

Bibliography

[3] Dynamic Forking of Win32 EXE. http://www.security.org.sg/code/loadexe.html.

[4] Windows Internal 5th edition, Shared Memory and Mapped Files, p.709.

twitter.png
fb.png
linkedin.png
hackernews.png
reddit.png

 

Latest articles:

Nexus Android banking botnet – compromising C&C panels and dissecting mobile AppInjects

Aditya Sood & Rohit Bansal provide details of a security vulnerability in the Nexus Android botnet C&C panel that was exploited to compromise the C&C panel in order to gather threat intelligence, and present a model of mobile AppInjects.

Cryptojacking on the fly: TeamTNT using NVIDIA drivers to mine cryptocurrency

TeamTNT is known for attacking insecure and vulnerable Kubernetes deployments in order to infiltrate organizations’ dedicated environments and transform them into attack launchpads. In this article Aditya Sood presents a new module introduced by…

Collector-stealer: a Russian origin credential and information extractor

Collector-stealer, a piece of malware of Russian origin, is heavily used on the Internet to exfiltrate sensitive data from end-user systems and store it in its C&C panels. In this article, researchers Aditya K Sood and Rohit Chaturvedi present a 360…

Fighting Fire with Fire

In 1989, Joe Wells encountered his first virus: Jerusalem. He disassembled the virus, and from that moment onward, was intrigued by the properties of these small pieces of self-replicating code. Joe Wells was an expert on computer viruses, was partly…

Run your malicious VBA macros anywhere!

Kurt Natvig wanted to understand whether it’s possible to recompile VBA macros to another language, which could then easily be ‘run’ on any gateway, thus revealing a sample’s true nature in a safe manner. In this article he explains how he recompiled…


Bulletin Archive

We have placed cookies on your device in order to improve the functionality of this site, as outlined in our cookies policy. However, you may delete and block all cookies from this site and your use of the site will be unaffected. By continuing to browse this site, you are agreeing to Virus Bulletin's use of data as outlined in our privacy policy.