-
-
Notifications
You must be signed in to change notification settings - Fork 251
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
x86: Improve Interceptor to support shadow stacks
This patch makes Interceptor code compatible with Intel CET shadow stacks. - Detect CPUs that have support for CET shadow stacks. - Make the on_leave_trampoline a legit address to return to from a CET-enabled intercepted function's point of view. - Ensure a proper CALL/RET discipline. On Windows, this means that it will now be possible to intercept functions that live in CETCOMPAT modules when the user shadow stack mitigation is active (though not in strict mode).
- Loading branch information
Showing
3 changed files
with
70 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
/* | ||
* Copyright (C) 2008-2022 Ole André Vadla Ravnås <[email protected]> | ||
* Copyright (C) 2008 Christian Berentsen <[email protected]> | ||
* Copyright (C) 2024 Yannis Juglaret <[email protected]> | ||
* | ||
* Licence: wxWindows Library Licence, Version 3.1 | ||
*/ | ||
|
@@ -46,6 +47,7 @@ struct _GumInterceptorBackend | |
struct _GumX86FunctionContextData | ||
{ | ||
guint redirect_code_size; | ||
gpointer push_to_shadow_stack; | ||
}; | ||
|
||
G_STATIC_ASSERT (sizeof (GumX86FunctionContextData) | ||
|
@@ -61,7 +63,7 @@ static void gum_emit_leave_thunk (GumX86Writer * cw); | |
|
||
static void gum_emit_prolog (GumX86Writer * cw, | ||
gssize stack_displacement); | ||
static void gum_emit_epilog (GumX86Writer * cw); | ||
static void gum_emit_epilog (GumX86Writer * cw, GumPointCut point_cut); | ||
|
||
GumInterceptorBackend * | ||
_gum_interceptor_backend_create (GRecMutex * mutex, | ||
|
@@ -171,6 +173,7 @@ _gum_interceptor_backend_create_trampoline (GumInterceptorBackend * self, | |
GumX86Relocator * rl = &self->relocator; | ||
GumX86FunctionContextData * data = GUM_FCDATA (ctx); | ||
GumAddress function_ctx_ptr; | ||
gpointer after_push_to_shadow_stack; | ||
guint reloc_bytes; | ||
|
||
if (!gum_interceptor_backend_prepare_trampoline (self, ctx)) | ||
|
@@ -189,6 +192,27 @@ _gum_interceptor_backend_create_trampoline (GumInterceptorBackend * self, | |
gum_x86_writer_put_push_near_ptr (cw, function_ctx_ptr); | ||
gum_x86_writer_put_jmp_address (cw, GUM_ADDRESS (self->enter_thunk->data)); | ||
|
||
if ((cw->cpu_features & GUM_CPU_CET_SS) != 0) | ||
{ | ||
/* | ||
* Jumping to push_to_shadow_stack will push the on_leave_trampoline | ||
* address onto the shadow stack, thereby making it a legit address to | ||
* return to. Then it will jump back through XAX. | ||
*/ | ||
|
||
after_push_to_shadow_stack = gum_x86_writer_cur (cw); | ||
|
||
gum_x86_writer_put_lea_reg_reg_offset (cw, GUM_X86_XSP, | ||
GUM_X86_XSP, (gssize) sizeof (gpointer)); | ||
|
||
gum_x86_writer_put_jmp_reg (cw, GUM_X86_XAX); | ||
|
||
data->push_to_shadow_stack = gum_x86_writer_cur (cw); | ||
|
||
gum_x86_writer_put_call_address (cw, | ||
GUM_ADDRESS (after_push_to_shadow_stack)); | ||
} | ||
|
||
ctx->on_leave_trampoline = gum_x86_writer_cur (cw); | ||
|
||
gum_x86_writer_put_push_near_ptr (cw, function_ctx_ptr); | ||
|
@@ -321,6 +345,8 @@ static void | |
gum_emit_enter_thunk (GumX86Writer * cw) | ||
{ | ||
const gssize return_address_stack_displacement = 0; | ||
const gchar * prepare_trap_on_leave = "prepare_trap_on_leave"; | ||
gpointer epilog; | ||
|
||
gum_emit_prolog (cw, return_address_stack_displacement); | ||
|
||
|
@@ -338,7 +364,26 @@ gum_emit_enter_thunk (GumX86Writer * cw) | |
GUM_ARG_REGISTER, GUM_X86_XDX, | ||
GUM_ARG_REGISTER, GUM_X86_XCX); | ||
|
||
gum_emit_epilog (cw); | ||
if ((cw->cpu_features & GUM_CPU_CET_SS) != 0) | ||
{ | ||
gum_x86_writer_put_test_reg_reg (cw, GUM_X86_EAX, GUM_X86_EAX); | ||
gum_x86_writer_put_jcc_short_label (cw, X86_INS_JNE, prepare_trap_on_leave, | ||
GUM_NO_HINT); | ||
|
||
epilog = gum_x86_writer_cur (cw); | ||
} | ||
|
||
gum_emit_epilog (cw, FALSE); | ||
|
||
if ((cw->cpu_features & GUM_CPU_CET_SS) != 0) | ||
{ | ||
gum_x86_writer_put_label (cw, prepare_trap_on_leave); | ||
|
||
gum_x86_writer_put_mov_reg_address (cw, GUM_X86_XAX, GUM_ADDRESS (epilog)); | ||
gum_x86_writer_put_jmp_reg_offset_ptr (cw, GUM_X86_XBX, | ||
G_STRUCT_OFFSET (GumFunctionContext, backend_data) + | ||
G_STRUCT_OFFSET (GumX86FunctionContextData, push_to_shadow_stack)); | ||
} | ||
} | ||
|
||
static void | ||
|
@@ -359,7 +404,7 @@ gum_emit_leave_thunk (GumX86Writer * cw) | |
GUM_ARG_REGISTER, GUM_X86_XSI, | ||
GUM_ARG_REGISTER, GUM_X86_XDX); | ||
|
||
gum_emit_epilog (cw); | ||
gum_emit_epilog (cw, TRUE); | ||
} | ||
|
||
static void | ||
|
@@ -401,7 +446,8 @@ gum_emit_prolog (GumX86Writer * cw, | |
} | ||
|
||
static void | ||
gum_emit_epilog (GumX86Writer * cw) | ||
gum_emit_epilog (GumX86Writer * cw, | ||
GumPointCut point_cut) | ||
{ | ||
guint8 fxrstor[] = { | ||
0x0f, 0xae, 0x0c, 0x24 /* fxrstor [esp] */ | ||
|
@@ -415,5 +461,17 @@ gum_emit_epilog (GumX86Writer * cw) | |
GumCpuContext.xip */ | ||
gum_x86_writer_put_popax (cw); | ||
gum_x86_writer_put_popfx (cw); | ||
gum_x86_writer_put_ret (cw); | ||
|
||
if (point_cut == GUM_POINT_LEAVE) | ||
{ | ||
gum_x86_writer_put_ret (cw); | ||
} | ||
else | ||
{ | ||
/* Emulate a ret without affecting the shadow stack. */ | ||
gum_x86_writer_put_lea_reg_reg_offset (cw, GUM_X86_XSP, | ||
GUM_X86_XSP, sizeof (gpointer)); | ||
gum_x86_writer_put_jmp_reg_offset_ptr (cw, GUM_X86_XSP, | ||
-((gssize) sizeof (gpointer))); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
/* | ||
* Copyright (C) 2008-2022 Ole André Vadla Ravnås <[email protected]> | ||
* Copyright (C) 2008 Christian Berentsen <[email protected]> | ||
* Copyright (C) 2024 Yannis Juglaret <[email protected]> | ||
* | ||
* Licence: wxWindows Library Licence, Version 3.1 | ||
*/ | ||
|
@@ -68,7 +69,7 @@ struct _GumFunctionContext | |
G_GNUC_INTERNAL void _gum_interceptor_init (void); | ||
G_GNUC_INTERNAL void _gum_interceptor_deinit (void); | ||
|
||
G_GNUC_INTERNAL void _gum_function_context_begin_invocation ( | ||
G_GNUC_INTERNAL gboolean _gum_function_context_begin_invocation ( | ||
GumFunctionContext * function_ctx, GumCpuContext * cpu_context, | ||
gpointer * caller_ret_addr, gpointer * next_hop); | ||
G_GNUC_INTERNAL void _gum_function_context_end_invocation ( | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ | |
* Copyright (C) 2008-2024 Ole André Vadla Ravnås <[email protected]> | ||
* Copyright (C) 2008 Christian Berentsen <[email protected]> | ||
* Copyright (C) 2024 Francesco Tamagni <[email protected]> | ||
* Copyright (C) 2024 Yannis Juglaret <[email protected]> | ||
* | ||
* Licence: wxWindows Library Licence, Version 3.1 | ||
*/ | ||
|
@@ -1513,7 +1514,7 @@ gum_function_context_find_taken_listener_slot ( | |
return NULL; | ||
} | ||
|
||
void | ||
gboolean | ||
_gum_function_context_begin_invocation (GumFunctionContext * function_ctx, | ||
GumCpuContext * cpu_context, | ||
gpointer * caller_ret_addr, | ||
|
@@ -1526,7 +1527,7 @@ _gum_function_context_begin_invocation (GumFunctionContext * function_ctx, | |
GumInvocationContext * invocation_ctx = NULL; | ||
gint system_error; | ||
gboolean invoke_listeners = TRUE; | ||
gboolean will_trap_on_leave; | ||
gboolean will_trap_on_leave = FALSE; | ||
|
||
g_atomic_int_inc (&function_ctx->trampoline_usage_counter); | ||
|
||
|
@@ -1663,15 +1664,13 @@ _gum_function_context_begin_invocation (GumFunctionContext * function_ctx, | |
*next_hop = function_ctx->on_invoke_trampoline; | ||
} | ||
|
||
bypass: | ||
if (!will_trap_on_leave) | ||
{ | ||
g_atomic_int_dec_and_test (&function_ctx->trampoline_usage_counter); | ||
} | ||
|
||
return; | ||
|
||
bypass: | ||
g_atomic_int_dec_and_test (&function_ctx->trampoline_usage_counter); | ||
return will_trap_on_leave; | ||
} | ||
|
||
void | ||
|