updated vmprofiler dep, vmemu can handle some virtual branching now...

main
_xeroxz 3 years ago
parent 4918ed0a38
commit 507929bbb1

2
deps/vmprofiler vendored

@ -1 +1 @@
Subproject commit b88c7b9321ea64989666ac19534d425b40369c6f Subproject commit 1b2b79e3e91916da08179663d672634db7c35d4c

@ -105,22 +105,39 @@ bool emu_t::emulate(std::uint32_t vmenter_rva, vm::instrs::vrtn_t& vrtn) {
auto br1_legit = legit_branch(*cc_blk, br1); auto br1_legit = legit_branch(*cc_blk, br1);
auto br2_legit = legit_branch(*cc_blk, br2); auto br2_legit = legit_branch(*cc_blk, br2);
std::printf("> br1 legit: %d, br2 legit: %d\n", br1_legit, br2_legit); 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;
} }
// keep track of the emulated blocks... by their addresses... // keep track of the emulated blocks... by their addresses...
std::vector<std::uintptr_t> blk_addrs; std::vector<std::uintptr_t> blk_addrs;
blk_addrs.push_back(blk.m_vip.img_base); blk_addrs.push_back(blk.m_vip.rva + m_vm->m_module_base);
// the vector containing the vblk's grows inside of this for loop // the vector containing the vblk's grows inside of this for loop
// thus we cannot use an advanced for loop (which uses itr's)... // thus we cannot use an advanced for loop (which uses itr's)...
for (auto idx = 0u; idx < cc_vrtn->m_blks.size(); ++idx) { for (auto idx = 0u; idx < cc_vrtn->m_blks.size(); ++idx) {
auto& blk = cc_vrtn->m_blks[idx]; vm::instrs::vblk_t blk = cc_vrtn->m_blks[idx];
if (blk.branch_type != vm::instrs::vbranch_type::none) { if (blk.branch_type != vm::instrs::vbranch_type::none) {
std::uintptr_t rip = 0ull, vsp = 0ull; std::uintptr_t vsp = 0ull;
uc_context_restore(uc, blk.m_jmp.ctx); uc_context_restore(uc, blk.m_jmp.ctx);
uc_mem_write(uc, STACK_BASE, blk.m_jmp.stack, STACK_SIZE); 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); uc_reg_read(uc, vm::instrs::reg_map[blk.m_vm.vsp], &vsp);
uc_reg_read(uc, UC_X86_REG_RIP, &rip);
// force the emulation of all branches... // force the emulation of all branches...
for (const auto br : blk.branches) { for (const auto br : blk.branches) {
@ -137,7 +154,41 @@ bool emu_t::emulate(std::uint32_t vmenter_rva, vm::instrs::vrtn_t& vrtn) {
// emulate the branch... // emulate the branch...
uc_mem_write(uc, vsp, &br, sizeof br); uc_mem_write(uc, vsp, &br, sizeof br);
uc_emu_start(uc, rip, 0ull, 0ull, 0ull); 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;
}
} }
} }
} }
@ -299,6 +350,7 @@ bool emu_t::code_exec_callback(uc_engine* uc,
// if this is the first instruction of this handler then save the stack... // if this is the first instruction of this handler then save the stack...
if (!obj->cc_trace.m_instrs.size()) { if (!obj->cc_trace.m_instrs.size()) {
obj->cc_trace.m_stack = new std::uint8_t[STACK_SIZE]; obj->cc_trace.m_stack = new std::uint8_t[STACK_SIZE];
obj->cc_trace.m_begin = address;
uc_mem_read(uc, STACK_BASE, obj->cc_trace.m_stack, STACK_SIZE); uc_mem_read(uc, STACK_BASE, obj->cc_trace.m_stack, STACK_SIZE);
} }
@ -374,8 +426,13 @@ bool emu_t::code_exec_callback(uc_engine* uc,
inst_stream.push_back({instr.m_instr}); inst_stream.push_back({instr.m_instr});
}); });
std::printf("> err: please define the following vm handler:\n"); std::printf(
"> err: please define the following vm handler (at = %p):\n",
(obj->cc_trace.m_begin - obj->m_vm->m_module_base) +
obj->m_vm->m_image_base);
vm::utils::print(inst_stream); vm::utils::print(inst_stream);
uc_emu_stop(uc);
return false; return false;
} }
@ -398,6 +455,7 @@ bool emu_t::code_exec_callback(uc_engine* uc,
// set current code block virtual jmp instruction information... // set current code block virtual jmp instruction information...
obj->cc_blk->m_jmp.ctx = copy; obj->cc_blk->m_jmp.ctx = copy;
obj->cc_blk->m_jmp.rip = obj->cc_trace.m_begin;
obj->cc_blk->m_jmp.stack = new std::uint8_t[STACK_SIZE]; obj->cc_blk->m_jmp.stack = new std::uint8_t[STACK_SIZE];
obj->cc_blk->m_jmp.m_vm = {obj->cc_trace.m_vip, obj->cc_trace.m_vsp}; obj->cc_blk->m_jmp.m_vm = {obj->cc_trace.m_vip, obj->cc_trace.m_vsp};
std::memcpy(obj->cc_blk->m_jmp.stack, obj->cc_trace.m_stack, std::memcpy(obj->cc_blk->m_jmp.stack, obj->cc_trace.m_stack,
@ -433,29 +491,13 @@ void emu_t::invalid_mem(uc_engine* uc,
switch (type) { switch (type) {
case UC_MEM_READ_UNMAPPED: { case UC_MEM_READ_UNMAPPED: {
uc_mem_map(uc, address & ~0xFFFull, PAGE_4KB, UC_PROT_ALL); uc_mem_map(uc, address & ~0xFFFull, PAGE_4KB, UC_PROT_ALL);
std::printf(">>> reading invalid memory at address = %p, size = 0x%x\n",
address, size);
break; break;
} }
case UC_MEM_WRITE_UNMAPPED: { case UC_MEM_WRITE_UNMAPPED: {
uc_mem_map(uc, address & ~0xFFFull, PAGE_4KB, UC_PROT_ALL); uc_mem_map(uc, address & ~0xFFFull, PAGE_4KB, UC_PROT_ALL);
std::printf(
">>> writing invalid memory at address = %p, size = 0x%x, val = "
"0x%x\n",
address, size, value);
break; break;
} }
case UC_MEM_FETCH_UNMAPPED: { case UC_MEM_FETCH_UNMAPPED: {
std::printf(">>> fetching invalid instructions at address = %p\n",
address);
std::uintptr_t rip, rsp;
uc_reg_read(uc, UC_X86_REG_RSP, &rsp);
uc_mem_read(uc, rsp, &rip, sizeof rip);
rsp += 8;
uc_reg_write(uc, UC_X86_REG_RSP, &rsp);
uc_reg_write(uc, UC_X86_REG_RIP, &rip);
std::printf(">>> injecting return to try and recover... rip = %p\n", rip);
break; break;
} }
default: default:
@ -499,6 +541,7 @@ bool emu_t::legit_branch(vm::instrs::vblk_t& vblk, std::uintptr_t branch_addr) {
delete[] stack; delete[] stack;
// add normal execution callback back... // add normal execution callback back...
uc_hook_del(uc, branch_pred_hook);
uc_hook_add(uc, &code_exec_hook, UC_HOOK_CODE, uc_hook_add(uc, &code_exec_hook, UC_HOOK_CODE,
(void*)&vm::emu_t::code_exec_callback, this, m_vm->m_module_base, (void*)&vm::emu_t::code_exec_callback, this, m_vm->m_module_base,
m_vm->m_module_base + m_vm->m_image_size); m_vm->m_module_base + m_vm->m_image_size);

Loading…
Cancel
Save