From 32b90cdccc3168d378969660b80b805cf8efe305 Mon Sep 17 00:00:00 2001 From: _xeroxz Date: Mon, 3 Jan 2022 07:12:04 -0800 Subject: [PATCH] this code sucks so fucking bad, i need to recode everything, its dog shit: --- include/vmemu_t.hpp | 6 +++ src/vmemu_t.cpp | 118 +++++++++++++++++++++++++++++++++----------- 2 files changed, 95 insertions(+), 29 deletions(-) diff --git a/include/vmemu_t.hpp b/include/vmemu_t.hpp index 5dd40c4..1678916 100644 --- a/include/vmemu_t.hpp +++ b/include/vmemu_t.hpp @@ -125,5 +125,11 @@ class emu_t { /// /// bool legit_branch(vm::instrs::vblk_t& vblk, std::uintptr_t branch_addr); + + void emulate_branch(uc_context* ctx, + std::uint8_t* stack, + std::uintptr_t branch_addr, + zydis_reg_t vsp, + vm::instrs::vblk_t& vblk); }; } // namespace vm diff --git a/src/vmemu_t.cpp b/src/vmemu_t.cpp index cd56d41..db7c562 100644 --- a/src/vmemu_t.cpp +++ b/src/vmemu_t.cpp @@ -112,13 +112,58 @@ bool emu_t::emulate(std::uint32_t vmenter_rva, vm::instrs::vrtn_t& vrtn) { blk.branch_type = vm::instrs::vbranch_type::jcc; std::printf("> code block has jcc, b1 = %p, b2 = %p\n", b1, b2); } else { + uc_context* backup; + std::uint8_t* stack = new std::uint8_t[STACK_SIZE]; + uc_mem_read(uc, STACK_BASE, stack, STACK_SIZE); + uc_context_alloc(uc, &backup); + uc_context_save(uc, backup); + uc_context_restore(uc, blk.m_jmp.ctx); + + std::uintptr_t vsp_ptr = 0ull, branch_addr = 0ull; + uc_reg_read(uc, vm::instrs::reg_map[blk.m_vm.vsp], &vsp_ptr); + uc_mem_read(uc, vsp_ptr, &branch_addr, sizeof branch_addr); + + uc_context_restore(uc, backup); + uc_context_free(backup); + uc_mem_write(uc, STACK_BASE, stack, STACK_SIZE); + delete stack; + + blk.branches.push_back(branch_addr); blk.branch_type = vm::instrs::vbranch_type::absolute; - std::printf("> code block has absolute jmp...\n"); + std::printf("> code block has absolute jmp, b1 = %p\n", branch_addr); } } return true; } +void emu_t::emulate_branch(uc_context* ctx, + std::uint8_t* stack, + std::uintptr_t branch_addr, + zydis_reg_t vsp, + vm::instrs::vblk_t& vblk) { + uc_context* backup; + std::uint8_t* stack_backup = new std::uint8_t[STACK_SIZE]; + std::uintptr_t vsp_addr = 0ull, rip = 0ull; + + uc_context_alloc(uc, &backup); + uc_context_save(uc, backup); + uc_mem_read(uc, STACK_BASE, stack_backup, STACK_SIZE); + + uc_context_restore(uc, ctx); + uc_mem_write(uc, STACK_BASE, stack, STACK_SIZE); + uc_reg_read(uc, vm::instrs::reg_map[vsp], &vsp_addr); + uc_reg_read(uc, UC_X86_REG_RIP, &rip); + uc_mem_write(uc, vsp_addr, &branch_addr, sizeof branch_addr); + + cc_blk = &vblk; + uc_emu_start(uc, rip, 0u, 0u, 0u); + + uc_mem_write(uc, STACK_BASE, stack_backup, STACK_SIZE); + uc_context_restore(uc, backup); + uc_context_free(backup); + delete stack_backup; +} + void emu_t::int_callback(uc_engine* uc, std::uint32_t intno, emu_t* obj) { uc_err err; std::uintptr_t rip = 0ull; @@ -342,36 +387,38 @@ bool emu_t::code_exec_callback(uc_engine* uc, std::getchar(); } + if (obj->cc_blk->m_vinstrs.size()) { + if (vinstr.mnemonic == vm::instrs::mnemonic_t::jmp) { + uc_context *backup, *copy; + + // backup current unicorn-engine context... + uc_context_alloc(uc, &backup); + uc_context_alloc(uc, ©); + uc_context_save(uc, backup); + + // make a copy of the first cpu context of the jmp handler... + uc_context_restore(uc, obj->cc_trace.m_instrs.begin()->m_cpu); + uc_context_save(uc, copy); + + // restore the unicorn-engine context... also free the backup... + uc_context_restore(uc, backup); + uc_context_free(backup); + + // set current code block virtual jmp instruction information... + obj->cc_blk->m_jmp.ctx = copy; + obj->cc_blk->m_jmp.stack = new std::uint8_t[STACK_SIZE]; + std::memcpy(obj->cc_blk->m_jmp.stack, obj->cc_trace.m_stack, + STACK_SIZE); + } + + if (vinstr.mnemonic == vm::instrs::mnemonic_t::jmp || + vinstr.mnemonic == vm::instrs::mnemonic_t::vmexit) + uc_emu_stop(obj->uc); + } + obj->cc_trace.m_vip = obj->vip; obj->cc_trace.m_vsp = obj->vsp; obj->cc_blk->m_vinstrs.push_back(vinstr); - - if (vinstr.mnemonic == vm::instrs::mnemonic_t::jmp) { - uc_context *backup, *copy; - - // backup current unicorn-engine context... - uc_context_alloc(uc, &backup); - uc_context_alloc(uc, ©); - uc_context_save(uc, backup); - - // make a copy of the first cpu context of the jmp handler... - uc_context_restore(uc, obj->cc_trace.m_instrs.begin()->m_cpu); - uc_context_save(uc, copy); - - // restore the unicorn-engine context... also free the backup... - uc_context_restore(uc, backup); - uc_context_free(backup); - - // set current code block virtual jmp instruction information... - obj->cc_blk->m_jmp.ctx = copy; - obj->cc_blk->m_jmp.stack = new std::uint8_t[STACK_SIZE]; - std::memcpy(obj->cc_blk->m_jmp.stack, obj->cc_trace.m_stack, - STACK_SIZE); - } - - if (vinstr.mnemonic == vm::instrs::mnemonic_t::jmp || - vinstr.mnemonic == vm::instrs::mnemonic_t::vmexit) - uc_emu_stop(obj->uc); } // -- free the trace since we will start a new one... @@ -434,7 +481,14 @@ bool emu_t::legit_branch(vm::instrs::vblk_t& vblk, std::uintptr_t branch_addr) { (void*)&vm::emu_t::branch_pred_spec_exec, this, m_vm->m_module_base, m_vm->m_module_base + m_vm->m_image_size); - // restore cpu and stack... + // -- make a backup of the current emulation state... + uc_context* backup; + uc_context_alloc(uc, &backup); + uc_context_save(uc, backup); + std::uint8_t* stack = new std::uint8_t[STACK_SIZE]; + uc_mem_read(uc, STACK_BASE, stack, STACK_SIZE); + + // restore cpu and stack back to the virtual jump handler... uc_context_restore(uc, vblk.m_jmp.ctx); uc_mem_write(uc, STACK_BASE, vblk.m_jmp.stack, STACK_SIZE); @@ -446,6 +500,12 @@ bool emu_t::legit_branch(vm::instrs::vblk_t& vblk, std::uintptr_t branch_addr) { m_sreg_cnt = 0u; uc_emu_start(uc, rip, 0ull, 0ull, 0ull); + // -- restore original cpu and stack... + uc_mem_write(uc, STACK_BASE, stack, STACK_SIZE); + uc_context_restore(uc, backup); + uc_context_free(backup); + delete stack; + // add normal execution callback back... uc_hook_add(uc, &code_exec_hook, UC_HOOK_CODE, (void*)&vm::emu_t::code_exec_callback, this, m_vm->m_module_base,