@@ -321,7 +321,8 @@ def __init__(self, minidump_file, *, trace=False, quiet=False, thread_id=None, d
321
321
self .handles = HandleManager ()
322
322
self ._setup_handles ()
323
323
self ._setup_registry ()
324
- self .kill_me = None
324
+ self .stopped = False
325
+ self .kill_exception = None
325
326
self .exit_code = None
326
327
self .exports = self ._all_exports ()
327
328
self ._exception = UnicornExceptionInfo ()
@@ -943,6 +944,8 @@ def handle_exception(self):
943
944
944
945
if self ._exception_hook is not None :
945
946
hook_result = self ._exception_hook (self ._exception )
947
+ if self .stopped :
948
+ return None
946
949
if hook_result is not None :
947
950
# Clear the pending exception
948
951
self ._last_exception = self ._exception
@@ -1073,12 +1076,16 @@ def write_stack(cur_ptr: int, data: bytes):
1073
1076
return self .KiUserExceptionDispatcher
1074
1077
1075
1078
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
1076
1083
# Clear exceptions before starting
1077
1084
self ._exception = UnicornExceptionInfo ()
1078
1085
emu_begin = begin
1079
1086
emu_until = end
1080
1087
emu_count = count
1081
- while True :
1088
+ while not self . stopped :
1082
1089
try :
1083
1090
if self ._exception .type != ExceptionType .NoException :
1084
1091
if self ._exception .final :
@@ -1093,6 +1100,8 @@ def start(self, begin, end=0xffffffffffffffff, count=0) -> None:
1093
1100
1094
1101
try :
1095
1102
emu_begin = self .handle_exception ()
1103
+ if self .stopped :
1104
+ break
1096
1105
except Exception :
1097
1106
traceback .print_exc ()
1098
1107
self .error (f"exception during exception handling (stack overflow?)" )
@@ -1117,15 +1126,14 @@ def start(self, begin, end=0xffffffffffffffff, count=0) -> None:
1117
1126
emu_count = self ._exception .tb_icount + 1
1118
1127
1119
1128
self .info (f"emu_start({ hex (emu_begin )} , { hex (emu_until )} , { emu_count } )" )
1120
- self .kill_me = None
1121
1129
self ._uc .emu_start (emu_begin , until = emu_until , count = emu_count )
1122
1130
self .info (f'emulation finished, cip = { hex (self .regs .cip )} ' )
1123
1131
if self .exit_code is not None :
1124
1132
self .info (f"exit code: { hex (self .exit_code )} " )
1125
1133
break
1126
1134
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
1129
1137
if self ._exception .type != ExceptionType .NoException :
1130
1138
# Handle the exception outside of the except handler
1131
1139
continue
@@ -1142,17 +1150,17 @@ def stop(self, exit_code=None) -> None:
1142
1150
except Exception :
1143
1151
traceback .print_exc ()
1144
1152
self .error ("Invalid type passed to exit_code!" )
1153
+ self .stopped = True
1145
1154
self ._uc .emu_stop ()
1146
1155
1147
1156
def raise_kill (self , exc = None ):
1148
1157
# HACK: You need to use this to exit from hooks (although it might not always work)
1149
1158
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
1156
1164
1157
1165
def NtCurrentProcess (self ):
1158
1166
return 0xFFFFFFFFFFFFFFFF if self ._x64 else 0xFFFFFFFF
@@ -1292,12 +1300,12 @@ def _hook_code_exception(uc: Uc, address, size, dp: Dumpulator):
1292
1300
1293
1301
def _hook_mem (uc : Uc , access , address , size , value , dp : Dumpulator ):
1294
1302
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 ) } ) " )
1296
1304
return True
1297
1305
1298
1306
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 )} ]" )
1301
1309
return False
1302
1310
if dp ._exception .final and access in fetch_accesses :
1303
1311
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):
1368
1376
dp ._exception .final = True
1369
1377
1370
1378
# Stop emulation (we resume it on KiUserExceptionDispatcher later)
1371
- dp .stop ()
1379
+ dp ._uc . emu_stop ()
1372
1380
return False
1373
1381
1374
1382
# There should not be an exception active
@@ -1387,7 +1395,7 @@ def _hook_mem(uc: Uc, access, address, size, value, dp: Dumpulator):
1387
1395
dp ._exception = exception
1388
1396
1389
1397
# Stop emulation (we resume execution later)
1390
- dp .stop ()
1398
+ dp ._uc . emu_stop ()
1391
1399
return False
1392
1400
except AssertionError as err :
1393
1401
traceback .print_exc ()
@@ -1421,50 +1429,53 @@ def _get_regs(instr, include_write=False):
1421
1429
return regs
1422
1430
1423
1431
def _hook_code (uc : Uc , address , size , dp : Dumpulator ):
1424
- code = b""
1425
1432
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 , "" )
1434
1442
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
1468
1479
1469
1480
def _unicode_string_to_string (dp : Dumpulator , arg : P [UNICODE_STRING ]):
1470
1481
try :
@@ -1627,7 +1638,7 @@ def syscall_arg(index):
1627
1638
if isinstance (status , ExceptionInfo ):
1628
1639
print ("context switch, stopping emulation" )
1629
1640
dp ._exception = status
1630
- raise dp . raise_kill ( UcError (UC_ERR_EXCEPTION )) from None
1641
+ raise UcError (UC_ERR_EXCEPTION )
1631
1642
else :
1632
1643
dp .info (f"status = { hex (status )} " )
1633
1644
dp .regs .cax = status
@@ -1669,7 +1680,7 @@ def _hook_invalid(uc: Uc, dp: Dumpulator):
1669
1680
if dp .trace :
1670
1681
dp .trace .flush ()
1671
1682
# HACK: unicorn cannot gracefully exit in all contexts
1672
- if dp .kill_me :
1683
+ if dp .stopped :
1673
1684
dp .error (f"terminating emulation..." )
1674
1685
return False
1675
1686
dp .error (f"invalid instruction at { hex (address )} " )
0 commit comments