FortiGuard Labs Threat Research
FortiGuard Labs Threat Analysis Report Series
IcedID is a banking trojan which performs web injection on browsers and acts as proxy to inspect and manipulate traffic. It steals information, such as credentials, from victims. It then sends that stolen information to a remote server.
Recently, the FortiGuard Labs team started to investigate some IcedID samples. In this series of blogs, I will provide a detailed analysis of a new IcedID malware sample. The entire detailed analysis is divided into three parts.
This blog is Part I below. Let’s dive in.
The sample being analyzed is a PE executable, and is most commonly distributed by a compromised Office file. The following image is the process tree after executing the PE file. We can see that this sample of IcedID eventually creates a svchost.exe parent process and three svchost.exe child processes. In addition, it can deliver a Trickbot payload, highlighted in red. In this series of blogs, the analysis of the Trickbot payload won’t be covered. We will only focus on how IcedID works internally.
As shown in Figure 1, the PE executable first launches itself with a command line parameter “-q=xxxxxxxxxx”. This new process then continues by launching a svchost.exe process. Once the first svchost.exe process is launched, the previous two processes exit. Finally, this svchost.exe parent process then launches three svchost.exe processes.
We can now start to dynamically analyze the PE execution. After tracing a few steps from the entry point, the program goes into the function sub_00415CAE() as follows.
In the trampoline code, it is used for decrypting the code segment. Eventually, it can jump to the real entry point of the program. At that point, the unpacking of the PE executable is complete.
The following is the pseudo code of the real entry point of the program.
Here is a list of the key functions:
We ran this sample without any parameters so it could go into the third step (sub_4012E9).
After performing the rdtsc instruction, the return value is converted into a string as a parameter of the new process execution. Next, the program sets an environment variable in the process context. The name of the variable is the command line parameter without the prefix “-q=”.
Finally, it invokes the CreateProcessA function to create itself with a parameter.
Next, we will continue the analysis with the new running process.
After launching the new process, the program goes to the real entry point of the program, as shown in Figure 4. At this point, the check_parameter() function returns TRUE because the command line parameter starts with “-q=”. It then goes to the sub_40124A() function.
In the function hook_NtCreateUserProcess(), it first invokes the function NtProtectVirtualMemory to change the protection of the first five bytes of the function NtCreateUserProcess to PAGE_EXECUTE_READWRITE. It then modifies those five bytes with a JMP instruction. Finally, it again invokes the function NtProtectVirtualMemory to restore protection to the first five bytes.
The following is the assembly code of the function NtCreateUserProcess hooked.
Inside the function CreateProcessA, the code invokes the low-level API NtCreateUserProcess. After the function CreateProcessA is invoked in Figure 7, the program goes to the trampoline code sub_4010B7(). The following is the pseudo code of the trampoline code.
The following list is what the trampoline code actually does.
Let’s take a closer look at step four. The following is the pseudo code of the function sub_401745() in that step.
It first uses NtAllocateVirtualMemory to allocate the memory region in the remote process space(svchost.exe). Next, it uses ZwWriteVirutalMemory to perform the code injection into the memory region in the svchost.exe process.
It then sets up a hook for the RtlExitUserProcess API in the process space of svchost.exe. It should be noted that there is a little difference between hooking RtlExitUserProcess and hooking NtCreateUserProcess in Figure 8. The former is to hook the API of remote process space, while the latter is to hook the API in its current process space.
The assembly code of the hooked RtlExitUserProcess is shown in Figure 14.
As shown in Figure 7, the process svchost.exe was created without a parameter. It could immediately exit if running svchost.exe without parameter, and after it exits, it could invoke the low-level API RtlExitUserProcess. Because IcedID hooks the RtlExitUserProcess, it could jump to the trampoline code to execute the IcedID payload.
The injected memory regions in the remote process svchost.ext are shown in Figure 15. We can see that two memory regions have been injected. The code segment is stored in the memory region(0xa1000 ~ 0xa7000).
As shown in Figure 14, it jumps to 0xA2B2D, which is in memory region(0xA0000 ~ 0xAC000). The offset of the trampoline code from this memory region is 0x2B2D.
We have walked through how to unpack the IcedID malware, hooking, and process injection techniques used by IcedID, as well as how to execute the IcedID payload. In the next blog, I will provide a deep analysis of the IcedID payload (0xA2B2D).
This malicious PE file has been detected as “W32/Kryptik.GTSU!tr” by the FortiGuard AntiVirus service.
PE executable (b8113a604e6c190bbd8b687fd2ba7386d4d98234f5138a71bcf15f0a3c812e91)
Read about the FortiGuard Security Rating Service, which provides security audits and best practices.