Debugger/Disambler unter Python (2.7)

In diesem Tutorial erkläre ich euch wie man einen eigenen Blackboxdebugger unter Windows mit Python (2.7) programmiert.
Vorausgesetzt wird:
  • Windows (min. XP) (mit Linux/Unix geht es auch aber die Grundfunktionen unterscheiden sich
  • Kenntnisse der Sprache Python
  • Kenntnisse der Bedeutung von Breakpoints
  • Kenntnisse der Sprache C/C++ ( nur zum verstehen der Win-Funktionen )
  • Kenntnisse von ctypes
  • Spaß am Programmieren

Nun, was ist ein sog. Blackboxdebugger ?
Ein Blackboxdebugger ( auch Disambler genannt ) disambliert ein Programm oder eine dynamische Link Libary (Windows: .dll ; Linux: .io ), d.h. er übersetzt den compilierten Code von den Nullen und Einsen zu einen schon besser lesbaren Code in der Programmiersprache Assembler.

Zum Programmieren des Debuggers werde ich die Grundfunktionen von Windows verwenden die in der kernel32.dll definiert sind.

1) Die Funktionen die Verwendet werden sollen:
  • CreateProcessA()
  • OpenProcess()
  • DebugActiveProcess()
  • WaitForDebugEvent()
  • ContinueDebugEvent()
  • DebugActiveProcessStop()
  • OpenThread()
  • CreateToolhelp32Snapshot()
  • THREADENTRY32() || C structuer
  • GetThreadContext()
  • SetThreadContext()
  • OpenThread()
  • ReadProcessMemory()
  • WriteProcessMemory()
  • GetProcAddress()
  • VirtualProtectEx()

Die Bedeutung der einzelnen Funktionen werde ich im Quellcode in den Kommentaren erklären.

Zunächst müssen wir die alle Strukturen die in den Funktionen definiert mit ctypes "nachbilden" damit sie von der jeweiligen Funktion verwendet werden können.
Legt zunächst eine Datei dbg_def.py an und schreibt den folgenden Code rein:

Code:
from ctypes import *

# Windows Typen werden zur Sicherheit definiert
# In den Kommentaren ist der C++ äquivalent
WORD       =  c_ushort              # unsigned short
DWORD     =  c_ulong               # unsigned long
LPBYTE     =  POINT(c_ubyte)    # char
LPSTR       =  c_void_p             # void

# Konstanten die während des Debuggen übergeben werden
DEBUG_PROCESS           = 0x00000001
CREATE_NEW_CONSOLE = 0x00000010

# Hier sind die Debuggeventsdefiniert,
# sie werden teilweise in den Funktionen gebraucht.
EXCEPTION_DEBUG_EVENT      =    0x1
CREATE_THREAD_DEBUG_EVENT  =    0x2
CREATE_PROCESS_DEBUG_EVENT =    0x3
EXIT_THREAD_DEBUG_EVENT    =    0x4
EXIT_PROCESS_DEBUG_EVENT   =    0x5
LOAD_DLL_DEBUG_EVENT       =    0x6
UNLOAD_DLL_DEBUG_EVENT     =    0x7
OUTPUT_DEBUG_STRING_EVENT  =    0x8
RIP_EVENT                  =    0x9

# Hier werden die einzelnen Werte gespeichert sollte man,
# bestimmte INT-werte setzen wollen um z.B: einen Softwarebreakpoint 
# zu setzen
EXCEPTION_ACCESS_VIOLATION     = 0xC0000005
EXCEPTION_BREAKPOINT           = 0x80000003
EXCEPTION_GUARD_PAGE           = 0x80000001
EXCEPTION_SINGLE_STEP          = 0x80000004

# Hier sind Werte und Variabeln für einen Processsnapshot gesetzt
# Ein Processsnapshot wird mit der Funktion CreateToolhelp32Snapshot()
# erstellt.
# Processsnapshots sind einfach gesagt "Bilder" des Prozesses,
# mit denen kann man einen Prozess zu einen früheren Punkt 
# "zurücksetzten". Die Variabeln sind auch betroffen.
TH32CS_SNAPHEAPLIST = 0x00000001
TH32CS_SNAPPROCESS  = 0x00000002
TH32CS_SNAPTHREAD   = 0x00000004
TH32CS_SNAPMODULE   = 0x00000008
TH32CS_INHERIT      = 0x80000000
TH32CS_SNAPALL      = (TH32CS_SNAPHEAPLIST | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD | TH32CS_SNAPMODULE)
THREAD_ALL_ACCESS   = 0x001F03FF

# Diese Deklarationen werden von der Funktion GetThreadContext() 
# verwendet, um die einzelnen CPU-Register mit den Werten abzurufen
CONTEXT_FULL                   = 0x00010007
CONTEXT_DEBUG_REGISTERS        = 0x00010010

# Hier werden die Rechte definiert mit denen man auf die Werte zugreift.
# Dieses Thema ist etwas kompliziert und hier nicht von belangen deswegen 
# werde ich , dies nicht weiter erklären.
# Es reicht wenn ihr es reinschreibt 
PAGE_EXECUTE_READWRITE         = 0x00000040

# Hier sind die "Bedingungen" definiert um einen Hardwarebreakpoint zusetzten
HW_ACCESS                      = 0x00000003
HW_EXECUTE                     = 0x00000000
HW_WRITE                       = 0x00000001

# Hier sind die Rechte zum Zugreifen auf die Dateien definiert.
# Diese werden von der Funktion VitrualProtect() verwendet.
# 
PAGE_NOACCESS                  = 0x00000001
PAGE_READONLY                  = 0x00000002
PAGE_READWRITE                 = 0x00000004
PAGE_WRITECOPY                 = 0x00000008
PAGE_EXECUTE                   = 0x00000010
PAGE_EXECUTE_READ              = 0x00000020
PAGE_EXECUTE_READWRITE         = 0x00000040
PAGE_EXECUTE_WRITECOPY         = 0x00000080
PAGE_GUARD                     = 0x00000100
PAGE_NOCACHE                   = 0x00000200
PAGE_WRITECOMBINE              = 0x00000400

# Für die Funktion CreateProcessA(), damit werden die Programme gestartet,
class STARTUPINFO(Structure):
    _fields_ = [
        ("cb",            DWORD),        
        ("lpReserved",    LPTSTR), 
        ("lpDesktop",     LPTSTR),  
        ("lpTitle",       LPTSTR),
        ("dwX",           DWORD),
        ("dwY",           DWORD),
        ("dwXSize",       DWORD),
        ("dwYSize",       DWORD),
        ("dwXCountChars", DWORD),
        ("dwYCountChars", DWORD),
        ("dwFillAttribute",DWORD),
        ("dwFlags",       DWORD),
        ("wShowWindow",   WORD),
        ("cbReserved2",   WORD),
        ("lpReserved2",   LPBYTE),
        ("hStdInput",     HANDLE),
        ("hStdOutput",    HANDLE),
        ("hStdError",     HANDLE),
        ]

# Hier werden einzelne Informationen für die Funktionen "abgefangen"
class PROCESS_INFORMATION(Structure):
    _fields_ = [
        ("hProcess",    HANDLE),
        ("hThread",     HANDLE),
        ("dwProcessId", DWORD),
        ("dwThreadId",  DWORD),
        ]

class EXCEPTION_RECORD(Structure):
    pass
    
EXCEPTION_RECORD._fields_ = [
        ("ExceptionCode",        DWORD),
        ("ExceptionFlags",       DWORD),
        ("ExceptionRecord",      POINTER(EXCEPTION_RECORD)),
        ("ExceptionAddress",     PVOID),
        ("NumberParameters",     DWORD),
        ("ExceptionInformation", UINT_PTR * 15),
        ]

# Code für dwDebugEvent
# Ich gehe hierauf nicht weiter ein
class _EXCEPTION_RECORD(Structure):
    _fields_ = [
        ("ExceptionCode",        DWORD),
        ("ExceptionFlags",       DWORD),
        ("ExceptionRecord",      POINTER(EXCEPTION_RECORD)),
        ("ExceptionAddress",     PVOID),
        ("NumberParameters",     DWORD),
        ("ExceptionInformation", UINT_PTR * 15),
        ]

# Exceptionen werden hier abgefangen
class EXCEPTION_DEBUG_INFO(Structure):
    _fields_ = [
        ("ExceptionRecord",    EXCEPTION_RECORD),
        ("dwFirstChance",      DWORD),
        ]

# Weitere Klasse des Debugevents
# 
class DEBUG_EVENT_UNION(Union):
    _fields_ = [
        ("Exception",         EXCEPTION_DEBUG_INFO),
        ("CreateThread",      CREATE_THREAD_DEBUG_INFO),
        ("CreateProcessInfo", CREATE_PROCESS_DEBUG_INFO),
        ("ExitThread",        EXIT_THREAD_DEBUG_INFO),
        ("ExitProcess",       EXIT_PROCESS_DEBUG_INFO),
        ("LoadDll",           LOAD_DLL_DEBUG_INFO),
        ("UnloadDll",         UNLOAD_DLL_DEBUG_INFO),
        ("DebugString",       OUTPUT_DEBUG_STRING_INFO),
        ("RipInfo",           RIP_INFO),
        ]  

# Debugevent ....
class DEBUG_EVENT(Structure):
    _fields_ = [
        ("dwDebugEventCode", DWORD),
        ("dwProcessId",      DWORD),
        ("dwThreadId",       DWORD),
        ("u",                DEBUG_EVENT_UNION),
        ]

# Wird für den Programm Kontext beim debuggen verwendet
class FLOATING_SAVE_AREA(Structure):
   _fields_ = [
   
        ("ControlWord", DWORD),
        ("StatusWord", DWORD),
        ("TagWord", DWORD),
        ("ErrorOffset", DWORD),
        ("ErrorSelector", DWORD),
        ("DataOffset", DWORD),
        ("DataSelector", DWORD),
        ("RegisterArea", BYTE * 80),
        ("Cr0NpxState", DWORD),
]
 
# Klasse für die einzelnen CPU-Register.
# Die Klasse wird von GetThreadContext() genutzt.
class CONTEXT(Structure):
    _fields_ = [
    
        ("ContextFlags", DWORD),
        ("Dr0", DWORD),
        ("Dr1", DWORD),
        ("Dr2", DWORD),
        ("Dr3", DWORD),
        ("Dr6", DWORD),
        ("Dr7", DWORD),
        ("FloatSave", FLOATING_SAVE_AREA),
        ("SegGs", DWORD),
        ("SegFs", DWORD),
        ("SegEs", DWORD),
        ("SegDs", DWORD),
        ("Edi", DWORD),
        ("Esi", DWORD),
        ("Ebx", DWORD),
        ("Edx", DWORD),
        ("Ecx", DWORD),
        ("Eax", DWORD),
        ("Ebp", DWORD),
        ("Eip", DWORD),
        ("SegCs", DWORD),
        ("EFlags", DWORD),
        ("Esp", DWORD),
        ("SegSs", DWORD),
        ("ExtendedRegisters", BYTE * 512),
]

# Hier werden einige Informationen der jeweiligen Threads gespeichert
class THREADENTRY32(Structure):
    _fields_ = [
        ("dwSize",             DWORD),
        ("cntUsage",           DWORD),
        ("th32ThreadID",       DWORD),
        ("th32OwnerProcessID", DWORD),
        ("tpBasePri",          DWORD),
        ("tpDeltaPri",         DWORD),
        ("dwFlags",            DWORD),
    ]

# Variabeln für die Systemstruktur -> SYSTEM_INFO
class PROC_STRUCT(Structure):
    _fields_ = [
        ("wProcessorArchitecture",    WORD),
        ("wReserved",                 WORD),
]

# Variabeln für die Systemstruktur -> SYSTEM_INFO
class SYSTEM_INFO_UNION(Union):
    _fields_ = [
        ("dwOemId",    DWORD),
        ("sProcStruc", PROC_STRUCT),
]

# Die Klasse wird gebraucht sollte ein Program die Aufbaustruktur des PC/ CPU 
# abfragen
class SYSTEM_INFO(Structure):
    _fields_ = [
        ("uSysInfo", SYSTEM_INFO_UNION),
        ("dwPageSize", DWORD),
        ("lpMinimumApplicationAddress", LPVOID),
        ("lpMaximumApplicationAddress", LPVOID),
        ("dwActiveProcessorMask", DWORD),
        ("dwNumberOfProcessors", DWORD),
        ("dwProcessorType", DWORD),
        ("dwAllocationGranularity", DWORD),
        ("wProcessorLevel", WORD),
        ("wProcessorRevision", WORD),
]

#  MEMORY_BASIC_INFORMATION enthält einige Information von bestimmten
# Speicherbereichen
class MEMORY_BASIC_INFORMATION(Structure):
    _fields_ = [
        ("BaseAddress", PVOID),
        ("AllocationBase", PVOID),
        ("AllocationProtect", DWORD),
        ("RegionSize", SIZE_T),
        ("State", DWORD),
        ("Protect", DWORD),
        ("Type", DWORD),
]

Das war der Code um die Funktionen zu deklarieren.

Hier kommt jetzt der genutzte Code, der die genutzten Algorithmen enthält:
Code:
from ctypes import *
from my_debugger_defines import *

import sys
import time
kernel32 = windll.kernel32

class debugger():

    def __init__(self):
        self.h_process       =     None
        self.pid             =     None
        self.debugger_active =     False
        self.h_thread        =     None
        self.context         =     None
        self.breakpoints     =     {}
        self.first_breakpoint=     True
        self.hardware_breakpoints = {}
        
        # Hier wird die jeweiligen "Seitengrösse" des System abgefragt
        system_info = SYSTEM_INFO()
        kernel32.GetSystemInfo(byref(system_info))
        self.page_size = system_info.dwPageSize
        self.guarded_pages      = []
        self.memory_breakpoints = {}

    def load(self,path_to_exe):
        
        # Ohne diesen Code würde die GUI des debuggden Programms nicht   
        # angezeigt werden    
        creation_flags = DEBUG_PROCESS
    
        # Programm Variabeln
        startupinfo         = STARTUPINFO()
        process_information = PROCESS_INFORMATION()
        
    
        # Die jeweiligen Werte können verwendet werden
        # so kann man die Unterschiede des Startup bei verschiedenen
        # Variabel einträgen sehen
        startupinfo.dwFlags     = 0x1
        startupinfo.wShowWindow = 0x0
        # Die CB Klasse wird hiermit Initialisiert
        startupinfo.cb = sizeof(startupinfo)

        # CreateProcessA zum Starten von Programmen
        if kernel32.CreateProcessA(path_to_exe,
                                   None,
                                   None,
                                   None,
                                   None,
                                   creation_flags,
                                   None,
                                   None,
                                   byref(startupinfo),
                                   byref(process_information)):
            
            print "[*] We have successfully launched the process!"
            print "[*] The Process ID I have is: %d" % \
                         process_information.dwProcessId
            self.pid = process_information.dwProcessId
            self.h_process = self.open_process(self,process_information.dwProcessId)
            self.debugger_active = True
        else:    
            print "[*] Error with error code %d." % kernel32.GetLastError()

    def open_process(self,pid):
        
        # Kommentarzeichen je nach belieben entfernen :-)
        # PROCESS_ALL_ACCESS = 0x0x001F0FFF
        h_process = kernel32.OpenProcess(PROCESS_ALL_ACCESS,False,pid) 
        
        return h_process
    
    def attach(self,pid):
        
        self.h_process = self.open_process(pid)

        if kernel32.DebugActiveProcess(pid):
            self.debugger_active = True
            self.pid             = int(pid)
                                  
        else:
            print "[*] Unable to attach to the process."
            
    def run(self):
        
        # Debugging Events werden hier verwendet    
        while self.debugger_active == True:
            self.get_debug_event() 

    def get_debug_event(self):
        
        debug_event    = DEBUG_EVENT()
        continue_status = DBG_CONTINUE
        
        if kernel32.WaitForDebugEvent(byref(debug_event),100):
            # Holt bestimmte benutzte Information her
            self.h_thread          = self.open_thread(debug_event.dwThreadId)
            self.context           = self.get_thread_context(h_thread=self.h_thread)
            self.debug_event       = debug_event
            
                       
            print "Event Code: %d Thread ID: %d" % \
                (debug_event.dwDebugEventCode,debug_event.dwThreadId)
            
            if debug_event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT:
                self.exception = debug_event.u.Exception.ExceptionRecord.ExceptionCode
                self.exception_address = debug_event.u.Exception.ExceptionRecord.ExceptionAddress
                
                # Wird benutzt um bestimmt Exceptionen aufzugreifen
                if self.exception == EXCEPTION_ACCESS_VIOLATION:
                    print "Access Violation Detected."
                elif self.exception == EXCEPTION_BREAKPOINT:
                    continue_status = self.exception_handler_breakpoint()
                elif self.exception == EXCEPTION_GUARD_PAGE:
                    print "Guard Page Access Detected."
                elif self.exception == EXCEPTION_SINGLE_STEP:
                    self.exception_handler_single_step()
                
            kernel32.ContinueDebugEvent(debug_event.dwProcessId, debug_event.dwThreadId, continue_status)

    # Code erklärt sich hier von selbst
    # Beim Beenden wird detach verwendet
    def detach(self):
        
        if kernel32.DebugActiveProcessStop(self.pid):
            print "[*] Finished debugging. Exiting..."
            return True
        else:
            print "There was an error"
            return False
    
    # Öffnen eines Threads
    def open_thread (self, thread_id):
        
        h_thread = kernel32.OpenThread(THREAD_ALL_ACCESS, None, thread_id)
        
        if h_thread is not None:
            return h_thread
        else:
            print "[*] Could not obtain a valid thread handle."
            return False

    def enumerate_threads(self):
              
        thread_entry     = THREADENTRY32()
        thread_list      = []
        snapshot         = kernel32.CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, self.pid)
        
        if snapshot is not None:
        
            
            # Grösse muss hier (im Programmablauf) definiert werden
            thread_entry.dwSize = sizeof(thread_entry)

            success = kernel32.Thread32First(snapshot, byref(thread_entry))

            while success:
                if thread_entry.th32OwnerProcessID == self.pid:
                    thread_list.append(thread_entry.th32ThreadID)
    
                success = kernel32.Thread32Next(snapshot, byref(thread_entry))
            
            # No need to explain this call, it closes handles
            # so that we don't leak them.
            kernel32.CloseHandle(snapshot)
            return thread_list
        else:
            return False

    def get_thread_context (self, thread_id=None,h_thread=None):
        
        context = CONTEXT()
        context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS
        
        # Enthält den Programhandler
        if h_thread is None:
            self.h_thread = self.open_thread(thread_id)
                        
        if kernel32.GetThreadContext(self.h_thread, byref(context)):
            
            return context 
        else:
            return False

    def read_process_memory(self,address,length):
        
        data         = ""
        read_buf     = create_string_buffer(length)
        count        = c_ulong(0)
        
        
        kernel32.ReadProcessMemory(self.h_process, address, read_buf, 5, byref(count))
        data    = read_buf.raw
        
        return data
    
    
    def write_process_memory(self,address,data):
        
        count  = c_ulong(0)
        length = len(data)
        
        c_data = c_char_p(data[count.value:])

        if not kernel32.WriteProcessMemory(self.h_process, address, c_data, length, byref(count)):
            return False
        else:
            return True
    
    def bp_set(self,address):
        print "[*] Setting breakpoint at: 0x%08x" % address
        if not self.breakpoints.has_key(address):

            # Original Wert wird behalten
            old_protect = c_ulong(0)
            kernel32.VirtualProtectEx(self.h_process, address, 1, PAGE_EXECUTE_READWRITE, byref(old_protect))
            
            original_byte = self.read_process_memory(address, 1)
            if original_byte != False:
                
                # Interupt Code wird hier behalten
                if self.write_process_memory(address, "\xCC"):
                    
                    # Breakpoint wird wird aufgenommen
                    self.breakpoints[address] = (original_byte)
                    return True
            else:
                return False

    def exception_handler_breakpoint(self):
        print "[*] Exception address: 0x%08x" % self.exception_address
        # Zeigt ob das UNSER Breakpoint ist
        if not self.breakpoints.has_key(self.exception_address):
           
                if self.first_breakpoint == True:
                   self.first_breakpoint = False
                   print "[*] Hit the first breakpoint."
                   return DBG_CONTINUE
               
        else:
            print "[*] Hit user defined breakpoint."
            # Handle für den breakpoint
            self.write_process_memory(self.exception_address, self.breakpoints[self.exception_address])

            self.context = self.get_thread_context(h_thread=self.h_thread)
            self.context.Eip -= 1
            
            kernel32.SetThreadContext(self.h_thread,byref(self.context))
            
            continue_status = DBG_CONTINUE


        return continue_status

    def func_resolve(self,dll,function):
        
        handle  = kernel32.GetModuleHandleA(dll)
        address = kernel32.GetProcAddress(handle, function)
        
        kernel32.CloseHandle(handle)

        return address
    
    def bp_set_hw(self, address, length, condition):
        
        # Überprüft ob ein falscher Wert da ist
        if length not in (1, 2, 4):
            return False
        else:
            length -= 1
            
        # Checkt auf Falsche Bedingungen
        if condition not in (HW_ACCESS, HW_EXECUTE, HW_WRITE):
            return False
        
        if not self.hardware_breakpoints.has_key(0):
            available = 0
        elif not self.hardware_breakpoints.has_key(1):
            available = 1
        elif not self.hardware_breakpoints.has_key(2):
            available = 2
        elif not self.hardware_breakpoints.has_key(3):
            available = 3
        else:
            return False

        # Register werden beibehalten
        for thread_id in self.enumerate_threads():
            context = self.get_thread_context(thread_id=thread_id)

            # Breakpoint wird aufgenommen
            context.Dr7 |= 1 << (available * 2)

            
            # Adresse des Breakpoints wird gespeichert
            if   available == 0: context.Dr0 = address
            elif available == 1: context.Dr1 = address
            elif available == 2: context.Dr2 = address
            elif available == 3: context.Dr3 = address

            # Breakpoint Bedingung wird hier gespeichert
            context.Dr7 |= condition << ((available * 4) + 16)

            # Wert/Länge wird gesetzt
            context.Dr7 |= length << ((available * 4) + 18)

            h_thread = self.open_thread(thread_id)
            kernel32.SetThreadContext(h_thread,byref(context))

        # Hardwarebreakpoint wird hier gesetzt
        self.hardware_breakpoints[available] = (address,length,condition)

        return True
###################
    def exception_handler_single_step(self):
        print "[*] Exception address: 0x%08x" % self.exception_address
        if self.context.Dr6 & 0x1 and self.hardware_breakpoints.has_key(0):
            slot = 0

        elif self.context.Dr6 & 0x2 and self.hardware_breakpoints.has_key(1):
            slot = 0
        elif self.context.Dr6 & 0x4 and self.hardware_breakpoints.has_key(2):
            slot = 0
        elif self.context.Dr6 & 0x8 and self.hardware_breakpoints.has_key(3):
            slot = 0
        else:
            # Kein INT1!
            continue_status = DBG_EXCEPTION_NOT_HANDLED

        # Breakpoint wird gelöscht
        if self.bp_del_hw(slot):
            continue_status = DBG_CONTINUE

        print "[*] Hardware breakpoint removed."
        return continue_status
    
    def bp_del_hw(self,slot):
        
        # Alle Breakpoints werden deaktiviert
        for thread_id in self.enumerate_threads():

            context = self.get_thread_context(thread_id=thread_id)
            
           
            context.Dr7 &= ~(1 << (slot * 2))

            # Adressen werden auf 0 gesetzt
            if   slot == 0: 
                context.Dr0 = 0x00000000
            elif slot == 1: 
                context.Dr1 = 0x00000000
            elif slot == 2: 
                context.Dr2 = 0x00000000
            elif slot == 3: 
                context.Dr3 = 0x00000000

            # Bedingungen werden gelöscht
            context.Dr7 &= ~(3 << ((slot * 4) + 16))

           
            context.Dr7 &= ~(3 << ((slot * 4) + 18))

            # Context wird "reseted"
            h_thread = self.open_thread(thread_id)
            kernel32.SetThreadContext(h_thread,byref(context))
            
        # Breakpoint wird von der Listegelöscht
        del self.hardware_breakpoints[slot]

        return True

    def bp_set_mem (self, address, size):
        
        mbi = MEMORY_BASIC_INFORMATION()
        
        # Adresse der Speicherseite
        if kernel32.VirtualQueryEx(self.h_process, address, byref(mbi), sizeof(mbi)) < sizeof(mbi):
            return False

    
        current_page = mbi.BaseAddress
    
        # Rechte für die Breakpoints
        while current_page <= address + size:
        
            # Seiteninformation wird ans OS geschickt
            self.guarded_pages.append(current_page)
            
            old_protection = c_ulong(0)
            if not kernel32.VirtualProtectEx(self.h_process, current_page, size, mbi.Protect | PAGE_GUARD, byref(old_protection)):
                return False
         

            # Verkleinert die Grösse des Speichers
            current_page += self.page_size
    
        # Speicher Breakpoints werden gelöscht
        self.memory_breakpoints[address] = (address, size, mbi)
    
        return True

Nun ich hoffen dieses Tutorial beschreibt genau den Text und die Schritte die gemacht werden müssen um einen Debugger zuprogrammieren.
Im Anhang findet ihr die fertigen Codes.

Bitte lasst ein Kommentar da, dieses Tut ist meine erste grössere Anleitung fürs Web.
http://www.hackerboard.de/images/smilies2/tongue.gif
http://www.hackerboard.de/images/smilies2/smilie.gif


LaVolpe
 
Drei kleine Anmerkungen:
-Shared Objects haben unter Linux meist die Endung .so oder .so.Nummer (z.B. glib.so.0)
-Das Modul mit den Definitionen nennst du dbg_def, importierst dann aber aus my_debugger_defines ;)
-from... import * ist böööööse :D, aber hier wohl angebracht... zumindest für die Debugging-Definitionen...
 
Ich bedanke mich für dein "Comment", bitte bewertet diesen Post :D

Und nun sehe ich den Fehler, ja das sollte eigentlich "from dbg_def *" heißen, aber den Fehler habe ich in den anderen Scripts nicht gemacht da diese Arbeiten :) (im Anhang, ist keine Warez ihr könnt es downloaden :D)
 
Zuletzt bearbeitet:
Copy&Pasta mit eigenen Kommentaren

Ich finde es ja ganz toll, wenn sich jemand die Mühe macht und für andere Tutorials macht. Allerdings gebe doch bitte deine Quelle an.
Der von dir angegebene Code stammt zu großen(wenn nicht fast alles bis auf wenige Änderungen) Stücken aus "Hacking mit Python" von Justin Seitz. Du hast die Kommentare rausgenommen und/oder übersetzt.
Deine eigene Leistung ist also nur bedingt erkennbar, wenn sie überhaupt vorhanden ist. Verkaufen tust es aber als dein Tutorial....

Ich weiß, dass das unfreundlich klingt, aber mich regt eine solche unattributierte Verwendung fremder Materialen vor allem zu Zeiten Guttenbergs auf.


EDIT: Es ist einfach lächerlich. Ich habe "deine" Quelltexte mit dem aus dem Buch gedifft. Es ist praktisch identisch. Funktionsnamen, Variablen, die print-Statements..... Es ist einfach dreist.

Ein wunderbares Wochenende.
 
Zuletzt bearbeitet:
*Der von dir angegebene Code stammt zu großen(wenn nicht fast alles bis auf wenige Änderungen) Stücken aus "Hacking mit Python" von Justin Seitz*

Nun ja, ich der Quellcode ist ähnlich, ich habe aber einige Klassen optimiert damit sie auch auf Win7 laufen. Außerdem er ist ähnlich ,weil die Funktionen in der WINAPI gleich geblieben sind . Wie willst du für verschiedene Funktionen falsche Werte übergeben ,wenn es dann noch laufen soll? Egal wie du es drehst, wenn es dann noch laufen soll wird der Quellcode ähnlich sein.

Ich habe auch versucht mich einiger Maßen an das Muster zu halten, da es eine Art "Musterbeispiel" ist. Ich habe ,wie schon gesagt, aber den Code verändert und optimiert. Nur die Ausgaben ,wie "Error" oder so etwas ist gleich :)

Ich werde bald auch ein Tutorial für einen Debugger unter C++ schreiben, du wirst bemerken das die da trotzdem ähnlich sind.
 
Zuletzt bearbeitet:
Nein, hast du nicht. Bis auf die Kommentare(und die sind auch maximal nur die übersetzten) ist der Code nicht von dir. Weder programmiert noch optimiert.
Du hast ein paar Defines rausgenommen. Ich habe keine Lust hier die Diffs zu posten.
Wer mag kann sich von hier die originalen Source besorgen
Gray Hat Python | No Starch Press
(Verlagsseite: auf .src klicken.) und sich selbst überzeugen.

Der Quelltext ist nicht ähnlich, sondern identisch. Statt aber wildes Copy&Pasta zuzugeben, fängst du jetzt an zu argumentieren? Glaube mir mal, dass ich ein Diff-Tool benutzen kann und Unterschiede sehe. Funktionsnamen, Variablennamen und sogar Leerzeilen sind identisch....
Natürlich kann der Quelltext bei gleicher Funktionalität ähnlich sein, aber so sehr? Reichlich unwahrscheinlich Selbst der Code für die print-Ausgaben ist gleich.

Es handelt sich natürlich um Beispiel aus einem Buch, aber das heißt nicht, dass es frei ist(Zugegeben, ich weiß nicht wie es lizenziert ist...).
Worst-Case ist hier die Urheberrechtsverletzung, da die Programme nicht frei sind und ohne Attributierung nicht veröffentlich werden dürfen.

Regards,

EDIT: For the lulz habe ich mal die beiden patches angehängt. Bis auf Kommentare entfernen und Leerzeilen löschen identisch. QED.
 
Zuletzt bearbeitet:
Weil ich es nicht glauben konnte habe ich es selber durch kdiff3 durchgejagt. Resultat: in dem zweiten Listing sind die einzigen Änderungen andere Kommentare bzw. Abstände der Codeblöcke. Mit Quellenangabe wäre es ein nettes Tutorial gewesen, aber dann auch noch stur zu behaupten es wäre die eigene geistige Leistung? Nope, so etwas macht man nicht.

mfg benediktibk

PS: Du hast vergessen einen Kommentar zu übersetzen:
Code:
            # No need to explain this call, it closes handles
            # so that we don't leak them.
1:1 aus dem Original übernommen, oder hast du wirklich selber exakt den gleichen Kommentar verfasst? ... ich zweifle :rolleyes:
 
Ich finde es schön das jemand sich die Mühe gemacht hat leider falsch zitiert :) .

Was noch zu bemängel gäbe wäre, dass dies lediglich ein Eventdebugger ist. Opcode gibt's dort keinen ^^
Ich glaube ich muss mal eines schreiben das opcode's ausspuckt :p

Gruß Techie
 
Zuletzt bearbeitet:
Zurück
Oben