@@ -321,7 +321,8 @@ def __init__(self, minidump_file, *, trace=False, quiet=False, thread_id=None, d
321321 self .handles = HandleManager ()
322322 self ._setup_handles ()
323323 self ._setup_registry ()
324- self .kill_me = None
324+ self .stopped = False
325+ self .kill_exception = None
325326 self .exit_code = None
326327 self .exports = self ._all_exports ()
327328 self ._exception = UnicornExceptionInfo ()
@@ -943,6 +944,8 @@ def handle_exception(self):
943944
944945 if self ._exception_hook is not None :
945946 hook_result = self ._exception_hook (self ._exception )
947+ if self .stopped :
948+ return None
946949 if hook_result is not None :
947950 # Clear the pending exception
948951 self ._last_exception = self ._exception
@@ -1073,12 +1076,16 @@ def write_stack(cur_ptr: int, data: bytes):
10731076 return self .KiUserExceptionDispatcher
10741077
10751078 def start (self , begin , end = 0xffffffffffffffff , count = 0 ) -> None :
1079+ # Clear stop state
1080+ self .stopped = False
1081+ self .kill_exception = None
1082+ self .exit_code = None
10761083 # Clear exceptions before starting
10771084 self ._exception = UnicornExceptionInfo ()
10781085 emu_begin = begin
10791086 emu_until = end
10801087 emu_count = count
1081- while True :
1088+ while not self . stopped :
10821089 try :
10831090 if self ._exception .type != ExceptionType .NoException :
10841091 if self ._exception .final :
@@ -1093,6 +1100,8 @@ def start(self, begin, end=0xffffffffffffffff, count=0) -> None:
10931100
10941101 try :
10951102 emu_begin = self .handle_exception ()
1103+ if self .stopped :
1104+ break
10961105 except Exception :
10971106 traceback .print_exc ()
10981107 self .error (f"exception during exception handling (stack overflow?)" )
@@ -1117,15 +1126,14 @@ def start(self, begin, end=0xffffffffffffffff, count=0) -> None:
11171126 emu_count = self ._exception .tb_icount + 1
11181127
11191128 self .info (f"emu_start({ hex (emu_begin )} , { hex (emu_until )} , { emu_count } )" )
1120- self .kill_me = None
11211129 self ._uc .emu_start (emu_begin , until = emu_until , count = emu_count )
11221130 self .info (f'emulation finished, cip = { hex (self .regs .cip )} ' )
11231131 if self .exit_code is not None :
11241132 self .info (f"exit code: { hex (self .exit_code )} " )
11251133 break
11261134 except UcError as err :
1127- if self .kill_me is not None and type (self .kill_me ) is not UcError :
1128- raise self .kill_me
1135+ if self .kill_exception is not None and type (self .kill_exception ) is not UcError :
1136+ raise self .kill_exception from None
11291137 if self ._exception .type != ExceptionType .NoException :
11301138 # Handle the exception outside of the except handler
11311139 continue
@@ -1142,17 +1150,17 @@ def stop(self, exit_code=None) -> None:
11421150 except Exception :
11431151 traceback .print_exc ()
11441152 self .error ("Invalid type passed to exit_code!" )
1153+ self .stopped = True
11451154 self ._uc .emu_stop ()
11461155
11471156 def raise_kill (self , exc = None ):
11481157 # HACK: You need to use this to exit from hooks (although it might not always work)
11491158 self .regs .cip = FORCE_KILL_ADDR
1150- self .kill_me = exc
1151- if exc is not None :
1152- return exc
1153- else :
1154- self .kill_me = True
1155- self ._uc .emu_stop ()
1159+ self .stop ()
1160+ if exc is None :
1161+ exc = Exception ()
1162+ self .kill_exception = exc
1163+ return exc
11561164
11571165 def NtCurrentProcess (self ):
11581166 return 0xFFFFFFFFFFFFFFFF if self ._x64 else 0xFFFFFFFF
@@ -1292,12 +1300,12 @@ def _hook_code_exception(uc: Uc, address, size, dp: Dumpulator):
12921300
12931301def _hook_mem (uc : Uc , access , address , size , value , dp : Dumpulator ):
12941302 if dp ._pages .handle_lazy_page (address , min (size , PAGE_SIZE )):
1295- dp .debug (f"committed lazy page { hex (address )} [{ hex (size )} ]" )
1303+ dp .debug (f"committed lazy page { hex (address )} [{ hex (size )} ] (cip: { hex ( dp . regs . cip ) } ) " )
12961304 return True
12971305
12981306 fetch_accesses = [UC_MEM_FETCH , UC_MEM_FETCH_PROT , UC_MEM_FETCH_UNMAPPED ]
1299- if access == UC_MEM_FETCH_UNMAPPED and FORCE_KILL_ADDR - 0x10 <= address <= FORCE_KILL_ADDR + 0x10 and dp . kill_me is not None :
1300- dp .error (f"forced exit memory operation { access } of { hex (address )} [{ hex (size )} ] = { hex ( value ) } " )
1307+ if dp . stopped and access == UC_MEM_FETCH_UNMAPPED and FORCE_KILL_ADDR - 0x10 <= address <= FORCE_KILL_ADDR + 0x10 :
1308+ dp .error (f"force exit fetch of { hex (address )} [{ hex (size )} ]" )
13011309 return False
13021310 if dp ._exception .final and access in fetch_accesses :
13031311 dp .info (f"fetch from { hex (address )} [{ size } ] already reported" )
@@ -1368,7 +1376,7 @@ def _hook_mem(uc: Uc, access, address, size, value, dp: Dumpulator):
13681376 dp ._exception .final = True
13691377
13701378 # Stop emulation (we resume it on KiUserExceptionDispatcher later)
1371- dp .stop ()
1379+ dp ._uc . emu_stop ()
13721380 return False
13731381
13741382 # There should not be an exception active
@@ -1387,7 +1395,7 @@ def _hook_mem(uc: Uc, access, address, size, value, dp: Dumpulator):
13871395 dp ._exception = exception
13881396
13891397 # Stop emulation (we resume execution later)
1390- dp .stop ()
1398+ dp ._uc . emu_stop ()
13911399 return False
13921400 except AssertionError as err :
13931401 traceback .print_exc ()
@@ -1421,50 +1429,53 @@ def _get_regs(instr, include_write=False):
14211429 return regs
14221430
14231431def _hook_code (uc : Uc , address , size , dp : Dumpulator ):
1424- code = b""
14251432 try :
1426- code = dp .read (address , min (size , 15 ))
1427- instr = next (dp .cs .disasm (code , address , 1 ))
1428- except StopIteration :
1429- instr = None # Unsupported instruction
1430- except IndexError :
1431- instr = None # Likely invalid memory
1432-
1433- address_name = dp .exports .get (address , "" )
1433+ code = b""
1434+ try :
1435+ code = dp .read (address , min (size , 15 ))
1436+ instr = next (dp .cs .disasm (code , address , 1 ))
1437+ except StopIteration :
1438+ instr = None # Unsupported instruction
1439+ except IndexError :
1440+ instr = None # Likely invalid memory
1441+ address_name = dp .exports .get (address , "" )
14341442
1435- module = ""
1436- if dp .last_module and address in dp .last_module :
1437- # same module again
1438- pass
1439- else :
1440- # new module
1441- dp .last_module = dp .modules .find (address )
1442- if dp .last_module :
1443- module = dp .last_module .name
1444-
1445- if address_name :
1446- address_name = " " + address_name
1447- elif module :
1448- address_name = " " + module
1449-
1450- line = f"{ hex (address )} { address_name } |"
1451- if instr is not None :
1452- line += instr .mnemonic
1453- if instr .op_str :
1454- line += " "
1455- line += instr .op_str
1456- for reg in _get_regs (instr ):
1457- line += f"|{ reg } ={ hex (dp .regs .__getattr__ (reg ))} "
1458- if instr .mnemonic == "call" :
1459- # print return address
1460- ret_address = address + instr .size
1461- line += f"|return_address={ hex (ret_address )} "
1462- if instr .mnemonic in {"syscall" , "sysenter" }:
1463- line += f"|sequence_id=[{ dp .sequence_id } ]"
1464- else :
1465- line += f"??? (code: { code .hex ()} , size: { hex (size )} )"
1466- line += "\n "
1467- dp .trace .write (line )
1443+ module = ""
1444+ if dp .last_module and address in dp .last_module :
1445+ # same module again
1446+ pass
1447+ else :
1448+ # new module
1449+ dp .last_module = dp .modules .find (address )
1450+ if dp .last_module :
1451+ module = dp .last_module .name
1452+
1453+ if address_name :
1454+ address_name = " " + address_name
1455+ elif module :
1456+ address_name = " " + module
1457+
1458+ line = f"{ hex (address )} { address_name } |"
1459+ if instr is not None :
1460+ line += instr .mnemonic
1461+ if instr .op_str :
1462+ line += " "
1463+ line += instr .op_str
1464+ for reg in _get_regs (instr ):
1465+ line += f"|{ reg } ={ hex (dp .regs .__getattr__ (reg ))} "
1466+ if instr .mnemonic == "call" :
1467+ # print return address
1468+ ret_address = address + instr .size
1469+ line += f"|return_address={ hex (ret_address )} "
1470+ elif instr .mnemonic in {"syscall" , "sysenter" }:
1471+ line += f"|sequence_id=[{ dp .sequence_id } ]"
1472+ else :
1473+ line += f"??? (code: { code .hex ()} , size: { hex (size )} )"
1474+ line += "\n "
1475+ dp .trace .write (line )
1476+ except (KeyboardInterrupt , SystemExit ) as e :
1477+ dp .stop ()
1478+ raise e
14681479
14691480def _unicode_string_to_string (dp : Dumpulator , arg : P [UNICODE_STRING ]):
14701481 try :
@@ -1627,7 +1638,7 @@ def syscall_arg(index):
16271638 if isinstance (status , ExceptionInfo ):
16281639 print ("context switch, stopping emulation" )
16291640 dp ._exception = status
1630- raise dp . raise_kill ( UcError (UC_ERR_EXCEPTION )) from None
1641+ raise UcError (UC_ERR_EXCEPTION )
16311642 else :
16321643 dp .info (f"status = { hex (status )} " )
16331644 dp .regs .cax = status
@@ -1669,7 +1680,7 @@ def _hook_invalid(uc: Uc, dp: Dumpulator):
16691680 if dp .trace :
16701681 dp .trace .flush ()
16711682 # HACK: unicorn cannot gracefully exit in all contexts
1672- if dp .kill_me :
1683+ if dp .stopped :
16731684 dp .error (f"terminating emulation..." )
16741685 return False
16751686 dp .error (f"invalid instruction at { hex (address )} " )
0 commit comments