@@ -404,7 +404,8 @@ def __setitem__(self, index, value):
404
404
405
405
406
406
class Dumpulator (Architecture ):
407
- def __init__ (self , minidump_file , trace = False ):
407
+ def __init__ (self , minidump_file , * , trace = False , quiet = False ):
408
+ self ._quiet = quiet
408
409
self ._minidump = MinidumpFile .parse (minidump_file )
409
410
super ().__init__ (type (self ._minidump .threads .threads [0 ].ContextObject ) is not WOW64_CONTEXT )
410
411
self .addr_mask = 0xFFFFFFFFFFFFFFFF if self ._x64 else 0xFFFFFFFF
@@ -434,6 +435,13 @@ def __init__(self, minidump_file, trace=False):
434
435
self ._setup_syscalls ()
435
436
self .exports = self ._setup_exports ()
436
437
438
+ def info (self , message : str ):
439
+ if not self ._quiet :
440
+ print (message )
441
+
442
+ def error (self , message : str ):
443
+ print (message )
444
+
437
445
# Source: https://github.com/mandiant/speakeasy/blob/767edd2272510a5badbab89c5f35d43a94041378/speakeasy/windows/winemu.py#L533
438
446
def _setup_gdt (self , teb_addr ):
439
447
"""
@@ -538,7 +546,7 @@ def _setup_emulator(self):
538
546
for info in self ._minidump .memory_info .infos :
539
547
emu_addr = info .BaseAddress & self .addr_mask
540
548
if info .State == MemoryState .MEM_COMMIT :
541
- print (f"mapped base: 0x{ emu_addr :x} , size: 0x{ info .RegionSize :x} , protect: { info .Protect } " )
549
+ self . info (f"mapped base: 0x{ emu_addr :x} , size: 0x{ info .RegionSize :x} , protect: { info .Protect } " )
542
550
self ._uc .mem_map (emu_addr , info .RegionSize , map_unicorn_perms (info .Protect ))
543
551
elif info .State == MemoryState .MEM_FREE and emu_addr > 0x10000 and info .RegionSize >= self ._allocate_size :
544
552
self ._allocate_base = emu_addr
@@ -547,7 +555,7 @@ def _setup_emulator(self):
547
555
seg : MinidumpMemorySegment
548
556
for seg in self ._minidump .memory_segments_64 .memory_segments :
549
557
emu_addr = seg .start_virtual_address & self .addr_mask
550
- print (f"initialize base: 0x{ emu_addr :x} , size: 0x{ seg .size :x} " )
558
+ self . info (f"initialize base: 0x{ emu_addr :x} , size: 0x{ seg .size :x} " )
551
559
memory .move (seg .start_virtual_address )
552
560
assert memory .current_position == seg .start_virtual_address
553
561
data = memory .read (seg .size )
@@ -631,17 +639,17 @@ def _setup_emulator(self):
631
639
self .stdin_handle = self .read_ptr (process_parameters + 0x18 )
632
640
self .stdout_handle = self .read_ptr (process_parameters + 0x1c )
633
641
self .stderr_handle = self .read_ptr (process_parameters + 0x20 )
634
- print (f"TEB: 0x{ self .teb :x} , PEB: 0x{ self .peb :x} " )
635
- print (f" ConsoleHandle: 0x{ self .console_handle :x} " )
636
- print (f" StandardInput: 0x{ self .stdin_handle :x} " )
637
- print (f" StandardOutput: 0x{ self .stdout_handle :x} " )
638
- print (f" StandardError: 0x{ self .stderr_handle :x} " )
642
+ self . info (f"TEB: 0x{ self .teb :x} , PEB: 0x{ self .peb :x} " )
643
+ self . info (f" ConsoleHandle: 0x{ self .console_handle :x} " )
644
+ self . info (f" StandardInput: 0x{ self .stdin_handle :x} " )
645
+ self . info (f" StandardOutput: 0x{ self .stdout_handle :x} " )
646
+ self . info (f" StandardError: 0x{ self .stderr_handle :x} " )
639
647
640
648
def _setup_exports (self ):
641
649
exports = {}
642
650
for module in self ._minidump .modules .modules :
643
651
module_name = module .name .split ('\\ ' )[- 1 ].lower ()
644
- print (f"{ module_name } 0x{ module .baseaddress :x} [0x{ module .size :x} ]" )
652
+ self . info (f"{ module_name } 0x{ module .baseaddress :x} [0x{ module .size :x} ]" )
645
653
for export in self ._parse_module_exports (module ):
646
654
if export .name :
647
655
name = export .name .decode ("utf-8" )
@@ -669,7 +677,7 @@ def _parse_module_exports(self, module):
669
677
try :
670
678
module_data = self .read (module .baseaddress , module .size )
671
679
except UcError :
672
- print (f"Failed to read module data" )
680
+ self . error (f"Failed to read module data" )
673
681
return []
674
682
pe = PE (data = module_data , fast_load = True )
675
683
# Hack to adjust pefile to accept in-memory modules
@@ -691,7 +699,7 @@ def _setup_syscalls(self):
691
699
elif export .name == b"Wow64Transition" :
692
700
addr = ntdll .baseaddress + export .address
693
701
patch_addr = self .read_ptr (addr )
694
- print (f"Patching Wow64Transition: { addr :0x} -> { patch_addr :0x} " )
702
+ self . info (f"Patching Wow64Transition: { addr :0x} -> { patch_addr :0x} " )
695
703
# See: https://opcode0x90.wordpress.com/2007/05/18/kifastsystemcall-hook/
696
704
# mov edx, esp; sysenter; ret
697
705
KiFastSystemCall = b"\x8B \xD4 \x0F \x34 \xC3 "
@@ -753,11 +761,11 @@ def allocate(self, size):
753
761
def start (self , begin , end = 0xffffffffffffffff , count = 0 ):
754
762
try :
755
763
self ._uc .emu_start (begin , until = end , count = count )
756
- print (f'emulation finished, cip = { self .regs .cip :0x} ' )
764
+ self . info (f'emulation finished, cip = { self .regs .cip :0x} ' )
757
765
if self .exit_code is not None :
758
- print (f"exit code: { self .exit_code } " )
766
+ self . info (f"exit code: { self .exit_code } " )
759
767
except UcError as err :
760
- print (f'error: { err } , cip = { self .regs .cip :0x} ' )
768
+ self . error (f'error: { err } , cip = { self .regs .cip :0x} ' )
761
769
762
770
def stop (self , exit_code = None ):
763
771
self .exit_code = int (exit_code )
@@ -772,12 +780,12 @@ def NtCurrentThread(self):
772
780
773
781
def _hook_mem (uc : Uc , access , address , size , value , dp : Dumpulator ):
774
782
if access == UC_MEM_READ_UNMAPPED :
775
- print (f"unmapped read from { address :0x} [{ size :0x} ], cip = { dp .regs .cip :0x} " )
783
+ dp . error (f"unmapped read from { address :0x} [{ size :0x} ], cip = { dp .regs .cip :0x} " )
776
784
elif access == UC_MEM_WRITE_UNMAPPED :
777
- print (f"unmapped write to { address :0x} [{ size :0x} ] = { value :0x} , cip = { dp .regs .cip :0x} " )
785
+ dp . error (f"unmapped write to { address :0x} [{ size :0x} ] = { value :0x} , cip = { dp .regs .cip :0x} " )
778
786
779
787
elif access == UC_MEM_FETCH_UNMAPPED :
780
- print (f"unmapped fetch of { address :0x} [{ size :0x} ] = { value :0x} , cip = { dp .regs .cip :0x} " )
788
+ dp . error (f"unmapped fetch of { address :0x} [{ size :0x} ] = { value :0x} , cip = { dp .regs .cip :0x} " )
781
789
return False
782
790
783
791
def _get_regs (instr ):
@@ -844,7 +852,7 @@ def _arg_type_string(arg):
844
852
845
853
846
854
def _hook_interrupt (uc : Uc , number , dp : Dumpulator ):
847
- print (f"interrupt { number } , cip = { dp .regs .cip :0x} " )
855
+ dp . error (f"interrupt { number } , cip = { dp .regs .cip :0x} " )
848
856
uc .emu_stop ()
849
857
850
858
@@ -861,7 +869,7 @@ def syscall_arg(index):
861
869
return dp .regs .r10
862
870
return dp .args [index ]
863
871
864
- print (f"syscall: { name } (" )
872
+ dp . info (f"syscall: { name } (" )
865
873
for i in range (0 , argcount ):
866
874
argname = argspec .args [1 + i ]
867
875
argtype = argspec .annotations [argname ]
@@ -881,25 +889,25 @@ def syscall_arg(index):
881
889
if i + 1 == argcount :
882
890
comma = ""
883
891
884
- print (f" { _arg_type_string (argvalue )} { argname } = { _arg_to_string (argvalue )} { comma } " )
885
- print (")" )
892
+ dp . info (f" { _arg_type_string (argvalue )} { argname } = { _arg_to_string (argvalue )} { comma } " )
893
+ dp . info (")" )
886
894
try :
887
895
status = cb (dp , * args )
888
- print (f"status = { status :x} " )
896
+ dp . info (f"status = { status :x} " )
889
897
dp .regs .cax = status
890
898
dp .regs .ccx = dp .regs .cip + 2
891
899
except Exception as exc :
892
900
sys .stderr = sys .stdout
893
901
traceback .print_exception (type (exc ), exc , exc .__traceback__ )
894
- print (f"Exception thrown during syscall implementation, stopping emulation!" )
902
+ dp . error (f"Exception thrown during syscall implementation, stopping emulation!" )
895
903
uc .emu_stop ()
896
904
else :
897
- print (f"syscall index: { index :0x} -> { name } not implemented!" )
905
+ dp . error (f"syscall index: { index :0x} -> { name } not implemented!" )
898
906
uc .emu_stop ()
899
907
else :
900
- print (f"syscall index { index :0x} out of range" )
908
+ dp . error (f"syscall index { index :0x} out of range" )
901
909
uc .emu_stop ()
902
910
903
911
def _hook_invalid (uc : Uc , address , dp : Dumpulator ):
904
- print (f"invalid instruction at { address :0x} " )
912
+ dp . error (f"invalid instruction at { address :0x} " )
905
913
return False
0 commit comments