Skip to content

Commit e1baf2f

Browse files
committed
x86: support hooking SYSCALL/SYSENTER instructions. we no longer share the SYSCALL callback with interrupt instructions
1 parent 3eeda8c commit e1baf2f

File tree

7 files changed

+41
-15
lines changed

7 files changed

+41
-15
lines changed

bindings/python/sample_x86.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -408,15 +408,15 @@ def test_x86_64_syscall():
408408
# write machine code to be emulated to memory
409409
mu.mem_write(ADDRESS, X86_CODE64_SYSCALL)
410410

411-
def hook_intr(mu, intno, user_data):
411+
def hook_syscall(mu, user_data):
412412
rax = mu.reg_read(X86_REG_RAX)
413-
if intno == 80 and rax == 0x100:
413+
if rax == 0x100:
414414
mu.reg_write(X86_REG_RAX, 0x200)
415415
else:
416416
print('ERROR: was not expecting rax=%d in syscall' % rax)
417417

418418
# hook interrupts for syscall
419-
mu.hook_add(UC_HOOK_INTR, hook_intr)
419+
mu.hook_add(UC_HOOK_INSN, hook_syscall, None, X86_INS_SYSCALL)
420420

421421
# syscall handler is expecting rax=0x100
422422
mu.reg_write(X86_REG_RAX, 0x100)

bindings/python/unicorn/__init__.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ def _setup_prototype(lib, fname, restype, *argtypes):
231231
ctypes.c_int, ctypes.c_void_p)
232232
UC_HOOK_INSN_OUT_CB = ctypes.CFUNCTYPE(None, ctypes.c_size_t, ctypes.c_uint32, \
233233
ctypes.c_int, ctypes.c_uint32, ctypes.c_void_p)
234+
UC_HOOK_INSN_SYSCALL_CB = ctypes.CFUNCTYPE(None, ctypes.c_size_t, ctypes.c_void_p)
234235

235236

236237
# access to error code via @errno of UcError
@@ -383,6 +384,12 @@ def _hook_insn_out_cb(self, handle, port, size, value, user_data):
383384
cb(self, port, size, value, data)
384385

385386

387+
def _hook_insn_syscall_cb(self, handle, user_data):
388+
# call user's callback with self object
389+
(cb, data) = self._callbacks[user_data]
390+
cb(self, data)
391+
392+
386393
# add a hook
387394
def hook_add(self, htype, callback, user_data=None, arg1=1, arg2=0):
388395
_h2 = ctypes.c_size_t()
@@ -413,6 +420,8 @@ def hook_add(self, htype, callback, user_data=None, arg1=1, arg2=0):
413420
cb = ctypes.cast(UC_HOOK_INSN_IN_CB(self._hook_insn_in_cb), UC_HOOK_INSN_IN_CB)
414421
if arg1 == x86_const.X86_INS_OUT: # OUT instruction
415422
cb = ctypes.cast(UC_HOOK_INSN_OUT_CB(self._hook_insn_out_cb), UC_HOOK_INSN_OUT_CB)
423+
if arg1 in (x86_const.X86_INS_SYSCALL, x86_const.X86_INS_SYSENTER): # SYSCALL/SYSENTER instruction
424+
cb = ctypes.cast(UC_HOOK_INSN_SYSCALL_CB(self._hook_insn_syscall_cb), UC_HOOK_INSN_SYSCALL_CB)
416425
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \
417426
cb, ctypes.cast(self._callback_count, ctypes.c_void_p), insn)
418427
elif htype == UC_HOOK_INTR:

include/uc_priv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ struct uc_struct {
146146
int hook_intr_idx; // for handling interrupt
147147
int hook_out_idx; // for handling OUT instruction (X86)
148148
int hook_in_idx; // for handling IN instruction (X86)
149+
int hook_syscall_idx; // for handling SYSCALL/SYSENTER (X86)
149150

150151

151152
bool init_tcg; // already initialized local TCGv variables?

include/unicorn/unicorn.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ extern "C" {
1919

2020
#include "platform.h"
2121

22+
// Handle to use with all APIs
23+
typedef size_t uch;
24+
2225
#include "m68k.h"
2326
#include "x86.h"
2427
#include "arm.h"
@@ -65,9 +68,6 @@ extern "C" {
6568
// 1 milisecond = 1000 nanoseconds
6669
#define UC_MILISECOND_SCALE 1000
6770

68-
// Handle using with all API
69-
typedef size_t uch;
70-
7171
// Architecture type
7272
typedef enum uc_arch {
7373
UC_ARCH_ARM = 1, // ARM architecture (including Thumb, Thumb-2)

include/unicorn/x86.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
extern "C" {
99
#endif
1010

11+
// Callback function for tracing SYSCALL/SYSENTER (for uc_hook_intr())
12+
// @user_data: user data passed to tracing APIs.
13+
typedef void (*uc_cb_insn_syscall_t)(uch handle, void *user_data);
14+
1115
//> X86 registers
1216
typedef enum x86_reg {
1317
X86_REG_INVALID = 0,

qemu/target-i386/seg_helper.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -945,15 +945,15 @@ void helper_syscall(CPUX86State *env, int next_eip_addend)
945945
#else
946946
void helper_syscall(CPUX86State *env, int next_eip_addend)
947947
{
948-
// Unicorn: call interrupt callback if registered
949-
struct uc_struct *uc = env->uc;
950-
if (uc->hook_intr_idx) {
951-
((uc_cb_hookintr_t)uc->hook_callbacks[uc->hook_intr_idx].callback)(
952-
(uch)uc, 80,
953-
uc->hook_callbacks[uc->hook_intr_idx].user_data);
954-
env->eip += next_eip_addend;
955-
return;
956-
}
948+
// Unicorn: call interrupt callback if registered
949+
struct uc_struct *uc = env->uc;
950+
if (uc->hook_syscall_idx) {
951+
((uc_cb_insn_syscall_t)uc->hook_callbacks[uc->hook_syscall_idx].callback)(
952+
(uch)uc, uc->hook_callbacks[uc->hook_syscall_idx].user_data);
953+
env->eip += next_eip_addend;
954+
}
955+
956+
return;
957957

958958
int selector;
959959

uc.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,18 @@ static uc_err _hook_insn(struct uc_struct *uc, unsigned int insn_id, void *callb
645645
return UC_ERR_OK;
646646
} else
647647
return UC_ERR_OOM;
648+
case X86_INS_SYSCALL:
649+
case X86_INS_SYSENTER:
650+
// FIXME: only one event handler at the same time
651+
i = hook_find_new(uc);
652+
if (i) {
653+
uc->hook_callbacks[i].callback = callback;
654+
uc->hook_callbacks[i].user_data = user_data;
655+
*evh = i;
656+
uc->hook_syscall_idx = i;
657+
return UC_ERR_OK;
658+
} else
659+
return UC_ERR_OOM;
648660
}
649661
break;
650662
}

0 commit comments

Comments
 (0)