1212from qiling .arch .x86_const import GS_SEGMENT_ADDR , GS_SEGMENT_SIZE
1313from qiling .arch .x86_utils import GDTManager , SegmentManager86 , SegmentManager64
1414from qiling .arch import arm_utils
15+ from qiling .arch .cortex_m_const import EXCP
16+ from qiling .arch .mips_const import EXCP as MIPS_EXCP
1517from qiling .cc import QlCC , intel , arm , mips , riscv , ppc
1618from qiling .const import QL_ARCH , QL_OS
1719from qiling .os .fcall import QlFunctionCall
@@ -56,7 +58,8 @@ def load(self):
5658 # ARM
5759 if self .ql .arch .type == QL_ARCH .ARM :
5860 self .ql .arch .enable_vfp ()
59- self .ql .hook_intno (self .hook_syscall , 2 )
61+ self .ql .hook_intno (self .hook_syscall , EXCP .SWI )
62+ self .ql .hook_intno (self .hook_cpu_exception , EXCP .UDEF )
6063 self .thread_class = thread .QlLinuxARMThread
6164 arm_utils .init_linux_traps (self .ql , {
6265 'memory_barrier' : 0xffff0fa0 ,
@@ -66,13 +69,15 @@ def load(self):
6669
6770 # MIPS32
6871 elif self .ql .arch .type == QL_ARCH .MIPS :
69- self .ql .hook_intno (self .hook_syscall , 17 )
72+ self .ql .hook_intno (self .hook_syscall , MIPS_EXCP .SYSCALL )
73+ self .ql .hook_intno (self .hook_cpu_exception , MIPS_EXCP .RI )
7074 self .thread_class = thread .QlLinuxMIPS32Thread
7175
7276 # ARM64
7377 elif self .ql .arch .type == QL_ARCH .ARM64 :
7478 self .ql .arch .enable_vfp ()
75- self .ql .hook_intno (self .hook_syscall , 2 )
79+ self .ql .hook_intno (self .hook_syscall , EXCP .SWI )
80+ self .ql .hook_intno (self .hook_cpu_exception , EXCP .UDEF )
7681 self .thread_class = thread .QlLinuxARM64Thread
7782
7883 # X86
@@ -137,6 +142,24 @@ def setup_procfs(self):
137142 def hook_syscall (self , ql , intno = None ):
138143 return self .load_syscall ()
139144
145+ def hook_cpu_exception (self , ql , intno = None ):
146+ # A cpu exception the kernel would turn into a fatal signal that
147+ # terminates the process (e.g. SIGILL on an undefined instruction).
148+ # Emulate that termination by stopping cleanly instead of letting the
149+ # unhandled-interrupt dispatcher raise QlErrorCoreHook. This commonly
150+ # happens with shellcode that falls through into trailing data once a
151+ # terminal syscall (e.g. a denied execve) returns instead of replacing
152+ # the image.
153+ signame = {
154+ EXCP .UDEF : 'SIGILL' , # ARM / ARM64 undefined instruction
155+ MIPS_EXCP .RI : 'SIGILL' , # MIPS reserved (illegal) instruction
156+ }.get (intno , f'exception { intno :#x} ' )
157+
158+ pc = ql .arch .regs .arch_pc
159+
160+ ql .log .debug (f'CPU raised { signame } at { pc :#x} ; terminating emulated process' )
161+ ql .stop ()
162+
140163 def register_function_after_load (self , function ):
141164 if function not in self .function_after_load_list :
142165 self .function_after_load_list .append (function )
0 commit comments