Jag har haft de bästa upplevelserna med PaiMei, eller särskilt PyDbg för dessa ändamål. Boken "Grayhat Python" väckte den till min uppmärksamhet och jag bestämde mig för att prova.
Skriptet
Här är ett något generiskt skelett jag har använt i min dynamiska analys ( dynamisk analys). Jag har justerat det så att det kommer att koppla Unicode-versionen av den funktion du är intresserad av att koppla till.
Svaret kanske inte är perfekt, eftersom du kan uppnå ett villkorligt brott, men du måste för att lägga till den interaktiva felsökningsdelen i skriptet. Om du ville vreak istället för att fortsätta, måste du be felsökaren att göra just det genom att ändra raden returnera DBG_CONTINUE
.
importera sysimport ctypesimport tracebacktry: från pydbg import * från pydbg.definerar import * från verktyg importera hookingexcept: skriv "FEL: du behöver pydbg och utils.hooking från PAIMEI." sys.exit (-1) reg = Noneclass reg_pydbg (pydbg): @staticmethod def __getlen (mbi, address): # Vad är det maximala antalet byte vi kan läsa? _maxlen = 64 * 1024 absmaxlen = (mbi.BaseAddress + mbi.RegionSize) - adress om absmaxlen > _maxlen: return _maxlen return absmaxlen def rootkey_const (self, key): if 0x80000000 == key: return "HKCR" elif 0x8000000 : returnera "HKCU" elif 0x80000002 == nyckel: returnera "HKLM" elif 0x80000003 == nyckel: returnera "HKU" elif 0x80000004 == nyckel: returnera "HKEY_PERFORMANCE_DATA" elif 0x80000050 == tangent: returnera "HKEY_PERFORMANCE_TEXT60 = key = elif 0x : returnera "HKEY_PERFORMANCE_NLSTEXT" elif 0x80000005 == nyckel: returnera "HKEY_CURRENT_CONFIG" elif 0x80000006 == nyckel: returnera "HKEY_DYN_DATA" elif 0x80000007 == nyckel: returnera "HKEY_CURRENT_USER_LOC
returnera "0x% 08X"% (key) def readmem (self, address, len = 0): try: mbi = self.virtual_query (address) utom: return None, "% 08X <invalid ptr>"% (address) if mbi. Skydda & PAGE_GUARD: # inget sätt att visa innehållet på en skyddssida returnerar inget, "% 08X <guard page>"% (adress) om 0 == len: # försök att göra en bra gissning då len = själv .__ getlen (mbi, adress ) try: explored = self.read_process_memory (address, len) utom: return None, "% 08X <ReadProcessMemory failed>"% (address) return explored, None def readstring (self, address, unicodeHint = False, returnNone = False): om 0 == adress: om returnNone: return None return "<nullptr>" utforskad, retval = self.readmem (adress) om den inte undersöktes: om returnNone: retur Ingen retur retval explored_string = Ingen om inte unicodeHint: explored_string = self.get_ascii_string (utforskad) om inte explored_string: explored_string = self.get_unicode_string (utforskad) om inte explored_string: explored_string = self.get_printable_string (explored) return explored_string , ret): keyname = dbg.readstring (args [1], True) print "RegOpenKeyExW (% s,% s, ...) ->% s (% d)"% (dbg.rootkey_const (args [0] ), keyname, ctypes.FormatError (ret), ret) return DBG_CONTINUEclass reghooks: fct2hook = {"advapi32.dll": {"RegOpenKeyExW": {"args": 5, "entry": None, "exit": exit_RegOpenKeyExW} ,},} hooked = {} hookcont = None dbg = None def __init__ (self, dbg): self.hookcont = hooking.hook_container () self.hooked = {} self.dbg = dbg
dbg.set_callback (LOAD_DLL_DEBUG_EVENT, self.handler_loadDLL) def hookByDLL (self, dll): om inte dll.name.lower () i self.hooked: för nyckel, värde i self.fct2hook.items (): om key.lower ( ) == dll.name.lower (): self.hooked [dll.name.lower ()] = 1 tryck "% s vid% 08x"% (dll.name, dll.base) för funk, fctprops i värde. objekt (): post = Ingen; exit = Ingen; args = 0 om "entry" i fctprops och None! = fctprops ["entry"]: skriv ut "\ tentry hook" + func entry = fctprops ["entry"] om "exit" i fctprops och None! = fctprops ["exit "]: skriv ut" \ texit hook "+ func exit = fctprops [" exit "] om" args "i fctprops och None! = fctprops [" args "]: args = fctprops [" args "] om None! = post eller Ingen! = Exit: funcaddr = self.dbg.func_resolve (dll.name, func) self.hookcont.add (self.dbg, funcaddr, args, entry, exit) else: self.hooked [dll.name.lower () ] + = 1 retur @staticmethod def handler_loadDLL (dbg): global reg dbg.hide_debugger () last_dll = dbg.get_system_dll (-1) reg.hookByDLL (last_dll) return DBG_CONTINUEdef main (): dbg = reg_pydbg () dbg.load ("C: \\ Windows \\ regedit.exe") global reg reg = reghooks (dbg) dbg.run () if __name__ == "__main__": main ()
Exempel på utdata
>C: \ Python26 \ python.exe hookreg.pyadvapi32.dll vid 75840000 exit hook RegOpenKeyExWRegOpenKeyExW (HKCU, Software \ Microsoft \ Windows \ CurrentVersion \ Applets \ Regedit , ...) -> Åtgärden slutfördes. (0)
RegOpenKeyExW (HKLM, SOFTWARE \ Microsoft \ Windows NT \ CurrentVersion \ FontLink \ SystemLink, ...) -> Åtgärden har slutförts. (0) RegOpenKeyExW (HKLM, SOFTWARE \ Microsoft \ Windows NT \ CurrentVersion \ LanguagePack \ DataStore_V1.0, ...) -> Åtgärden slutfördes. (0) RegOpenKeyExW (HKLM, SOFTWARE \ Microsoft \ Windows NT \ CurrentVersion \ LanguagePack \ SurrogateFallback, ...) -> Åtgärden har slutförts. (0)
Förklaring
De viktiga delarna är:
"RegOpenKeyExW": {"args": 5, "entry ": Ingen," exit ": exit_RegOpenKeyExW},
och funktionen exit_RegOpenKeyExW
. Du kan också ändra ovanstående för att bara koppla vid inmatning RegOpenKeyExW istället för vid utgång eller för att göra båda. Beror på vad du vill uppnå.
Jag har använt den här metoden för att avkoda buffertar ( SCSI_PASS_THROUGH_DIRECT och SCSI_PASS_THROUGH ) skickas via DeviceIoControl kod>, så ovanstående är överlägset inte det mest komplexa du kan göra.
På en annan anteckning har jag också anslutit saker som att öppna filer (eller registernycklar) och hållit listor över de returnerade handtagen längs med strängformen av vad de är. På det här sättet kunde jag implementera ganska komplexa mänskligt läsbara loggningsscenarier.
Motiv
Anledningen till att saker som den kapslade ordboken finns är så att den lätt kan utökas för att koppla in vilken funktion som helst DLL, tack. Naturligtvis kan det också vara hårdkodat, men jag har haft scenarier där jag kopplade in dussintals funktioner.