diff --git a/include/vmemu_t.hpp b/include/vmemu_t.hpp
index 72666b9..a427c26 100644
--- a/include/vmemu_t.hpp
+++ b/include/vmemu_t.hpp
@@ -124,5 +124,10 @@ class emu_t {
///
///
bool legit_branch(vm::instrs::vblk_t& vblk, std::uintptr_t branch_addr);
+
+ ///
+ /// extracts the current code blocks branch data...
+ ///
+ void extract_branch_data();
};
} // namespace vm
diff --git a/src/vmemu_t.cpp b/src/vmemu_t.cpp
index 39fda60..91d8748 100644
--- a/src/vmemu_t.cpp
+++ b/src/vmemu_t.cpp
@@ -92,38 +92,8 @@ bool emu_t::emulate(std::uint32_t vmenter_rva, vm::instrs::vrtn_t& vrtn) {
return false;
}
- auto br_info = could_have_jcc(cc_blk->m_vinstrs);
- if (br_info.has_value()) {
- auto [br1, br2] = br_info.value();
-
- // convert to absolute addresses...
- br1 -= m_vm->m_image_base;
- br2 -= m_vm->m_image_base;
- br1 += m_vm->m_module_base;
- br2 += m_vm->m_module_base;
-
- auto br1_legit = legit_branch(*cc_blk, br1);
- auto br2_legit = legit_branch(*cc_blk, br2);
- std::printf("> br1 legit: %d, br2 legit: %d\n", br1_legit, br2_legit);
-
- if (br1_legit && br2_legit) {
- std::printf("> virtual jcc uncovered... br1 = %p, br2 = %p\n", br1, br2);
- cc_blk->branch_type = vm::instrs::vbranch_type::jcc;
- cc_blk->branches.push_back(br1);
- cc_blk->branches.push_back(br2);
- } else if (br1_legit || br2_legit) {
- std::printf("> absolute virtual jmp uncovered... branch = %p\n",
- br1_legit ? br1 : br2);
- cc_blk->branch_type = vm::instrs::vbranch_type::absolute;
- cc_blk->branches.push_back(br1_legit ? br1 : br2);
- } else {
- std::printf("> unknown branch type...\n");
- return false;
- }
- } else if (cc_blk->m_vinstrs.back().mnemonic ==
- vm::instrs::mnemonic_t::vmexit) {
- cc_blk->branch_type = vm::instrs::vbranch_type::none;
- }
+ extract_branch_data();
+ std::printf("> emulated blk_%p\n\n", cc_blk->m_vip.img_base);
// keep track of the emulated blocks... by their addresses...
std::vector blk_addrs;
@@ -134,11 +104,6 @@ bool emu_t::emulate(std::uint32_t vmenter_rva, vm::instrs::vrtn_t& vrtn) {
for (auto idx = 0u; idx < cc_vrtn->m_blks.size(); ++idx) {
vm::instrs::vblk_t blk = cc_vrtn->m_blks[idx];
if (blk.branch_type != vm::instrs::vbranch_type::none) {
- std::uintptr_t vsp = 0ull;
- uc_context_restore(uc, blk.m_jmp.ctx);
- uc_mem_write(uc, STACK_BASE, blk.m_jmp.stack, STACK_SIZE);
- uc_reg_read(uc, vm::instrs::reg_map[blk.m_vm.vsp], &vsp);
-
// force the emulation of all branches...
for (const auto br : blk.branches) {
// only emulate blocks that havent been emulated before...
@@ -146,6 +111,11 @@ bool emu_t::emulate(std::uint32_t vmenter_rva, vm::instrs::vrtn_t& vrtn) {
blk_addrs.end())
continue;
+ std::uintptr_t vsp = 0ull;
+ uc_context_restore(uc, blk.m_jmp.ctx);
+ uc_mem_write(uc, STACK_BASE, blk.m_jmp.stack, STACK_SIZE);
+ uc_reg_read(uc, vm::instrs::reg_map[blk.m_vm.vsp], &vsp);
+
// setup new cc_blk...
auto& new_blk = vrtn.m_blks.emplace_back();
new_blk.m_vip = {0ull, 0ull};
@@ -154,41 +124,14 @@ bool emu_t::emulate(std::uint32_t vmenter_rva, vm::instrs::vrtn_t& vrtn) {
// emulate the branch...
uc_mem_write(uc, vsp, &br, sizeof br);
- uc_emu_start(uc, blk.m_jmp.rip, 0ull, 0ull, 0ull);
-
- auto br_info = could_have_jcc(cc_blk->m_vinstrs);
- if (br_info.has_value()) {
- auto [br1, br2] = br_info.value();
-
- // convert to absolute addresses...
- br1 -= m_vm->m_image_base;
- br2 -= m_vm->m_image_base;
- br1 += m_vm->m_module_base;
- br2 += m_vm->m_module_base;
-
- auto br1_legit = legit_branch(*cc_blk, br1);
- auto br2_legit = legit_branch(*cc_blk, br2);
- std::printf("> br1 legit: %d, br2 legit: %d\n", br1_legit, br2_legit);
-
- if (br1_legit && br2_legit) {
- std::printf("> virtual jcc uncovered... br1 = %p, br2 = %p\n", br1,
- br2);
- cc_blk->branch_type = vm::instrs::vbranch_type::jcc;
- cc_blk->branches.push_back(br1);
- cc_blk->branches.push_back(br2);
- } else if (br1_legit || br2_legit) {
- std::printf("> absolute virtual jmp uncovered... branch = %p\n",
- br1_legit ? br1 : br2);
- cc_blk->branch_type = vm::instrs::vbranch_type::absolute;
- cc_blk->branches.push_back(br1_legit ? br1 : br2);
- } else {
- std::printf("> unknown branch type...\n");
- return false;
- }
- } else if (cc_blk->m_vinstrs.back().mnemonic ==
- vm::instrs::mnemonic_t::vmexit) {
- cc_blk->branch_type = vm::instrs::vbranch_type::none;
+ std::printf("> beginning execution at = %p\n", blk.m_jmp.rip);
+ if ((err = uc_emu_start(uc, blk.m_jmp.rip, 0ull, 0ull, 0ull))) {
+ std::printf("> error starting emu... reason = %d\n", err);
+ return false;
}
+
+ extract_branch_data();
+ std::printf("> emulated blk_%p\n", cc_blk->m_vip.img_base);
}
}
}
@@ -206,6 +149,65 @@ bool emu_t::emulate(std::uint32_t vmenter_rva, vm::instrs::vrtn_t& vrtn) {
return true;
}
+void emu_t::extract_branch_data() {
+ auto br_info = could_have_jcc(cc_blk->m_vinstrs);
+ if (br_info.has_value()) {
+ auto [br1, br2] = br_info.value();
+ // convert to absolute addresses...
+ br1 -= m_vm->m_image_base;
+ br2 -= m_vm->m_image_base;
+ br1 += m_vm->m_module_base;
+ br2 += m_vm->m_module_base;
+
+ auto br1_legit = legit_branch(*cc_blk, br1);
+ auto br2_legit = legit_branch(*cc_blk, br2);
+ std::printf("> br1 legit: %d, br2 legit: %d\n", br1_legit, br2_legit);
+
+ if (br1_legit && br2_legit) {
+ std::printf("> virtual jcc uncovered... br1 = %p, br2 = %p\n", br1, br2);
+ cc_blk->branch_type = vm::instrs::vbranch_type::jcc;
+ cc_blk->branches.push_back(br1);
+ cc_blk->branches.push_back(br2);
+ } else if (br1_legit || br2_legit) {
+ std::printf("> absolute virtual jmp uncovered... branch = %p\n",
+ br1_legit ? br1 : br2);
+ cc_blk->branch_type = vm::instrs::vbranch_type::absolute;
+ cc_blk->branches.push_back(br1_legit ? br1 : br2);
+ } else {
+ std::printf("> unknown branch type...\n");
+ }
+ } else if (cc_blk->m_vinstrs.back().mnemonic ==
+ vm::instrs::mnemonic_t::vmexit) {
+ cc_blk->branch_type = vm::instrs::vbranch_type::none;
+ } else if (cc_blk->m_vinstrs.back().mnemonic == vm::instrs::mnemonic_t::jmp) {
+ // see if there is 1 lconst...
+ if (auto last_lconst = std::find_if(
+ cc_blk->m_vinstrs.rbegin(), cc_blk->m_vinstrs.rend(),
+ [&](vm::instrs::vinstr_t& vinstr) -> bool {
+ return vinstr.mnemonic == vm::instrs::mnemonic_t::lconst &&
+ vinstr.imm.size == 64;
+ });
+ last_lconst != cc_blk->m_vinstrs.rend()) {
+ const auto imm_img_based = last_lconst->imm.val;
+ const auto imm_mod_based =
+ (imm_img_based - m_vm->m_image_base) + m_vm->m_module_base;
+
+ // check to see if the imm is inside of the module... and if the ptr lands
+ // inside of an executable section... then lastly check to see if its a
+ // legit branch or not...
+ if (imm_img_based >= m_vm->m_image_base &&
+ imm_img_based < m_vm->m_image_base + m_vm->m_image_size &&
+ vm::utils::scn::executable(m_vm->m_module_base, imm_mod_based)) {
+ cc_blk->branches.push_back(imm_mod_based);
+ cc_blk->branch_type = vm::instrs::vbranch_type::absolute;
+ }
+ } else {
+ std::printf("> jump table detected... review instruction stream...\n");
+ uc_emu_stop(uc);
+ }
+ }
+}
+
void emu_t::int_callback(uc_engine* uc, std::uint32_t intno, emu_t* obj) {
uc_err err;
std::uintptr_t rip = 0ull;
@@ -395,13 +397,10 @@ bool emu_t::code_exec_callback(uc_engine* uc,
uc_context* backup;
uc_context_alloc(uc, &backup);
uc_context_save(uc, backup);
- uc_context_restore(uc, vip_write->m_cpu);
-
- auto uc_reg =
- vm::instrs::reg_map[vip_write->m_instr.operands[0].reg.value];
+ uc_context_restore(uc, (--vip_write)->m_cpu);
std::uintptr_t vip_addr = 0ull;
- uc_reg_read(uc, uc_reg, &vip_addr);
+ uc_reg_read(uc, vm::instrs::reg_map[obj->cc_trace.m_vip], &vip_addr);
obj->cc_blk->m_vip.rva = vip_addr -= obj->m_vm->m_module_base;
obj->cc_blk->m_vip.img_base = vip_addr += obj->m_vm->m_image_base;