pydbgでAnti-Anti-Debugging

マルウェアなどがデバッグを難しくするためのテクニックの1つにAnti-Debuggingといわれるものがあります。
その名の通りデバッグを中止させるためのテクニックです。
Windows Anti-Debug Reference
リンク先で紹介されているIsDebuggerPresent()を用いたAnti-Debuggingの無効化をpydbgでやってみます。

基礎知識

IsDebuggerPresent()はデバッグされていたら1、されていなければ0を返すAPI
どう実装されているかというと、PEB(Process Enviroment Block)のBeingDebugged byte-flagを読んでいるだけ。
つまりIsDebuggerPresent()を使ったAnti-Debuggingを無効にするにはこのフラグを0に書き変えてやればいいいのです。

PEBははFSレジスタの中のTIB(Thread Information Block)のさらにその中にあります。
TIBのFSレジスタからのオフセットは0x18、PEBのTIBからのオフセットは0x30、フラグのPEBからのオフセットは0x2と固定さているので簡単に書き換えができるのです。

実装

from pydbg import *
from pydbg.defines import *

def hide_debugger(self):
    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)

    peb = self.read_process_memory(fs_base + 0x30, 4)
    peb = self.flip_endian_dword(peb)

    self.write_process_memory(peb+2, "\x00", 1)
    return self.ret_self()

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

    return DBG_CONTINUE

if __name__ == "__main__":
    dbg = pydbg()
    dbg.set_callback(EXCEPTION_BREAKPOINT, handler_bp)
    dbg.load("IsDebuggerPresent.exe")
    dbg.run()

pydbgだとこんなコードになります。


Immunity Debuggerを使うと・・・

imm.WriteMemory(img.getPEBaddress() + 2, "\x00")

これだけで済みます。便利ですね。