Analysis of “Heaven’s Gate” part 2

Sachiel
8 min readJan 4, 2021

Beyond the “Heaven’s gate”

Overview

This article is a continuation of part 1. In part 1, I succeeded in extracting the 64-bit code executed by Heaven’s Gate. Analyzing this code, I found that it was injecting the code into the memory of the “svchost.exe” process created by the original code and resuming the thread. The extracted 64-bit code will fail this process.
There are two reasons:

  • It isn’t known the handle of the process and thread to inject into “svchost.exe” created by the original 32-bit code.
  • It refers to the decrypted malware payload in the memory of the original 32-bit code.

Perhaps it’s enough to know that what Heaven’s Gate does is injection and resume into the process. But I really wanted it to run and attach to the injected “svchost.exe”. As a result of trial and error, I succeeded in doing so.
This article describes the procedure.

Target malware hash value:
MD5:545BFDC9B1976AE0003443FF4F90EB7E
SHA1:92E8CE006BB3C4A1DDB8D8BA8DE3A90C0BBB6326

Required points

In order for the extracted 64-bit code to be successfully injected into “svchost.exe”, I needed to know:

  • Handles of processes and threads of “svchost.exe” created and suspended by 32-bit code
  • Data in memory referenced on 32-bit code(probably malicious code)
  • Parameters passed when executing Heaven’s Gate

The 32-bit code is running on IDA just before Heaven’s Gate. Therefore, I can refer to the data in the memory of the 32-bit code.

As a result of analysis of 64-bit code, I found that parameters are passed by “rcx” from 32-bit code. The value of “rcx” was the address of the structure in memory of the 32-bit code. The structure contained the address for malicious code, size, and handles of the “svchost.exe” process and thread. I think this depends on the case. If you do the same analysis on different specimen, you need the skills to read this.

The following problems occur when executing with the extracted 64-bit code.

  • The handle value of the structure in the 32-bit code cannot be used because the process is different.
  • The 32-bit code memory cannot be referenced because the process is different.

I solved these in a very muddy way. The procedure is shown below.

Getting process handle

I thought the solution would be to “OpenHandle” on the extracted 64-bit code. This is a rudimentary knowledge of Windows programming. “OpenHandle” requires a process ID. I was able to find out with “ProcessHacker” tool(Figure 1).

Figure 1. Process tree

In this case, “3656” is the process ID.

But is it possible to execute “Open Handle” that is not described in the program? I tried running the program in an adventurous way. The method is to search for Kernel32.dll, find “OpenHandle”, and execute it using the “Set IP” function. I have tried this violent method.

I went to the Kernel32.dll segment and selected “Search”-”Text Search” from the menu. I typed “Open Process” in the dialog and pressed “OK”(Figure 2).

Figure 2. Search “OpenProcess” by text search
Figure 3. Search result of “OpenProcess” text search

I was able to discover “OpenProcess” in Kernel32.dll(Figure 3).
Let’s run this “OpenProcess”. “Set IP” moves the EIP to the “Open Process” address. “Open Process” requires arguments. The arguments should be examined on MSDN. The third parameter is the process ID. The decimal number “3656” is the hexadecimal number “0xE48”. Set the first argument to rcx, the second argument to rdx, and the third argument to r8. Don’t forget to move the stack pointer to a safe position(Figure 4).

Figure 4. Move EIP and set arguments
Figure 5. Result of OpenProcess

Processes before the return. Then, 0x0000000000000088 is set in EAX(Figure 5). This value is the process handle for “svchost.exe” on this 64-bit code!
We were able to get the target process handle.

Getting thread handle

“OpenThread” can also be executed in the same way as “OpenProcess”. The thread ID could be found by referring to the properties of the “ProcessHacker” tool(Figure 6).

Figure 6. Properties of “svchost.exe(3656)”

I found out that the thread ID is 5008. I searched for “OpenThread” in the same way as “OpenProcess”. The third parameter is the thread ID. The decimal number “5008” is the hexadecimal number “0x1390”. Then, use “Set IP” and execute it in the same way as “OpenProcess”(Figure 7).

Figure 7. Move EIP and set arguments
Figure 8. Result of OpenThread

Processes before the return. Then, 0x000000000000008C is included in EAX (Figure 8).

Reference of malicious code

The structure passed by “Heaven’s Gate” had the address and size of the malicious code. I needed to be able to reference this data in a 64-bit code. Dumping this memory data is easy because the structure contains the address and size on the 32-bit code. I saved it to a file in the same way as Pert 1. The extension was “.dmp”.

I tried to load this file. But it didn’t succeed. Because the “Load file” function must have a memory area on the process. Therefore, I had to provide a memory area on the process.

How to get memory area? I chose to use “VirtualAlloc”. The method is the same as “OpenProcess”.

Figure 9. Move EIP and set arguments
Figure 10. Result of VirtualAlloc

I ran VirtualAlloc with a large enough memory area. Then, 0x0000000002410000 is included in EAX. I got a memory area to load the data.

Let’s load the binary file in the prepared area. We can load it by selecting “File”-”Load file”-”Additional binary file…” from the menu (Figure 11).

Figure 11. Menu of Loading binary file
Figure 12. Select loading file
Figure 13. Parameters for loading file

Select the file to load from the dialog (Figure 12). As parameters to note, set “Loading segument” to blank and “Loading offset” to the address obtained by VirtualAlloc.

Figure 14. Loaded data

The data load was successful. From the 64-bit code process, I could now refer to the data that was on the 32-bit code process.

Accurate execution of 64-bit code and attach to the code of the injected svchost.exe

I knew the required parameters and was able to load the data. I thought I could simulate the exact behavior of Heaven’s Gate’s 64-bit code by running in this condition. I set the stack pointer correctly and set the EIP to the starting position with “Set IP” (Figure 15). The correct starting position had to be obtained by analysis in advance.

Figure 15. Set EIP to starting position

I will only introduce the important points of the processing to be executed.

The first point is calling the “NtAllocateVirtualMemory” API. The malware tried to allocate a memory area on the “svchost.exe” process. The malware set the handle of the “svchost.exe” process in the first argument. Therefore, the allocated area was on the “svchost.exe” process (Figure 16).

Figure 16. Calling NtAllocateVirtualMemory API

There is one supplementary information. The 64-bit code process copied the contents of the 32-bit code structure before this process. That means that the address and size of the malicious code, and process and thread handles for “svchost.exe” have been copied onto the stack. Overwrite these parameters with the address and size of the loaded data, and the results of OpenProcess and OpenThread. This makes it possible to analyze more smoothly.

The second point is calling the “NtWriteVirtualMemory” API. The malware set the handle of the “svchost.exe” process in the first argument. Therefore, the malicious code was copied to the memory area allocated on “svchost.exe” (Figure 17).

Figure 17. Calling NtWriteVirtualMemory API

“NtWriteVirtualMemory” was executed twice. The first time, the payload of the malware loaded by “Load file” was copied. The second time, a small 16-byte code was copied (Figure 18). This second code was the code to jump to the first copied code when thread was resumed.

Figure 18. Calling NtWriteVirtualMemory API (2)

The third point is calling the “ResumeThread” API. Resuming the code injected into “svchost.exe” will execute the malicious payload (Figure 19). This could be the real process of malware. The malware set the handle of the “svchost.exe” thread obtained by “OpenThread” as the first argument.

Figure 19. Calling ResumeThread

Before running “ResumeThread”, I had to attach to the process “svchost.exe” in the debugger.I was able to easily attach using IDA. I started IDA and selected “Debugger”-”Attach”-”Local Windows debugger” (Figure 20). Then, I selected the target “svchost.exe” (note the process ID) (Figure 21).

Figure 20. Menu for attaching to a process
Figure 21. Select the process to attach

I knew a suspicious address. It was the address where the code was copied by the second NtWriteVirtualMemory run. I knew from preliminary analysis that it was the code to jump to the malicious payload.

When I jumped to that address, I was able to find the code to jump to the malicious payload. I set a breakpoint at the beginning of the code (Figure 22).

Figure 22. Set breakpoint to stop malware process

It’s finally the last step. I ran “Resume Thread”. At this time, the attached process was paused. Processes attached by the debugger are automatically paused. I have resumed the attached process that was paused. Then, the process stopped at a breakpoint (Figure 23).

Figure 23. Stop the process at a breakpoint

Great!

I was able to stand at the starting point of malicious code injected into “svchost.exe”. If We analyze this code with a debugger, we will understand many behaviors of malware.

Conclusion

I wanted to analyze how the 64-bit code executed by Heaven’s Gate launches malware. And I wanted to accurately attach to the malware by imitating that behavior. I used a very muddy method, but I was able to achieve my goal. Please note that a correct analysis must be done in advance for this method to be successful. This is not a smart method, but if it is useful for your analysis, please refer to it.

--

--

Sachiel

Security Analyst in Japan. GIAC GREM (Gold) #165237