Flag: Tornado! Hurricane!

 Forums >>  Debuggers  >>  Anti-Debugger Support in PaiMei

Topic created on: August 24, 2006 00:01 CDT by ryanlrussell .

I'm trying to stalk an app that has a silly antidebugger check (IsDebuggerPresent).  I know how to deal with this in IDA Pro or Ollydbg.  However, I can't start debugging under those, and then attach with PaiMei.  I believe you only get one debugger.  And I don't believe you can detach a debugger sucessfully before Win2K3.  Even if you could, I assume it would just put the debugging flag back.

Ideally, I'd like to avoid patching the binary.  It would be easy enough in this case, but less so in others.

So, it would appear that pydbg will be the only debugger you can use when stalking.  Question is have you planned for any kind of scripted startup when attaching to or launching a process with PaiMei? (Such as, the obvious clearing the debug flag in the PEB.)  And/or thought about adding the ability to break in with some debugger UI while stalking?

  pedram     August 24, 2006 14:12.44 CDT
There are no plans for using any other debugger other then PyDbg for stalking.

There is an unfinished routine in the pydbg.py class, hide_debugger(), which is supposed to accomplish the very task you need.

Defeating IsDebuggerPresent() is a joke, it's a simple matter of updating a flag. If you complete that portion of the routine, please submit a patch. Hopefully, as the need arises, other people can add more sophisticated anti-anti-debugging logic to that routine.

  quig   August 24, 2006 18:52.27 CDT
write a small wrapper for writeprocessmemory in so you can patch fx in memory or overwrite the peb flag at runtime

  pedram     August 29, 2006 18:06.16 CDT
Ryan: I needed the feature, like 5 minutes ago, so I thought I'd share. I haven't debugged this, but it appears to be working. Replace the current shell function with the following:


def hide_debugger (self):
    '''
    Hide the presence of the debugger. This routine requires an active context and therefore can not be called
    immediately after a load() for example. Call it from the first chance breakpoint handler. This routine hides
    the debugger in the following ways:

        - Modifies the PEB flag that IsDebuggerPresent() checks for.

    @raise pdx: An exception is raised if we are unable to hide the debugger for various reasons.
    '''

    selector_entry = LDT_ENTRY()

    # a current thread context is required.
    if not self.context:
        raise pdx("hide_debugger(): a thread context is required. Call me from a breakpoint handler.")

    if not kernel32.GetThreadSelectorEntry(self.h_thread, self.context.SegFs, byref(selector_entry)):
        self.win32_error("GetThreadSelectorEntry()")

    fs_base  = selector_entry.BaseLow
    fs_base += (selector_entry.HighWord.Bits.BaseMid << 16) + (selector_entry.HighWord.Bits.BaseHi << 24)

    # http://openrce.org/reference_library/files/reference/Windows Memory Layout, User-Kernel Address Spaces.pdf
    # find the peb.
    peb = self.read_process_memory(fs_base + 0x30, 4)
    peb = self.flip_endian_dword(peb)

    # zero out the flag. (3rd byte)
    self.write_process_memory(peb+2, "\x00", 1)

    return self.ret_self()

  ryanlrussell     August 30, 2006 01:06.47 CDT
> pedram: Ryan: I needed the feature, like 5 minutes ago, so I thought I\'d share. I haven\'t debugged this, but it appears to be working. Replace the current shell function with the following:

Cool, thanks.  So far, my attempts at learning Python in a couple of hours hadn't gotten me there yet.  I think you had the minimum functionality there already, with just a typo.  Though it looks like you've added some useful error checking.

But where I was stuck was trying to figure out the right place to add a hide_debugger call in the rest of the Paimei code.

If you know where, I'd be happy to test it out.  I've got a DebuggerPresent.exe sitting right here that I compiled up...

  pedram     August 30, 2006 11:03.17 CDT
> ryanlrussell: > If you know where, I'd be happy to test it out.  I've got a DebuggerPresent.exe sitting right here that I compiled up...

Register a breakpoint handler and hide the debugger at the first breakpoint:


#!c:\python\python.exe

from pydbg import *
from pydbg.defines import *

def handler_bp (dbg):
    if dbg.first_breakpoint:
        dbg.hide_debugger()

    return DBG_CONTINUE

dbg = pydbg()
dbg.set_callback(EXCEPTION_BREAKPOINT, handler_bp)
dbg.load("IsDebuggerPresent.exe")
dbg.run()

  ryanlrussell     September 1, 2006 01:27.03 CDT
Works perfectly, both your hide_debugger update, and your sample code.  Verified both the positive and negative case by REMing out the hide_debugger call.  Thanks again!

  igorsk     September 1, 2006 18:40.29 CDT
I also used the new code in QTFairUse6 v2. Works perfectly :)

  Roady     September 2, 2006 03:02.56 CDT
Works perfectly!

I have a stupid question however. I have a program that uses SEH for anti-debugging.

What I don't understand is that the exceptions generated by the program don't seem to be caught by PyDbg. Moreover, the custom handlers of the program are not executed either, resulting in the debugger being detected anyway.

Any idea ?

  ryanlrussell     September 2, 2006 13:21.14 CDT
So, a few more random things related to this topic.  Does anyone (and I hate to keep bugging Pedram) know where one would insert the hide_debugger call in Paimei?  I thought this was going to do it:


    ####################################################################################################################
    def handler_breakpoint (self, dbg):
        '''
        The breakpoint handler is of course responsible for logging the code coverage.
        '''

        dbg.hide_debugger()

        if dbg.get_attr("first_breakpoint"):
            return DBG_CONTINUE

        if self.print_bps:
            self.log("debugger hit %08x cc #%d" % (dbg.exception_address, self.cc.num))

        is_function = 0
        for module in self.pida_modules.values():
            if module.nodes.has_key(dbg.context.Eip):
                is_function = 1
                break

        self.cc.add(dbg, is_function)

        return DBG_CONTINUE

in process_stalker.py

Doesn't seem to work, though.  It looks like there are 4 handlers, but this one is the one that matches the example.  My excuse for being lame is that I'm trying to learn Python and Pedram's framework at the same time.  I'm about to trying throwing in some print debugging, but I thought I'd ask here first.

Since it looks like at least a couple of us are looking at iTunes, a quick brain dump.  If one doesn't have Paimei set up to do the silly IsDebuggerPresent bypass yet, then you have to patch the executable.  Version 6.0.4.2.  Right below  this call:

0066CF90                 call    ds:IsDebuggerPresent ;

Is a condition jump, which you can change to an absolute jump.  But once you've patched the file at all, you also have to fix this:

004FB8AA                 call    check_MD5

A couple of lines below that, you have another conditional jump which you can change to an absolute jump to make it always pass the MD5 check.

As for Roady's question, which is basically "what about more advanced antidebugger tricks?".  I certainly don't know why pydbg isn't picking up the exception you expected.  Do you have your own wrapper code, and did you register a callback for that exception type?  For example, I see this in the stalk function in process_stalker:

        self.pydbg.set_callback(EXCEPTION_BREAKPOINT,       self.handler_breakpoint)
        self.pydbg.set_callback(LOAD_DLL_DEBUG_EVENT,       self.handler_load_dll)
        self.pydbg.set_callback(EXCEPTION_ACCESS_VIOLATION, self.handler_access_violation)
        self.pydbg.set_callback(USER_CALLBACK_DEBUG_EVENT,  self.handler_user_callback)


But there are also the general cases, where this won't help either.  This kind of thing is one of the reasons I was asking about the possibility of getting a live debugger GUI working with pydbg.

So, you can always patch an executable, or unpack it ahead of time.  I suppose the latter doesn't help if you're trying to get pydbg to do the unpacking for you.

Since stalker is already doing branch tracing, it might be interesting if one could tell it to take the other branch in key places.  Maybe modify the instruction, or temporarily flipping the zero flag or something.  I guess right now, IDA is the GUI for prepping a binary, so you'd want a way in IDA to flag a branch for bypass.

Might be cool if I could load a set of patches once the process has been loaded.  If I could do that, I wouldn't have had to patch out the MD5 check, which goes after the file on disk.  The hide_debugger call is a patch of sorts, so I don't see why not.  The hardest bit is the storage format, and the interface for building the list of patches.

Anyway, back to trying to make myself competent enough to do some of these on my own, rather than just asking others to do it for me.

  ryanlrussell     September 2, 2006 18:58.59 CDT
Ah, there!  See, I was assuming that process_stalker.py would be the in in the utils directory in the paimei install.  But no, python or something else squirreled away a copy in C:\Python24\lib\site-packages\utils.  In case I messed it up by editing it or something, I guess...

WTF?

Well, that only took all day, and the use of filemon to figure out...

So my quick and dirty change to handler_breakpoint earlier in the thread does actually function.

  Roady     September 2, 2006 19:57.24 CDT

Too bad I only saw your post now, I had the same problem earlier.

  Roady     September 2, 2006 20:01.36 CDT
The anti-debug trick is using a int3. I would have thought that int3 would be caught by "exception_breakpoint".

  igorsk     September 2, 2006 20:32.57 CDT
> ryanlrussell: Ah, there!  See, I was assuming that process_stalker.py would be the in in the utils directory in the paimei install.  But no, python or something else squirreled away a copy in C:\\Python24\\lib\\site-packages\\utils.  In case I messed it up by editing it or something, I guess...
That's the result of answering "y" to "Install PaiMei framework libraries to Python site packages?" in __install_requirements.py.

  ryanlrussell     September 2, 2006 21:06.28 CDT
> Roady: The anti-debug trick is using a int3. I would have thought that int3 would be caught by \"exception_breakpoint\".

Do you want to post the snippet of antidebugger disassembly you're trying to bypass?

  ryanlrussell     September 2, 2006 21:10.44 CDT
> igorsk:
> That\'s the result of answering \"y\" to \"Install PaiMei framework libraries to Python site packages?\" in __install_requirements.py.

I think you're probably right.  Well, that will teach me.  Even so, I would have thought it would pick up the local edited copy, since that what the includes pointed to.

  Roady     September 3, 2006 05:15.39 CDT
> ryanlrussell: > Roady: The anti-debug trick is using a int3. I would have thought that int3 would be caught by \\\"exception_breakpoint\\\".
>
> Do you want to post the snippet of antidebugger disassembly you\'re trying to bypass?

I will try to make a functionnally equivalent program. But this week I will be really busy.

  Roady     September 3, 2006 16:53.15 CDT
This code detects PyDBG:

#include <windows.h>
#include <stdio.h>

  LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *lpTopLevelExceptionFilter)
  {
lpTopLevelExceptionFilter->ContextRecord->Eax++;    
lpTopLevelExceptionFilter->ContextRecord->Eip++;
    return -1;
  }

int main(int argc, char **argv)
{
int result = 0;

SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);

__asm
    {
        push eax
xor eax,eax
        int 3
    mov result,eax
pop eax    }

if (result == 0)
{
printf("debugger detected!\n");
}
else
{
printf("debugger not detected!\n");
}
}

Here is my script:

from pydbg import *
from pydbg.defines import *

def handler_bp (pydbg):

if pydbg.first_breakpoint:
dbg.hide_debugger()
          print "Exception caught from %d @%08x => debugger hidden" % (pydbg.dbg.dwThreadId, pydbg.exception_address)   
return DBG_CONTINUE
print "Exception caught from %d @%08x" % (pydbg.dbg.dwThreadId, pydbg.exception_address)   
return DBG_CONTINUE
  

dbg = pydbg()
dbg.set_callback(EXCEPTION_BREAKPOINT, handler_bp)

print "\nLoading program\n"
dbg.load("int3test.exe")

dbg.run()


## my indentation got messed up when pasting :-/

I am not really good at this exception stuff, any idea?

  ryanlrussell     September 4, 2006 01:38.19 CDT
> Roady: This code detects PyDBG:

I can't get your example C program to detect me.

D:\paimei>c:\Python24\python.exe antidebug_int3.py
Exception caught from 3132 @7c901230 => debugger hidden
debugger not detected!

Same when running in the debugger in IDA or MSVC.  I'm not sure your example is correct.

  Roady     September 4, 2006 05:29.18 CDT
I don't know which version you tried, but the first one I posted was full of bugs (and strangely it still worked on my system). I think I fixed it now.

I also think that it is better to compile in "release" mode.

  pedram     September 4, 2006 11:27.22 CDT
Roady: PyDbg does not call the registered handler if the triggered breakpoint is not one that was explicitly set. On that note, there is a bug in the current release regarding the handling of exceptions triggered by the debuggee. This has been fixed for a few revisions now in subversion along with some other bugs.

I'll do a new release this week sometime.

-pedram

  Roady     September 4, 2006 13:13.22 CDT
> pedram:  PyDbg does not call the registered handler if the triggered breakpoint is not one that was explicitly set.

And it does not pass the exception to the application either ?

Note: Registration is required to post to the forums.

There are 31,313 total registered users.


Recently Created Topics
[help] Unpacking VMP...
Mar/12
Reverse Engineering ...
Jul/06
hi!
Jul/01
let 'IDAPython' impo...
Sep/24
set 'IDAPython' as t...
Sep/24
GuessType return une...
Sep/20
About retrieving the...
Sep/07
How to find specific...
Aug/15
How to get data depe...
Jul/07
Identify RVA data in...
May/06


Recent Forum Posts
Finding the procedur...
rolEYder
Question about debbu...
rolEYder
Identify RVA data in...
sohlow
let 'IDAPython' impo...
sohlow
How to find specific...
hackgreti
Problem with ollydbg
sh3dow
How can I write olly...
sh3dow
New LoadMAP plugin v...
mefisto...
Intel pin in loaded ...
djnemo
OOP_RE tool available?
Bl4ckm4n


Recent Blog Entries
halsten
Mar/14
Breaking IonCUBE VM

oleavr
Oct/24
Anatomy of a code tracer

hasherezade
Sep/24
IAT Patcher - new tool for ...

oleavr
Aug/27
CryptoShark: code tracer ba...

oleavr
Jun/25
Build a debugger in 5 minutes

More ...


Recent Blog Comments
nieo on:
Mar/22
IAT Patcher - new tool for ...

djnemo on:
Nov/17
Kernel debugger vs user mod...

acel on:
Nov/14
Kernel debugger vs user mod...

pedram on:
Dec/21
frida.github.io: scriptable...

capadleman on:
Jun/19
Using NtCreateThreadEx for ...

More ...


Imagery
SoySauce Blueprint
Jun 6, 2008

[+] expand

View Gallery (11) / Submit