@@ -115,3 +115,47 @@ def hook_RemoveVectoredExceptionHandler(ql: Qiling, address: int, params):
115115 hook .remove ()
116116
117117 return 0
118+
119+ # VOID RaiseException(
120+ # DWORD dwExceptionCode,
121+ # DWORD dwExceptionFlags,
122+ # DWORD nNumberOfArguments,
123+ # CONST ULONG_PTR* lpArguments
124+ # );
125+ @winsdkapi (cc = STDCALL , params = {
126+ 'dwExceptionCode' : DWORD ,
127+ 'dwExceptionFlags' : DWORD ,
128+ 'nNumberOfArguments' : DWORD ,
129+ 'lpArguments' : PVOID
130+ }, passthru = True )
131+ def hook_RaiseException (ql : Qiling , address : int , params ):
132+ # On x86_64, RaiseException will call RtlRaiseException,
133+ # which calls the exception dispatcher directly. The native
134+ # exception dispatching code mostly works correctly
135+ # for software exceptions, so we shall simply continue
136+ # through to the native dispatcher in this case.
137+ if ql .arch .type is not QL_ARCH .X86 :
138+ return
139+
140+ # On x86, the situation is different. RtlRaiseException
141+ # will call ZwRaiseException, which uses a syscall.
142+ # However, Qiling doesn't really support Windows syscalls
143+ # right now.
144+ # We will treat all exceptions as unhandled exceptions,
145+ # which is better than nothing.
146+ # TODO: Get kernel exception dispatching working properly,
147+ # then first-chance software exceptions, SEH, and C++
148+ # exceptions can work on 32-bit Windows too.
149+ nNumberOfArguments = params ['nNumberOfArguments' ]
150+ lpArguments = params ['lpArguments' ]
151+
152+ handle = ql .os .handle_manager .search ("TopLevelExceptionHandler" )
153+
154+ if handle is None :
155+ ql .log .warning (f'RaiseException: top level exception handler not found' )
156+ return
157+
158+ exception_handler = handle .obj
159+ args = [(PARAM_INTN , ql .mem .read_ptr (lpArguments + i * ql .arch .pointersize )) for i in range (nNumberOfArguments )] if lpArguments else []
160+
161+ ql .os .fcall .call_native (exception_handler , args , None )
0 commit comments