KOrUPt

Debugging child processes and injectors

by KOrUPt on Jan.14, 2009, under Malware analysis, Reversing, Tips and Tricks

A question I get asked quite often is how to go about debugging a child process or a DLL injector. For a Malware analyst knowing these techniques has become a necessity, given most common day Malware uses the aforementioned methods to aid in achieving their goal and sometimes static analysis just isn’t good enough.

For those curios as to what a DLL file is, I shall refer you to the article on Wikipedia:

  • http://en.wikipedia.org/wiki/Dynamic-link_library

I’m sure at least a few readers have come across Malware that has utilized DLL injection in one way or another, but for those who haven’t, I’ll briefly cover some of the various reasons Malware may use these nefarious techniques… Some use the technique in an attempt to bypass firewalls by executing their own code from within a trusted process and others attempt to subvert certain applications that may be used to detect their presence… The list goes on.

Injecting a DLL into a foreign process has become a rather trivial task these days, even more so given the amount of code laying around the internet.

Most commonly you’ll see an injector using the CreateRemoteThread() API, but it’s worth pointing out that there are some less known methods, such as using the undocumented NtQueueApcThread() routine.

In order for a DLL injector to do its work, it has to know whereabouts the target DLL file is located on the system. You can usually find the path to this DLL by setting a breakpoint on the WriteProcessMemory() API, as this API is typically used to write the location of the DLL into the foreign process’s memory.

IDA is mostly used for static analysis and given we’ll be debugging, I’ll be using OllyDbg, of course you can still use your preferred debugger(WinDbg for instance).

Once we have the path of our DLL, we can open it inside our debugger, you’ll typically see the CRT initialization routines, disassembly of a DLL compiled within MSVC6 using optimizations would look similar to this(main routine):

PUSH    EBP
MOV     EBP, ESP
CMP     [ARG.2], 1
JNZ L011
PUSH    0
PUSH    0
PUSH    0
PUSH    DLL.003F105E
PUSH    0
PUSH    0
CALL CreateThread
L011:
MOV     EAX, 1
POP     EBP
RETN    0C

A new thread is created so the process that has been injected with the DLL doesn’t hang. The first comparison is checking the 2nd parameter of DLLMain() is DLL_PROCESS_ATTACH, which is defined as 1.

Upon checking the threads code, we see the following:

PUSH    EBP
MOV     EBP, ESP
SUB     ESP, 0C
PUSH    DLL.003F505C
PUSH    0
CALL FindWindowA
MOV     [LOCAL.1], EAX
MOV     EAX, [LOCAL.1]
PUSH    EAX
CALL GetMenu
MOV     [LOCAL.2], EAX
CALL CreateMenu
MOV     [LOCAL.3], EAX
PUSH    DLL.003F5070
MOV     ECX, [LOCAL.3]
PUSH    ECX
PUSH    10
MOV     EDX, [LOCAL.2]
PUSH    EDX
CALL AppendMenuA
...

Basically, the DLL is obtaining a handle the process’s window and adding a menu, along with subclassing the window procedure(not visible in the above code). The DLL was injected using the traditional CreateRemoteThread() API.

The Just-In-Time debugger comes in handy here, I’ve configured my JIT debugger to be OllyDbg(which can be done via the options menu of OllyDbg), the idea is to cause the injected process to crash, then attach to the process using the JIT debugger.

We can cause the injected process to crash by throwing an exception, we can cause an exception to be thrown simply by overwriting the function prolog/epilog with an INT3(breakpoint) instruction. For those who don’t know what I mean by prolog, I’m referring to the instructions that set up the functions local stack, those being:

PUSH    EBP
MOV     EBP, ESP
SUB     ESP, 0C

We can overwrite the PUSH EBP instruction with an INT3 instruction and restore the overwritten bytes once attached to the process.

Overwrite the instruction, save the changes and run the DLL injector/Sample, once the DLL has been injected, the target process will hopefully crash and the MS Error Reporting dialog will appear, upon clicking clicking the “Debug” button OllyDbg will launch and attach to the process.

If you’re not currently paused at the INT3 instruction press Alt + F9(pass exception) until you reach it. We can then restore the original instruction, that being “PUSH EBP” and step through the code as normal.

I feel the need to point out that the above steps should only be used within a controlled environment, as some Malware sample’s can be crafty…

For instance, a custom SEH(Structured Exception Handler) may be setup to catch exceptions which means the MS Error Reporting dialog will not appear and the process may execute a fall back routine. We can circumvent custom SEH but I’ll be saving that for another article. For those eager, it mainly involves overwriting the current exception handler with the one used within kernel32.

We can use the same technique described above to debug child process’s.

For Linux users, GDB offers a few useful functionalities to follow child process’s, it can be configured to follow fork()’s and such by issuing the following commands:

  • set follow-fork-mode child
  • set detach-on-fork     on

It can be useful to follow a child process sometimes, as most of the time a certain possibly important routine is only carried out inside the child process.

As for debugging sample’s that use DCI(Direct Code Injection), we can again breakpoint the WriteProcessMemory() API and modify the buffer of instructions that is being written into the target process so it contains an INT3 instruction, after which we can proceed as mentioned previously…

And on that note, I think that just about covers this article.

I look forward to reading any questions and or comments you may have. Let me know of any experiences you have have had whilst debugging such Malware sample’s.

I hope you enjoyed the read.

KOrUPt.

:, , , , ,

11 Comments for this entry

  • meh

    I wonder if you purposefully left out EBFE-breakpoints

    EBFE is the opcode of a JMP -1, so it’s an endless loop.

    Instead of crashing the app with a spurious interrupt, you dump the process in an endless loop, and attach to it later. This is particularly useful in the debugging child process.

  • KOrUPt

    That little trick slipped my mind. Various polymorphic breakpoint techniques come to mind :p,

    Thanks for the input, as always.

    KOrUPt.

  • meh

    yeah, this was pretty hot in the arma days.

    The benefit of EBFE is that the main purpous that malware typically spawns a child process as debugee. There can only be one debugger so attaching to it is slightly tricky. Just throwing the child into an endless loop and hence “pausing” it, gives you a chance to handle the parent and detach/kill it..
    So i wondered if you were sparing this for the article that would cover replacing the structured exception handlers.

    but the main reason for this post is because i made quite a big error saying it’s JMP -1, while FE clearly is -2(in two’s complemenet), and hence also the opcode length ;-)

    googling for EBFE will give you a few nice reads. I know it took me some time before i realized that “ebfe breakpoint” was not just a typo ;-) .

    Cheers.

  • KOrUPt

    Thanks for the input as usual :) .

    I didn’t notice the -1 part, I just go by the opcodes :p.

    I can understand the preference for EBFE over an INT3 regarding Armadillo, given all those nanomites lying around, amongst other things.

    I’ll do writeup on overwriting exception handlers later tonight :) .

    Hm, perhaps I should recruit a few more authors for this Blog.

    KOrUPt.

  • DiabloHorn

    dude thanks :D this indeed covers what I needed. Will try it out soon enough.

  • kellogs

    hi,

    interresting read ^^

    Can you clarify a bit more pls. From what I am reading here, I simply cannot debug my target process after injecting my dll by just selecting debug->attach to process in VS. Of course, I do have the dll source. Is this the case ?

    thanks

  • KOrUPt

    Insert a breakpoint instruction at the entry point of your DLL then inject it, after which you can attach to the ‘paused’ process using the JIT debugger. Watch out for VEH and SEH.

    Hope this helps.

    KOrUPt.

  • kellogs

    “Watch out for VEH and SEH.” – u have just opened my eyes to a new way of hooking. sweet.

    But.. what do you mean to whatch out for those ? why ?

    And another one – how can I place a breakpoint (from VS2008) inside kernel32.dll ? I know I managed to somehow do this from VS2003 .. but I just cant get it right this time in VS2008.

    How nice for hackerts to keep blogs now :) . Keep it up!
    kellogs

  • KOrUPt

    I say to watch out for VEH and SEH because if you’re using a breakpoint(INT 3), to cause the injected DLL to call upon the MS Error handler(so you can attach to the process using the JIT debugger), the Dialog will not be called upon if custom exception handlers are in place(SEH/VEH and the like), thus you end up with unexpected results…

    If you look through the other posts on my Blog you’ll find I’ve wrote a small article about this :) .

    I don’t use VS2008 so I can’t really help with your 2nd problem :( . Perhaps one of my other readers would like to comment?

    Hope this helps.

    Also I apologise for the drought in new posts at the moment. I’m rather busy at the moment…

    KOrUPt.

  • kellogs

    thank you,

    i shall try it out when I’ll be more awake ^^

1 Trackback or Pingback for this entry

Leave a Reply

Looking for something?

Use the form below to search the site:

Still not finding what you're looking for? Drop a comment on a post or contact us so we can take care of it!

Archives

All entries, chronologically...