Debugging Hollow Processes

This post is a quick example of how to continue debugging a hollow process. I'm not going to discuss the technical steps for hollowing out a process. I'd recommend this post by Dinesh Venkatesan to get an idea of what the code looks like in a debugger. Then I'd recommend a post by the admin at CodeReversing to get an idea of the C++ code. Hollowing out a process is a simple technique. First the malware creates a process in a suspended state by calling CreateProcess, calls ZwUnmapViewSection to un-reserve the memory, allocates memory using VirtualAlloc, writes data to the process memory using WriteProcessMemory, retrieves the context  of the thread using GetThreadContext, modifies the context and then sets the context using SetThreadContext and then call ResumeThread to start the process. Process hollowing makes stepping through the malware code difficult because the called thread will be running outside of the debugged process. A logical step would be to attach to the suspended process using Ollydbg. Unfortunately, Ollydbg 1.1 can not attach to a suspended processes. So how can we keep walking through the hollowed out processes once the ResumeThread is called?

Our first step will be to find the entry point of the hollowed out process, patch it with 0xCC (int9), set Ollydbg as the just in time debugger, let the malware execute till after it calls ResumeThread. At this point we the malware cause the hollowed process to be opened in Ollydbg. We can then patch the malware with the original bytes and we will be good to go.


In the recommended blog posts it was stated that the entry point will be stored in the EAX register of the CONTEXT structure. If we were to compile CodeReversing's C++ and view the code in IDA we would have the above assembly (left) and the CONTEXT structure (right). Since we know EAX will contain the address we need to find that address in the CONTEXT structure of the memory of the malware. We know that the malware will use SetThreadContext to set the register of EAX so we can set a breakpoint on it before it's called. 

From MSDN
BOOL WINAPI SetThreadContext(
  _In_  HANDLE hThread,
  _In_  const CONTEXT *lpContext
); 
 
If we wanted to get the contents of the EAX in the CONTEXT structure we would need to find the address of lpContext [0xB0].  In the example above the entry point is 0x40EE60. Since we know the address of the entry point we will need to patch it. The best non-complicated tool I have found for patching the memory of a running process is Process Hacker. Once we have it running we will locate the hollowed out process running under the malware. Right Click, Properties and the locate the memory section of the hollowed out process.


We will then need to patch the memory with 'cc' aka INT3 (remember the original byte) , press "Write" and now the hollowed out process has been patched. We will need to setup our just in time debugger by opening Ollydbg > Options > Just-in-time debugging. Then we will need to step through the code after the SetThreadContext until ResumeThread is called. After it's called the INT3 instruction will be executed and our Just in time debugger will open up Ollydbg. We now can patch the INT3 with the original byte and now continue stepping through the code that was written to the hollow process.

Patching with INT3 can be very useful. I have used it many times when I want to debug a service with ollydbg. Hope this was helpful to anyone who might come across this problem. Cheers.

Update 2014/08/29
If the sample uses the CreateRemoteThread and LoadLibrary* technique the following steps can be used.
  1. Open the sample in a debugger
  2. Set a breakpoint on OpenProcess and execute till the breakpoint is hit.
  3. Open a separate instance of the child process that is being injected into. 
  4. Change the process-id (3rd argument for OpenProcess) to the newely created child process. 
  5. Set a bp on LoadLibrary* in the child/dummy process in the debugger. 
  6. Execute to LoadLibrary* is hit. 
  7. Set a breakpoint on the DLLEntryPoint of the dll. 
  8. Start walking through the code.

14 comments:

  1. Another trick to pause at the new EntryPoint of the suspended process is to attach to it via. another debugger e.g. WinDbg and set a breakpoint at ntdll!RtlUserThreadStart (Win7) or kernel32!BaseProcessStartThunk (WinXP). Once we are at RtlUserThreadStart or BaseProcessStartThunk, inspect the value of EAX and place another breakpoint.

    As follows (In Win7):
    bp ntdll!RtlUserThreadStart

    bp @eax

    The reason why OllyDbg v1.10 can't attach to a suspended process (initially suspended) is due to the process's PEB being incompletely initialized. This happens at point OllyDbg v1.10 tries to call "EnumProcessModules" function. Sorry if off-topic.

    ReplyDelete
    Replies
    1. Not off topic at all. Thank you for the information. I was wondering how others would go about it and why I couldn't attach to the process. Keep up the great posts on your blog. Cheers.

      Delete
    2. How exactly would i attached windbg to it. When I do it gives me an error. I am attaching before ResumeThread()
      thanks in advance.

      Delete
    3. Sorry, but I don't know how to mimic the steps in Windbg. I'd recommend checkout out waliedassar comments (2 above). That will probably point you in the right direction.

      Delete
  2. You can also force the new process to initialize itself by injecting a thread using CreateRemoteThread on Sleep() for example. After that thread returns, you can attach with Olly v1.10.

    ReplyDelete
    Replies
    1. How would that work? Sleep suspends the current thread, not the whole process.

      Delete
    2. If the process is suspended (initially suspended), then its Process Environment Block (PEB) is not completely initialized and this is why OllyDbg v1.10 can't attach to it (due to the "EnumProcessModules" function failure).

      But once you create a dummy thread into this suspended process, the uninitialized values in its PEB will be filled i.e. PEB becomes ready and the suspended process appears in the "Select process to attach" dialog box of OllyDbg v1.10.

      Hope this helps.

      Delete
  3. Nice. Excellent run-through...

    ReplyDelete
  4. Have you considered the "EB FE" technique? Right before resuming the remote thread. Patch the first two instructions with "EB FE". On resuming the thread, it'll be put into an infinite loop stuck in the same "EB FE" instruction. You can now attach with a debugger, path the "EB FE" bytes back and start debugging.

    ReplyDelete
    Replies
    1. I have used the EB FE technique many times. I'm a big fan of it. The int3 technique is nice because it removes having to attach to the process manually and it's one byte shorter.

      Delete
  5. Just Look For WriteProcessMemory Call After VirtualAllocEx and You can get the Address of Executable to Written on SUSPENDED Process,You Can Easily DUMP it .

    ReplyDelete
    Replies
    1. Correct but dumping a process and continuing to debug a process are two separate things. I'd recommend re-reading the post.

      Delete
  6. Unfortunately, Ollydbg 1.1 can not attach to a suspended processes.

    try https://www.openrce.org/repositories/users/anonymouse/ModifiedCommandLinePluginWithChildDbg_Date_16082008.rar

    it has its own problems but it succeeds in attaching to a child process most of the time :D

    ReplyDelete