From 723c7c5d4dc00770a6b0205bafade79eed3e7051 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 14 Jun 2024 09:50:33 -0700 Subject: [PATCH] further tightening up of win32 demon run path; take a few fastpaths on x64; speeds up conditional breakpoints --- src/ctrl/ctrl_core.c | 32 +++++--- src/ctrl/ctrl_core.h | 1 + src/demon/win32/demon_core_win32.c | 122 ++++++++++++++++++++++++----- src/demon/win32/demon_core_win32.h | 10 +-- 4 files changed, 130 insertions(+), 35 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 2f04dbb4..33a24e57 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -1524,6 +1524,18 @@ ctrl_query_cached_rip_from_thread(CTRL_EntityStore *store, CTRL_MachineID machin return result; } +internal U64 +ctrl_query_cached_rsp_from_thread(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle thread) +{ + Temp scratch = scratch_begin(0, 0); + CTRL_Entity *thread_entity = ctrl_entity_from_machine_id_handle(store, machine_id, thread); + Architecture arch = thread_entity->arch; + void *block = ctrl_query_cached_reg_block_from_thread(scratch.arena, store, machine_id, thread); + U64 result = regs_rsp_from_arch_block(arch, block); + scratch_end(scratch); + return result; +} + //- rjf: thread register writing internal B32 @@ -3567,13 +3579,12 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, { CTRL_Entity *thread = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, CTRL_MachineID_Local, spoof->thread); Architecture arch = thread->arch; - void *regs_block = push_array(scratch.arena, U8, regs_block_size_from_architecture(arch)); - dmn_thread_read_reg_block(spoof->thread, regs_block); + void *regs_block = ctrl_query_cached_reg_block_from_thread(scratch.arena, ctrl_state->ctrl_thread_entity_store, CTRL_MachineID_Local, spoof->thread); U64 spoof_thread_rip = regs_rip_from_arch_block(arch, regs_block); if(spoof_thread_rip == spoof->new_ip_value) { regs_arch_block_write_rip(arch, regs_block, spoof_old_ip_value); - dmn_thread_write_reg_block(spoof->thread, regs_block); + ctrl_thread_write_reg_block(CTRL_MachineID_Local, spoof->thread, regs_block); } } @@ -3983,7 +3994,7 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) // threads, because otherwise, their stack pointer may change, if single-stepping // causes e.g. entrance into a function via a call instruction. // - U64 sp_check_value = dmn_rsp_from_thread(target_thread); + U64 sp_check_value = ctrl_query_cached_rsp_from_thread(ctrl_state->ctrl_thread_entity_store, CTRL_MachineID_Local, target_thread); ////////////////////////////// //- rjf: single step "stuck threads" @@ -4012,7 +4023,7 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) if(process->kind != CTRL_EntityKind_Process) { continue; } for(CTRL_Entity *thread = process->first; thread != &ctrl_entity_nil; thread = thread->next) { - U64 rip = dmn_rip_from_thread(thread->handle); + U64 rip = ctrl_query_cached_rip_from_thread(ctrl_state->ctrl_thread_entity_store, thread->machine_id, thread->handle); // rjf: determine if thread is frozen B32 thread_is_frozen = !msg->freeze_state_is_frozen; @@ -4432,7 +4443,7 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) // CTRL_Entity *thread = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, CTRL_MachineID_Local, event->thread); Architecture arch = thread->arch; - U64 thread_rip_vaddr = dmn_rip_from_thread(event->thread); + U64 thread_rip_vaddr = ctrl_query_cached_rip_from_thread(ctrl_state->ctrl_thread_entity_store, CTRL_MachineID_Local, event->thread); CTRL_Entity *module = &ctrl_entity_nil; { CTRL_Entity *process = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, CTRL_MachineID_Local, event->process); @@ -4593,10 +4604,9 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) machine.arch = arch; machine.memory_read = ctrl_eval_memory_read; machine.reg_size = regs_block_size_from_architecture(arch); - machine.reg_data = push_array(scratch.arena, U8, machine.reg_size); + machine.reg_data = ctrl_query_cached_reg_block_from_thread(scratch.arena, ctrl_state->ctrl_thread_entity_store, CTRL_MachineID_Local, event->thread); machine.module_base = &module_base; machine.tls_base = &tls_base; - dmn_thread_read_reg_block(event->thread, machine.reg_data); eval = eval_interpret(&machine, bytecode); } if(eval.code == EVAL_ResultCode_Good && eval.value.u64 == 0) @@ -4711,7 +4721,7 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) B32 stack_pointer_matches = 0; if(use_trap_net_logic) { - U64 sp = dmn_rsp_from_thread(target_thread); + U64 sp = ctrl_query_cached_rsp_from_thread(ctrl_state->ctrl_thread_entity_store, CTRL_MachineID_Local, target_thread); stack_pointer_matches = (sp == sp_check_value); } @@ -4759,7 +4769,7 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) { // rjf: setup spoof mode begin_spoof_mode = 1; - U64 spoof_sp = dmn_rsp_from_thread(target_thread); + U64 spoof_sp = ctrl_query_cached_rsp_from_thread(ctrl_state->ctrl_thread_entity_store, CTRL_MachineID_Local, target_thread); spoof_mode = 1; spoof.process = target_process; spoof.thread = target_thread; @@ -4777,7 +4787,7 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) if(stack_pointer_matches) { save_stack_pointer = 1; - sp_check_value = dmn_rsp_from_thread(target_thread); + sp_check_value = ctrl_query_cached_rsp_from_thread(ctrl_state->ctrl_thread_entity_store, CTRL_MachineID_Local, target_thread); } } } diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index a5ad6540..40787d1e 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -743,6 +743,7 @@ internal B32 ctrl_process_write(CTRL_MachineID machine_id, DMN_Handle process, R internal void *ctrl_query_cached_reg_block_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle thread); internal U64 ctrl_query_cached_tls_root_vaddr_from_thread(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle thread); internal U64 ctrl_query_cached_rip_from_thread(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle thread); +internal U64 ctrl_query_cached_rsp_from_thread(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle thread); //- rjf: thread register writing internal B32 ctrl_thread_write_reg_block(CTRL_MachineID machine_id, DMN_Handle thread, void *block); diff --git a/src/demon/win32/demon_core_win32.c b/src/demon/win32/demon_core_win32.c index a9179885..1d865093 100644 --- a/src/demon/win32/demon_core_win32.c +++ b/src/demon/win32/demon_core_win32.c @@ -580,6 +580,7 @@ internal B32 dmn_w32_thread_read_reg_block(Architecture arch, HANDLE thread, void *reg_block) { B32 result = 0; + ProfBeginFunction(); switch(arch) { //////////////////////////// @@ -817,6 +818,7 @@ dmn_w32_thread_read_reg_block(Architecture arch, HANDLE thread, void *reg_block) scratch_end(scratch); }break; } + ProfEnd(); return result; } @@ -824,6 +826,7 @@ internal B32 dmn_w32_thread_write_reg_block(Architecture arch, HANDLE thread, void *reg_block) { B32 result = 0; + ProfBeginFunction(); switch(arch) { //////////////////////////// @@ -1050,6 +1053,7 @@ dmn_w32_thread_write_reg_block(Architecture arch, HANDLE thread, void *reg_block }break; } ins_atomic_u64_inc_eval(&dmn_w32_shared->reg_gen); + ProfEnd(); return result; } @@ -1381,6 +1385,34 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) { Temp scratch = scratch_begin(&arena, 1); + ////////////////////////// + //- rjf: get single step thread's context (x64 single-step-set fast path) + // + CONTEXT *single_step_thread_ctx = 0; + if(!dmn_handle_match(ctrls->single_step_thread, dmn_handle_zero())) + { + DMN_W32_Entity *thread = dmn_w32_entity_from_handle(ctrls->single_step_thread); + Architecture arch = thread->arch; + switch(arch) + { + default:{}break; + case Architecture_x64: + { + U32 ctx_flags = DMN_W32_CTX_X64|DMN_W32_CTX_INTEL_CONTROL; + DWORD size = 0; + InitializeContext(0, ctx_flags, 0, &size); + if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + void *ctx_memory = push_array(scratch.arena, U8, size); + if(!InitializeContext(ctx_memory, ctx_flags, &single_step_thread_ctx, &size)) + { + single_step_thread_ctx = 0; + } + } + }break; + } + } + ////////////////////////// //- rjf: set single step bit // @@ -1398,7 +1430,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) case Architecture_arm32: {NotImplemented;}break; - //- rjf: x86/64 + //- rjf: x86 case Architecture_x86: { REGS_RegBlockX86 regs = {0}; @@ -1406,12 +1438,22 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) regs.eflags.u32 |= 0x100; dmn_thread_write_reg_block(ctrls->single_step_thread, ®s); }break; + + //- rjf: x64 case Architecture_x64: { - REGS_RegBlockX64 regs = {0}; - dmn_thread_read_reg_block(ctrls->single_step_thread, ®s); - regs.rflags.u64 |= 0x100; - dmn_thread_write_reg_block(ctrls->single_step_thread, ®s); + if(!GetThreadContext(thread->handle, single_step_thread_ctx)) + { + single_step_thread_ctx = 0; + } + if(single_step_thread_ctx != 0) + { + U64 rflags = single_step_thread_ctx->EFlags|0x2; + U64 new_rflags = rflags |= 0x100; + single_step_thread_ctx->EFlags = new_rflags; + SetThreadContext(thread->handle, single_step_thread_ctx); + ins_atomic_u64_inc_eval(&dmn_w32_shared->reg_gen); + } }break; } } @@ -1983,19 +2025,53 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) B32 should_do_rollback = (hit_user_trap || (is_trap && !hit_explicit_trap)); //- rjf: roll back thread's instruction pointer - U64 post_trap_rip = 0; - if(should_do_rollback) + if(should_do_rollback) ProfScope("roll back thread's instruction pointer") { - Temp temp = temp_begin(scratch.arena); - U64 regs_block_size = regs_block_size_from_architecture(thread->arch); - void *regs_block = push_array(scratch.arena, U8, regs_block_size); - if(dmn_w32_thread_read_reg_block(thread->arch, thread->handle, regs_block)) + switch(thread->arch) { - post_trap_rip = regs_rip_from_arch_block(thread->arch, regs_block); - regs_arch_block_write_rip(thread->arch, regs_block, instruction_pointer); - dmn_w32_thread_write_reg_block(thread->arch, thread->handle, regs_block); + //- rjf: default, general path + default: + { + Temp temp = temp_begin(scratch.arena); + U64 regs_block_size = regs_block_size_from_architecture(thread->arch); + void *regs_block = push_array(scratch.arena, U8, regs_block_size); + if(dmn_w32_thread_read_reg_block(thread->arch, thread->handle, regs_block)) + { + regs_arch_block_write_rip(thread->arch, regs_block, instruction_pointer); + dmn_w32_thread_write_reg_block(thread->arch, thread->handle, regs_block); + } + temp_end(temp); + }break; + + //- rjf: x64 (fastpath) + case Architecture_x64: + { + CONTEXT *ctx = 0; + U32 ctx_flags = DMN_W32_CTX_X64|DMN_W32_CTX_INTEL_CONTROL; + DWORD size = 0; + InitializeContext(0, ctx_flags, 0, &size); + if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + void *ctx_memory = push_array(scratch.arena, U8, size); + if(!InitializeContext(ctx_memory, ctx_flags, &ctx, &size)) + { + ctx = 0; + } + } + if(!GetThreadContext(thread->handle, ctx)) + { + ctx = 0; + } + if(ctx != 0) + { + U64 rip = ctx->Rip; + U64 new_rip = instruction_pointer; + ctx->Rip = new_rip; + SetThreadContext(thread->handle, ctx); + ins_atomic_u64_inc_eval(&dmn_w32_shared->reg_gen); + } + }break; } - temp_end(temp); } //- rjf: not a user trap, not an explicit trap, then it's a trap that @@ -2347,10 +2423,18 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) }break; case Architecture_x64: { - REGS_RegBlockX64 regs = {0}; - dmn_thread_read_reg_block(ctrls->single_step_thread, ®s); - regs.rflags.u64 &= ~0x100; - dmn_thread_write_reg_block(ctrls->single_step_thread, ®s); + if(!GetThreadContext(thread->handle, single_step_thread_ctx)) + { + single_step_thread_ctx = 0; + } + if(ctx != 0) + { + U64 rflags = single_step_thread_ctx->EFlags|0x2; + U64 new_rflags = rflags &= ~0x100; + single_step_thread_ctx->EFlags = new_rflags; + SetThreadContext(thread->handle, single_step_thread_ctx); + ins_atomic_u64_inc_eval(&dmn_w32_shared->reg_gen); + } }break; } } diff --git a/src/demon/win32/demon_core_win32.h b/src/demon/win32/demon_core_win32.h index 285f86be..04c955c8 100644 --- a/src/demon/win32/demon_core_win32.h +++ b/src/demon/win32/demon_core_win32.h @@ -61,11 +61,11 @@ #define DMN_W32_CTX_X86 0x00010000 #define DMN_W32_CTX_X64 0x00100000 -#define DMN_W32_CTX_INTEL_CONTROL 0x0001 -#define DMN_W32_CTX_INTEL_INTEGER 0x0002 -#define DMN_W32_CTX_INTEL_SEGMENTS 0x0004 -#define DMN_W32_CTX_INTEL_FLOATS 0x0008 -#define DMN_W32_CTX_INTEL_DEBUG 0x0010 +#define DMN_W32_CTX_INTEL_CONTROL 0x0001 // segss, rsp, segcs, rip, and rflags +#define DMN_W32_CTX_INTEL_INTEGER 0x0002 // rax, rcx, rdx, rbx, rbp, rsi, rdi, and r8-r15 +#define DMN_W32_CTX_INTEL_SEGMENTS 0x0004 // segds, seges, segfs, and seggs +#define DMN_W32_CTX_INTEL_FLOATS 0x0008 // xmm0-xmm15 +#define DMN_W32_CTX_INTEL_DEBUG 0x0010 // dr0-dr3 and dr6-dr7 #define DMN_W32_CTX_INTEL_EXTENDED 0x0020 #define DMN_W32_CTX_INTEL_XSTATE 0x0040