Better design of cpuid instruction hook

This commit is contained in:
lazymio 2021-12-22 20:36:56 +01:00
parent dfb14e971f
commit 7bb756249a
No known key found for this signature in database
GPG Key ID: DFF27E34A47CB873
3 changed files with 27 additions and 9 deletions

View File

@ -75,6 +75,14 @@ typedef struct uc_x86_msr {
// @user_data: user data passed to tracing APIs. // @user_data: user data passed to tracing APIs.
typedef void (*uc_cb_insn_syscall_t)(struct uc_struct *uc, void *user_data); typedef void (*uc_cb_insn_syscall_t)(struct uc_struct *uc, void *user_data);
// Callback function for tracing cpuid (for uc_hook_intr())
// @user_data: user data passed to tracing APIs.
//
// @return: true indicates the callback overwrites the cpuid instruction while
// false
// indicates cpuid instruction will still be executed.
typedef int (*uc_cb_insn_cpuid_t)(struct uc_struct *uc, void *user_data);
//> X86 registers //> X86 registers
typedef enum uc_x86_reg { typedef enum uc_x86_reg {
UC_X86_REG_INVALID = 0, UC_X86_REG_INVALID = 0,

View File

@ -106,16 +106,10 @@ void helper_cpuid(CPUX86State *env)
{ {
uint32_t eax, ebx, ecx, edx; uint32_t eax, ebx, ecx, edx;
struct hook *hook; struct hook *hook;
int skip_cpuid = 0;
cpu_svm_check_intercept_param(env, SVM_EXIT_CPUID, 0, GETPC()); cpu_svm_check_intercept_param(env, SVM_EXIT_CPUID, 0, GETPC());
cpu_x86_cpuid(env, (uint32_t)env->regs[R_EAX], (uint32_t)env->regs[R_ECX],
&eax, &ebx, &ecx, &edx);
env->regs[R_EAX] = eax;
env->regs[R_EBX] = ebx;
env->regs[R_ECX] = ecx;
env->regs[R_EDX] = edx;
// Unicorn: call registered CPUID hooks // Unicorn: call registered CPUID hooks
HOOK_FOREACH_VAR_DECLARE; HOOK_FOREACH_VAR_DECLARE;
HOOK_FOREACH(env->uc, hook, UC_HOOK_INSN) { HOOK_FOREACH(env->uc, hook, UC_HOOK_INSN) {
@ -123,13 +117,26 @@ void helper_cpuid(CPUX86State *env)
continue; continue;
if (!HOOK_BOUND_CHECK(hook, env->eip)) if (!HOOK_BOUND_CHECK(hook, env->eip))
continue; continue;
// Multiple cpuid callbacks returning different values is undefined.
// true -> skip the cpuid instruction
if (hook->insn == UC_X86_INS_CPUID) if (hook->insn == UC_X86_INS_CPUID)
((uc_cb_insn_syscall_t)hook->callback)(env->uc, hook->user_data); skip_cpuid = ((uc_cb_insn_cpuid_t)hook->callback)(env->uc, hook->user_data);
// the last callback may already asked to stop emulation // the last callback may already asked to stop emulation
if (env->uc->stop_request) if (env->uc->stop_request)
break; break;
} }
if (!skip_cpuid) {
cpu_x86_cpuid(env, (uint32_t)env->regs[R_EAX], (uint32_t)env->regs[R_ECX],
&eax, &ebx, &ecx, &edx);
env->regs[R_EAX] = eax;
env->regs[R_EBX] = ebx;
env->regs[R_ECX] = ecx;
env->regs[R_EDX] = edx;
}
} }
target_ulong helper_read_crN(CPUX86State *env, int reg) target_ulong helper_read_crN(CPUX86State *env, int reg)

View File

@ -601,11 +601,14 @@ static void test_x86_sysenter()
OK(uc_close(uc)); OK(uc_close(uc));
} }
static void test_x86_hook_cpuid_callback(uc_engine *uc, void *data) static int test_x86_hook_cpuid_callback(uc_engine *uc, void *data)
{ {
int reg = 7; int reg = 7;
OK(uc_reg_write(uc, UC_X86_REG_EAX, &reg)); OK(uc_reg_write(uc, UC_X86_REG_EAX, &reg));
// Overwrite the cpuid instruction.
return 1;
} }
static void test_x86_hook_cpuid() static void test_x86_hook_cpuid()