Fix handle_exit_process + detach in Debugger to prevent keeping ref on process + fix pe_parse IATHook: all test pass

This commit is contained in:
hakril
2016-11-03 23:17:24 +01:00
committed by Clement Rouault
parent 8653c4c1e4
commit d2b801cada
3 changed files with 21 additions and 37 deletions
+14 -31
View File
@@ -56,7 +56,7 @@ class Debugger(object):
self.breakpoints = {}
self._pending_breakpoints = {} #Breakpoints to put in new process / threads
# Values rewritten by "\xcc"
self._memory_save = defaultdict(dict)
self._memory_save = dict()
# Dict of {tid : {drx taken : BP}}
self._hardware_breakpoint = {}
# Breakpoints to reput..
@@ -97,6 +97,7 @@ class Debugger(object):
return
for proc in targets:
self.detach(proc)
del targets
return
if not isinstance(target, WinProcess):
raise ValueError("Detach accept only WinProcess")
@@ -125,20 +126,22 @@ class Debugger(object):
thread.set_context(ctx)
del self.processes[target.pid]
del self._watched_pages[target.pid]
del self._module_by_process[target.pid]
if target is self.current_process:
self._finish_debug_event(self.REMOVE_ME_debug_event, DBG_CONTINUE)
self.current_process = None
self.current_thread = None
if target is self.target:
if target.pid == self.target.pid:
self.target = None
print("Detach from {0}".format(target.pid))
windows.winproxy.DebugActiveProcessStop(target.pid)
def _killed_in_action(self):
"""Return ``True`` if current process have been detached by user callback"""
# Fix ? _handle_exit_process remove from processes but need a FinishDebugEvent
return self.current_process.pid not in self.processes
return self.current_process is None or self.current_process.pid not in self.processes
@classmethod
def debug(cls, path, args=None, dwCreationFlags=0, show_windows=False):
@@ -469,6 +472,7 @@ class Debugger(object):
thread.set_syswow_context(ctx)
else:
thread.set_context(ctx)
del thread
continue_flag = self._dispatch_breakpoint(exception, excp_addr)
if self._killed_in_action():
return continue_flag
@@ -647,6 +651,7 @@ class Debugger(object):
self.processes[self.current_process.pid] = self.current_process
self._watched_pages[self.current_process.pid] = {} #defaultdict(list)
self.breakpoints[self.current_process.pid] = {}
self._memory_save[self.current_process.pid] = {}
self._module_by_process[self.current_process.pid] = {}
self._update_debugger_state(debug_event)
self._setup_pending_breakpoints_new_process(self.current_process)
@@ -658,8 +663,6 @@ class Debugger(object):
def _handle_exit_process(self, debug_event):
"""Handle EXIT_PROCESS_DEBUG_EVENT"""
self._update_debugger_state(debug_event)
print("Exit process !!!")
#import pdb;pdb.set_trace()
exit_process = debug_event.u.ExitProcess
retvalue = self.on_exit_process(exit_process)
del self.threads[self.current_thread.tid]
@@ -668,36 +671,16 @@ class Debugger(object):
del self._breakpoint_to_reput[self.current_thread.tid]
del self.processes[self.current_process.pid]
del self._watched_pages[self.current_process.pid]
del self._memory_save[self.current_process.pid]
del self._module_by_process[self.current_process.pid]
# GC EXPLORATION CODE
import gc
over = gc.get_referrers
under = gc.get_referents
####
cpid = self.current_process.pid
del self.current_thread
## This should trigger DEL of the self.current_process
#print("self.current_process WILL BE DELETED")
del self.current_process
#print("self.current_process DELETED")
self.current_thread = None
self.current_process = None
if cpid == self.target.pid:
#del self.target
print("DEL TARGET")
del self.target
#import pdb;pdb.set_trace()
self.target = None
# This is like.. the WORST PATCH EVER
# I'am going to sleep so here the problem for when it will time to fix this:
# The PEFile class is a mess: too much cell arround target
# This means that destroying them is not enought to __del__ the target (dbg.current_process)
# So the dbg.current_process is still alive, so handle is also still alive..
# For now we need to force gc.collect
# This will need a rewrite of GetPEFile...
import gc; gc.collect()
return retvalue
def _handle_create_thread(self, debug_event):
+4 -3
View File
@@ -475,13 +475,14 @@ class IATEntry(ctypes.Structure):
@classmethod
def create(cls, addr, ord, name, transformers):
def create(cls, addr, ord, name, target, transformers):
self = transformers.create_structure_at(cls, addr)
self.addr = addr
self.ord = ord
self.name = name
self.hook = None
self.nonhookvalue = self.value
self.target = target
return self
def __repr__(self):
@@ -503,7 +504,7 @@ class IATEntry(ctypes.Structure):
This works only for PEFile with the current process as target.
"""
if target is not None:
if self.target is not None:
raise NotImplementedError("Setting hook in remote process (use python code injection)")
hook = hooks.IATHook(self, callback, types)
@@ -547,7 +548,7 @@ class IMAGE_IMPORT_DESCRIPTOR(IMAGE_IMPORT_DESCRIPTOR): # TODO: use explicite na
iat_entry = self.transformers.create_structure_at(THUNK_DATA, iat_addr)
res = []
while iat_entry.Ordinal:
res.append(IATEntry.create(iat_addr, -1, "??", self.transformers))
res.append(IATEntry.create(iat_addr, -1, "??", self.target, self.transformers))
iat_addr += ctypes.sizeof(type(iat_entry))
iat_entry = self.transformers.create_structure_at(THUNK_DATA, iat_addr)
return res
+3 -3
View File
@@ -27,9 +27,9 @@ if windows.system.version[0] < 10:
test_binary_name = "calc.exe"
else:
test_binary_name = "cmd.exe"
test_binary_name = "notepad.exe"
DEFAULT_CREATION_FLAGS = CREATE_NEW_CONSOLE
#DEFAULT_CREATION_FLAGS = 0
if is_windows_32_bits:
def pop_calc_32(dwCreationFlags=DEFAULT_CREATION_FLAGS):
@@ -51,7 +51,7 @@ else:
@contextmanager
def Calc64(dwCreationFlags=0, exit_code=0):
def Calc64(dwCreationFlags=DEFAULT_CREATION_FLAGS, exit_code=0):
try:
calc = pop_calc_64(dwCreationFlags)
yield calc
@@ -63,7 +63,7 @@ def Calc64(dwCreationFlags=0, exit_code=0):
calc.exit(exit_code)
@contextmanager
def Calc32(dwCreationFlags=0, exit_code=0):
def Calc32(dwCreationFlags=DEFAULT_CREATION_FLAGS, exit_code=0):
try:
calc = pop_calc_32(dwCreationFlags)
yield calc