4

I'm trying to debug an application that reads the Parent Process Id(PPID), to check if the application is being debugged. It expects the PPID to be the PID of explorer.exe, if it isn't, it quits.

To bypass this, I wrote a pycommand script. This script breaks at the end of (and before the pops and ret) Process32NextW and Process32FirstW. Below is the hook I'm using:

class Process32NextWHook(LogBpHook):

def __init__(self):
    LogBpHook.__init__(self)
    return

def run(self, regs):
    imm = immlib.Debugger()

    # Get the Out_ LPPROCESSENTRY32 lppe
    PROCESSENTRY32 = regs["EBP"] + 16

    # Get the DWORD th32ParentProcessID
    target_ppid = PROCESSENTRY32 + 24

    # Get the DWORD th32ProcessID
    target_pid = imm.readMemory(PROCESSENTRY32 + 12, 4)

    # Get the debugged process id
    self_pid = imm.getDebuggedPid()

    # If the target pid matches our pid
    if int(target_pid.encode("HEX"), 16) == self_pid:
        # Set our ppid to the pid of explorer.exe
        imm.writeMemory(target_ppid, explorer_pid)
        imm.log("[*] patch_ppid patched ppid!!")

    return

However the

if int(target_pid.encode("HEX"), 16) == self_pid:

Is never true. My guess is that I use the wrong offsets, but I don't know what the right offsets would be. I could simply patch out the anti-debug measure, but that wouldn't be much of a learning experience.

Thanks.

  • 1
    target_pid is +8 not +12 – peter ferrie Jul 1 '16 at 15:50
  • @peterferrie yes, at first I thought that was the case, but if I print the value with +8, it's the wrong field – JeffreyZ Jul 2 '16 at 12:13
  • 1
    Just note that this method of debugger detection is super unreliable. Start process hacker and note that lots of services for instance don't have Explorer as parent... – mrexodia Jan 28 '17 at 17:11
  • 1
    @mrexodia in general you're absolutely right, different programs are executed by many different ways. But if the program author knows that their program should run only after a user double clicked it via explorer (decoy file extension for example) then it's an okay way to detect it, imo. Not the best way though... – Megabeets Jul 27 '17 at 18:55
  • @Megabeets I use Total Commander for everything, the parent would be TOTALCMD64.exe and I'm not doing anything shady, so no it's never a good way. – mrexodia Jul 27 '17 at 20:48
1

So after going through the existing immunity scripts and mona.py, I found out that you also need to unpack the readMemory return values. Working code:

class Process32NextWHook(LogBpHook):

def __init__(self, ppid):
    LogBpHook.__init__(self)
    self.new_ppid = ppid
    return

def run(self, regs):
    imm = immlib.Debugger()

    # Get the Out_ LPPROCESSENTRY32 lppe
    PROCESSENTRY32 = regs["EBP"] + 16

    # Get the DWORD th32ParentProcessID
    target_ppid = PROCESSENTRY32 + 28

    # Get the DWORD th32ProcessID
    target_pid = struct.unpack("<L", imm.readMemory(PROCESSENTRY32 + 12, 4))[0]

    # Get the debugged process id
    self_pid = imm.getDebuggedPid()

    # If the target pid matches our pid
    if target_pid == self_pid:
        # Set our ppid to the pid of explorer.exe
        imm.log("[*] patch_ppid patching ppid, Before: %d" % struct.unpack("<L", imm.readMemory(target_ppid, 4))[0])
        imm.writeMemory(target_ppid, self.new_ppid)
        imm.log("[*] patch_ppid Done patching, After: %d" % struct.unpack("<L", imm.readMemory(target_ppid, 4))[0])

    return

Feeling a bit stupid now, that I forgot something so basic. Oh well : )

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.