@@ -296,6 +296,7 @@ def __init__(self, minidump_file, *, trace=False, quiet=False, thread_id=None, d
296296 self .debug (f"total commit: { hex (self ._pages .total_commit )} , pages: { self ._pages .total_commit // PAGE_SIZE } " )
297297 self ._setup_modules ()
298298 self .syscalls = []
299+ self .win32k_syscalls = []
299300 self ._setup_syscalls ()
300301 self ._setup_emulator (thread )
301302 self .handles = HandleManager ()
@@ -779,10 +780,10 @@ def _setup_modules(self):
779780 def _setup_syscalls (self ):
780781 # Load the ntdll module from memory
781782 ntdll = self .modules ["ntdll.dll" ]
782- syscalls = []
783+ nt_syscalls = []
783784 for export in ntdll .exports :
784785 if export .name and export .name .startswith ("Zw" ):
785- syscalls .append ((export .address , export .name ))
786+ nt_syscalls .append ((export .address , export .name ))
786787 elif export .name == "Wow64Transition" :
787788 patch_addr = self .read_ptr (export .address )
788789 self .info (f"Patching Wow64Transition: { hex (export .address )} -> { hex (patch_addr )} " )
@@ -795,20 +796,46 @@ def _setup_syscalls(self):
795796 elif export .name == "LdrLoadDll" :
796797 self .LdrLoadDll = export .address
797798
798- syscalls .sort ()
799- for index , (rva , name ) in enumerate (syscalls ):
800- cb = syscall_functions .get (name , None )
801- argcount = 0
802- if cb :
803- argspec = inspect .getfullargspec (cb )
804- argcount = len (argspec .args ) - 1
805- self .syscalls .append ((name , cb , argcount ))
799+ def add_syscalls (syscalls , table ):
800+ # The index when sorting by RVA is the syscall index
801+ syscalls .sort ()
802+ for index , (rva , name ) in enumerate (syscalls ):
803+ cb = syscall_functions .get (name , None )
804+ argcount = 0
805+ if cb :
806+ argspec = inspect .getfullargspec (cb )
807+ argcount = len (argspec .args ) - 1
808+ table .append ((name , cb , argcount ))
809+
810+ add_syscalls (nt_syscalls , self .syscalls )
811+
812+ # Get the syscalls for win32u
813+ win32u = self .modules .find ("win32u.dll" )
814+ if win32u is not None :
815+ win32k_syscalls = []
816+ for export in win32u .exports :
817+ if export .name and export .name .startswith ("Nt" ):
818+ win32k_syscalls .append ((export .address , export .name ))
819+
820+ add_syscalls (win32k_syscalls , self .win32k_syscalls )
821+
806822
807823 def push (self , value ):
808824 csp = self .regs .csp - self .ptr_size ()
809825 self .write_ptr (csp , value )
810826 self .regs .csp = csp
811827
828+ def pop (self ):
829+ csp = self .regs .csp
830+ value = self .read_ptr (csp )
831+ self .regs .csp = csp + self .ptr_size ()
832+ return value
833+
834+ def ret (self , imm = 0 ):
835+ return_address = self .pop ()
836+ self .regs .csp -= imm
837+ return return_address
838+
812839 def read (self , addr , size ):
813840 if not isinstance (addr , int ):
814841 addr = int (addr )
@@ -1464,19 +1491,36 @@ def _hook_syscall(uc: Uc, dp: Dumpulator):
14641491 # Flush the trace for easier debugging
14651492 if dp .trace is not None :
14661493 dp .trace .flush ()
1467- index = dp .regs .cax & 0xffff
1468- if index < len (dp .syscalls ):
1469- name , syscall_impl , argcount = dp .syscalls [index ]
1494+
1495+ # Extract the table and function number from eax
1496+ service_number = dp .regs .cax & 0xffff
1497+ table_number = (service_number >> 12 ) & 0xf # 0: ntoskrnl, 1: win32k
1498+ function_index = service_number & 0xfff
1499+ if table_number == 0 :
1500+ table = dp .syscalls
1501+ table_prefix = ""
1502+ elif table_number == 1 :
1503+ table = dp .win32k_syscalls
1504+ table_prefix = "win32k "
1505+ else :
1506+ table = []
1507+ table_prefix = f"unknown:{ table_number } "
1508+
1509+ if function_index < len (table ):
1510+ name , syscall_impl , argcount = table [function_index ]
14701511 if syscall_impl :
14711512 argspec = inspect .getfullargspec (syscall_impl )
14721513 args = []
14731514
14741515 def syscall_arg (index ):
1516+ # There is an extra call that adds a return address to the stack
1517+ if dp .wow64 :
1518+ index += 1
14751519 if index == 0 and dp .ptr_size () == 8 :
14761520 return dp .regs .r10
14771521 return dp .args [index ]
14781522
1479- dp .info (f"[{ dp .sequence_id } ] syscall ( index: { hex (index ) } ): { name } ( " )
1523+ dp .info (f"[{ dp .sequence_id } ] { table_prefix } syscall: { name } ( /* index: { hex (service_number ) } */ " )
14801524 for i in range (0 , argcount ):
14811525 argname = argspec .args [1 + i ]
14821526 argtype = argspec .annotations [argname ]
@@ -1499,9 +1543,9 @@ def syscall_arg(index):
14991543 argvalue = argtype (dp , argvalue )
15001544 elif issubclass (argtype , Enum ):
15011545 try :
1502- argvalue = argtype (dp . args [ i ] & 0xFFFFFFFF )
1546+ argvalue = argtype (argvalue & 0xFFFFFFFF )
15031547 except KeyError as x :
1504- raise Exception (f"Unknown enum value { dp . args [ i ] } for { type (argtype )} " ) from None
1548+ raise Exception (f"Unknown enum value { argvalue } for { type (argtype )} " ) from None
15051549 else :
15061550 argvalue = argtype (argvalue )
15071551 args .append (argvalue )
@@ -1535,9 +1579,9 @@ def syscall_arg(index):
15351579 finally :
15361580 dp .sequence_id += 1
15371581 else :
1538- raise dp .raise_kill (NotImplementedError (f"syscall index: { index :x } -> { name } not implemented!" )) from None
1582+ raise dp .raise_kill (NotImplementedError (f"{ table_prefix } syscall { hex ( service_number ) } -> { name } not implemented!" )) from None
15391583 else :
1540- raise dp .raise_kill (IndexError (f"syscall index { index :x } out of range" )) from None
1584+ raise dp .raise_kill (IndexError (f"{ table_prefix } syscall { hex ( service_number ) } ( index: { hex ( function_index ) } ) out of range" )) from None
15411585
15421586def _emulate_unsupported_instruction (dp : Dumpulator , instr : CsInsn ):
15431587 if instr .id == X86_INS_RDRAND :
0 commit comments