diff --git a/CMakeLists.txt b/CMakeLists.txt
index f06b06f..bad5164 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -54,6 +54,8 @@ list(APPEND vmprofiler_SOURCES
"src/vminstrs.cpp"
"src/vmlocate.cpp"
"src/vmprofiles/jmp.cpp"
+ "src/vmprofiles/lconst.cpp"
+ "src/vmprofiles/lreg.cpp"
"src/vmprofiles/sreg.cpp"
"src/vmutils.cpp"
"include/vmctx.hpp"
diff --git a/include/vminstrs.hpp b/include/vminstrs.hpp
index 31dc534..30f541f 100644
--- a/include/vminstrs.hpp
+++ b/include/vminstrs.hpp
@@ -50,7 +50,7 @@ struct vinstr_t {
/// "64" here...where the SREGDW varient would have a "32" here... this is the
/// stack disposition essentially, or the value on the stack...
///
- u8 size;
+ u8 stack_size;
struct {
///
@@ -84,6 +84,7 @@ struct emu_instr_t {
///
struct hndlr_trace_t {
std::uintptr_t m_hndlr_addr;
+ uc_engine* m_uc;
zydis_reg_t m_vip, m_vsp;
std::vector m_instrs;
};
@@ -137,11 +138,86 @@ struct profiler_t {
///
extern profiler_t jmp;
extern profiler_t sreg;
+extern profiler_t lreg;
+extern profiler_t lconst;
///
/// unsorted vector of profiles... they get sorted once at runtime...
///
-inline std::vector profiles = {&jmp, &sreg};
+inline std::vector profiles = {&jmp, &sreg, &lreg, &lconst};
+
+///
+/// no i did not make this by hand, you cannot clown upon me!
+///
+inline std::map reg_map = {
+ {ZYDIS_REGISTER_AL, UC_X86_REG_AL},
+ {ZYDIS_REGISTER_CL, UC_X86_REG_CL},
+ {ZYDIS_REGISTER_DL, UC_X86_REG_DL},
+ {ZYDIS_REGISTER_BL, UC_X86_REG_BL},
+ {ZYDIS_REGISTER_AH, UC_X86_REG_AH},
+ {ZYDIS_REGISTER_CH, UC_X86_REG_CH},
+ {ZYDIS_REGISTER_DH, UC_X86_REG_DH},
+ {ZYDIS_REGISTER_BH, UC_X86_REG_BH},
+ {ZYDIS_REGISTER_SPL, UC_X86_REG_SPL},
+ {ZYDIS_REGISTER_BPL, UC_X86_REG_BPL},
+ {ZYDIS_REGISTER_SIL, UC_X86_REG_SIL},
+ {ZYDIS_REGISTER_DIL, UC_X86_REG_DIL},
+ {ZYDIS_REGISTER_R8B, UC_X86_REG_R8B},
+ {ZYDIS_REGISTER_R9B, UC_X86_REG_R9B},
+ {ZYDIS_REGISTER_R10B, UC_X86_REG_R10B},
+ {ZYDIS_REGISTER_R11B, UC_X86_REG_R11B},
+ {ZYDIS_REGISTER_R12B, UC_X86_REG_R12B},
+ {ZYDIS_REGISTER_R13B, UC_X86_REG_R13B},
+ {ZYDIS_REGISTER_R14B, UC_X86_REG_R14B},
+ {ZYDIS_REGISTER_R15B, UC_X86_REG_R15B},
+ {ZYDIS_REGISTER_AX, UC_X86_REG_AX},
+ {ZYDIS_REGISTER_CX, UC_X86_REG_CX},
+ {ZYDIS_REGISTER_DX, UC_X86_REG_DX},
+ {ZYDIS_REGISTER_BX, UC_X86_REG_BX},
+ {ZYDIS_REGISTER_SP, UC_X86_REG_SP},
+ {ZYDIS_REGISTER_BP, UC_X86_REG_BP},
+ {ZYDIS_REGISTER_SI, UC_X86_REG_SI},
+ {ZYDIS_REGISTER_DI, UC_X86_REG_DI},
+ {ZYDIS_REGISTER_R8W, UC_X86_REG_R8W},
+ {ZYDIS_REGISTER_R9W, UC_X86_REG_R9W},
+ {ZYDIS_REGISTER_R10W, UC_X86_REG_R10W},
+ {ZYDIS_REGISTER_R11W, UC_X86_REG_R11W},
+ {ZYDIS_REGISTER_R12W, UC_X86_REG_R12W},
+ {ZYDIS_REGISTER_R13W, UC_X86_REG_R13W},
+ {ZYDIS_REGISTER_R14W, UC_X86_REG_R14W},
+ {ZYDIS_REGISTER_R15W, UC_X86_REG_R15W},
+ {ZYDIS_REGISTER_EAX, UC_X86_REG_EAX},
+ {ZYDIS_REGISTER_ECX, UC_X86_REG_ECX},
+ {ZYDIS_REGISTER_EDX, UC_X86_REG_EDX},
+ {ZYDIS_REGISTER_EBX, UC_X86_REG_EBX},
+ {ZYDIS_REGISTER_ESP, UC_X86_REG_ESP},
+ {ZYDIS_REGISTER_EBP, UC_X86_REG_EBP},
+ {ZYDIS_REGISTER_ESI, UC_X86_REG_ESI},
+ {ZYDIS_REGISTER_EDI, UC_X86_REG_EDI},
+ {ZYDIS_REGISTER_R8D, UC_X86_REG_R8D},
+ {ZYDIS_REGISTER_R9D, UC_X86_REG_R9D},
+ {ZYDIS_REGISTER_R10D, UC_X86_REG_R10D},
+ {ZYDIS_REGISTER_R11D, UC_X86_REG_R11D},
+ {ZYDIS_REGISTER_R12D, UC_X86_REG_R12D},
+ {ZYDIS_REGISTER_R13D, UC_X86_REG_R13D},
+ {ZYDIS_REGISTER_R14D, UC_X86_REG_R14D},
+ {ZYDIS_REGISTER_R15D, UC_X86_REG_R15D},
+ {ZYDIS_REGISTER_RAX, UC_X86_REG_RAX},
+ {ZYDIS_REGISTER_RCX, UC_X86_REG_RCX},
+ {ZYDIS_REGISTER_RDX, UC_X86_REG_RDX},
+ {ZYDIS_REGISTER_RBX, UC_X86_REG_RBX},
+ {ZYDIS_REGISTER_RSP, UC_X86_REG_RSP},
+ {ZYDIS_REGISTER_RBP, UC_X86_REG_RBP},
+ {ZYDIS_REGISTER_RSI, UC_X86_REG_RSI},
+ {ZYDIS_REGISTER_RDI, UC_X86_REG_RDI},
+ {ZYDIS_REGISTER_R8, UC_X86_REG_R8},
+ {ZYDIS_REGISTER_R9, UC_X86_REG_R9},
+ {ZYDIS_REGISTER_R10, UC_X86_REG_R10},
+ {ZYDIS_REGISTER_R11, UC_X86_REG_R11},
+ {ZYDIS_REGISTER_R12, UC_X86_REG_R12},
+ {ZYDIS_REGISTER_R13, UC_X86_REG_R13},
+ {ZYDIS_REGISTER_R14, UC_X86_REG_R14},
+ {ZYDIS_REGISTER_R15, UC_X86_REG_R15}};
///
/// deadstore and opaque branch removal from unicorn engine trace... this is the
diff --git a/include/vmutils.hpp b/include/vmutils.hpp
index 32c31f8..7c8835f 100644
--- a/include/vmutils.hpp
+++ b/include/vmutils.hpp
@@ -68,6 +68,13 @@ inline bool open_binary_file(const std::string& file,
///
bool is_jmp(const zydis_decoded_instr_t& instr);
+///
+/// used by profiles to see if an instruction is a MOV/SX/ZX...
+///
+///
+///
+bool is_mov(const zydis_decoded_instr_t& instr);
+
///
/// prints a disassembly view of a routine...
///
diff --git a/src/vmprofiles/jmp.cpp b/src/vmprofiles/jmp.cpp
index ef92654..b1d283f 100644
--- a/src/vmprofiles/jmp.cpp
+++ b/src/vmprofiles/jmp.cpp
@@ -123,6 +123,10 @@ profiler_t jmp = {
if (mov_reg_vsp != instrs.end())
vsp = mov_reg_vsp->m_instr.operands[0].reg.value;
}
- return vinstr_t{mnemonic_t::jmp};
+
+ vinstr_t res;
+ memset(&res, NULL, sizeof vinstr_t);
+ res.mnemonic = mnemonic_t::jmp;
+ return res;
}};
}
\ No newline at end of file
diff --git a/src/vmprofiles/lconst.cpp b/src/vmprofiles/lconst.cpp
new file mode 100644
index 0000000..d8b0acb
--- /dev/null
+++ b/src/vmprofiles/lconst.cpp
@@ -0,0 +1,86 @@
+#include
+
+namespace vm::instrs {
+profiler_t lconst = {
+ "LCONST",
+ mnemonic_t::lconst,
+ {{// MOV REG, [VIP]
+ [&](const zydis_reg_t vip,
+ const zydis_reg_t vsp,
+ const zydis_decoded_instr_t& instr) -> bool {
+ return vm::utils::is_mov(instr) &&
+ instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
+ instr.operands[1].type == ZYDIS_OPERAND_TYPE_MEMORY &&
+ instr.operands[1].mem.base == vip;
+ },
+ // SUB VSP, OFFSET
+ [&](const zydis_reg_t vip,
+ const zydis_reg_t vsp,
+ const zydis_decoded_instr_t& instr) -> bool {
+ return instr.mnemonic == ZYDIS_MNEMONIC_SUB &&
+ instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
+ instr.operands[0].reg.value == vsp &&
+ instr.operands[1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE;
+ },
+ // MOV [VSP], REG
+ [&](const zydis_reg_t vip,
+ const zydis_reg_t vsp,
+ const zydis_decoded_instr_t& instr) -> bool {
+ return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
+ instr.operands[0].type == ZYDIS_OPERAND_TYPE_MEMORY &&
+ instr.operands[0].mem.base == vsp &&
+ instr.operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER;
+ }}},
+ [&](zydis_reg_t& vip,
+ zydis_reg_t& vsp,
+ hndlr_trace_t& hndlr) -> std::optional {
+ vinstr_t res;
+ res.mnemonic = mnemonic_t::lconst;
+ res.imm.has_imm = true;
+
+ const auto sub_vsp = std::find_if(
+ hndlr.m_instrs.begin(), hndlr.m_instrs.end(),
+ [&](emu_instr_t& instr) -> bool {
+ const auto& i = instr.m_instr;
+ return i.mnemonic == ZYDIS_MNEMONIC_SUB &&
+ i.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
+ i.operands[0].reg.value == vsp &&
+ i.operands[1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE;
+ });
+
+ res.stack_size = sub_vsp->m_instr.operands[1].imm.value.u * 8;
+ const auto fetch_imm = std::find_if(
+ hndlr.m_instrs.begin(), hndlr.m_instrs.end(),
+ [&](emu_instr_t& instr) -> bool {
+ const auto& i = instr.m_instr;
+ return vm::utils::is_mov(i) &&
+ i.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
+ i.operands[1].type == ZYDIS_OPERAND_TYPE_MEMORY &&
+ i.operands[1].mem.base == vip;
+ });
+
+ res.imm.size = fetch_imm->m_instr.operands[1].size;
+ const auto mov_vsp_imm = std::find_if(
+ hndlr.m_instrs.begin(), hndlr.m_instrs.end(),
+ [&](emu_instr_t& instr) -> bool {
+ const auto& i = instr.m_instr;
+ return i.mnemonic == ZYDIS_MNEMONIC_MOV &&
+ i.operands[0].type == ZYDIS_OPERAND_TYPE_MEMORY &&
+ i.operands[0].mem.base == vsp &&
+ i.operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER;
+ });
+
+ uc_context* backup;
+ uc_context_alloc(hndlr.m_uc, &backup);
+ uc_context_save(hndlr.m_uc, backup);
+ uc_context_restore(hndlr.m_uc, mov_vsp_imm->m_cpu);
+
+ const uc_x86_reg imm_reg =
+ vm::instrs::reg_map[mov_vsp_imm->m_instr.operands[1].reg.value];
+
+ uc_reg_read(hndlr.m_uc, imm_reg, &res.imm.val);
+ uc_context_restore(hndlr.m_uc, backup);
+ uc_context_free(backup);
+ return res;
+ }};
+}
\ No newline at end of file
diff --git a/src/vmprofiles/lreg.cpp b/src/vmprofiles/lreg.cpp
new file mode 100644
index 0000000..8bf0d63
--- /dev/null
+++ b/src/vmprofiles/lreg.cpp
@@ -0,0 +1,89 @@
+#include
+
+namespace vm::instrs {
+profiler_t lreg = {
+ "LREG",
+ mnemonic_t::lreg,
+ {{// MOV REG, [VIP]
+ [&](const zydis_reg_t vip,
+ const zydis_reg_t vsp,
+ const zydis_decoded_instr_t& instr) -> bool {
+ return vm::utils::is_mov(instr) &&
+ instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
+ instr.operands[1].type == ZYDIS_OPERAND_TYPE_MEMORY &&
+ instr.operands[1].mem.base == vip;
+ },
+ // MOV REG, [RSP+REG]
+ [&](const zydis_reg_t vip,
+ const zydis_reg_t vsp,
+ const zydis_decoded_instr_t& instr) -> bool {
+ return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
+ instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
+ instr.operands[1].type == ZYDIS_OPERAND_TYPE_MEMORY &&
+ instr.operands[1].mem.base == ZYDIS_REGISTER_RSP &&
+ instr.operands[1].mem.index != ZYDIS_REGISTER_NONE;
+ },
+ // SUB VSP, OFFSET
+ [&](const zydis_reg_t vip,
+ const zydis_reg_t vsp,
+ const zydis_decoded_instr_t& instr) -> bool {
+ return instr.mnemonic == ZYDIS_MNEMONIC_SUB &&
+ instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
+ instr.operands[0].reg.value == vsp &&
+ instr.operands[1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE;
+ },
+ // MOV [VSP], REG
+ [&](const zydis_reg_t vip,
+ const zydis_reg_t vsp,
+ const zydis_decoded_instr_t& instr) -> bool {
+ return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
+ instr.operands[0].type == ZYDIS_OPERAND_TYPE_MEMORY &&
+ instr.operands[0].mem.base == vsp &&
+ instr.operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER;
+ }}},
+ [&](zydis_reg_t& vip,
+ zydis_reg_t& vsp,
+ hndlr_trace_t& hndlr) -> std::optional {
+ vinstr_t res;
+ memset(&res, NULL, sizeof res);
+ res.mnemonic = mnemonic_t::lreg;
+ res.imm.has_imm = true;
+ res.imm.size = 8;
+
+ const auto sub_vsp = std::find_if(
+ hndlr.m_instrs.begin(), hndlr.m_instrs.end(),
+ [&](emu_instr_t& instr) -> bool {
+ const auto& i = instr.m_instr;
+ return i.mnemonic == ZYDIS_MNEMONIC_SUB &&
+ i.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
+ i.operands[0].reg.value == vsp &&
+ i.operands[1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE;
+ });
+
+ res.stack_size = sub_vsp->m_instr.operands[1].imm.value.u * 8;
+ // // MOV REG, [RSP+REG]... we want the register in [RSP+REG]...
+ const auto mov_reg_vreg = std::find_if(
+ hndlr.m_instrs.begin(), hndlr.m_instrs.end(),
+ [&](emu_instr_t& instr) -> bool {
+ const auto& i = instr.m_instr;
+ return i.mnemonic == ZYDIS_MNEMONIC_MOV &&
+ i.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
+ i.operands[1].type == ZYDIS_OPERAND_TYPE_MEMORY &&
+ i.operands[1].mem.base == ZYDIS_REGISTER_RSP &&
+ i.operands[1].mem.index != ZYDIS_REGISTER_NONE;
+ });
+
+ uc_context* backup;
+ uc_context_alloc(hndlr.m_uc, &backup);
+ uc_context_save(hndlr.m_uc, backup);
+ uc_context_restore(hndlr.m_uc, mov_reg_vreg->m_cpu);
+
+ const uc_x86_reg idx_reg =
+ vm::instrs::reg_map[mov_reg_vreg->m_instr.operands[1].mem.index];
+
+ uc_reg_read(hndlr.m_uc, idx_reg, &res.imm.val);
+ uc_context_restore(hndlr.m_uc, backup);
+ uc_context_free(backup);
+ return res;
+ }};
+}
\ No newline at end of file
diff --git a/src/vmprofiles/sreg.cpp b/src/vmprofiles/sreg.cpp
index 0b05d02..0607dce 100644
--- a/src/vmprofiles/sreg.cpp
+++ b/src/vmprofiles/sreg.cpp
@@ -26,9 +26,7 @@ profiler_t sreg = {
[&](const zydis_reg_t vip,
const zydis_reg_t vsp,
const zydis_decoded_instr_t& instr) -> bool {
- return (instr.mnemonic == ZYDIS_MNEMONIC_MOV ||
- instr.mnemonic == ZYDIS_MNEMONIC_MOVSX ||
- instr.mnemonic == ZYDIS_MNEMONIC_MOVZX) &&
+ return vm::utils::is_mov(instr) &&
instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[1].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[1].mem.base == vip;
@@ -47,9 +45,11 @@ profiler_t sreg = {
zydis_reg_t& vsp,
hndlr_trace_t& hndlr) -> std::optional {
vinstr_t res;
+ memset(&res, NULL, sizeof res);
res.mnemonic = mnemonic_t::sreg;
+ res.imm.has_imm = true;
+ res.imm.size = 8;
- // locates ADD VSP, VALUE...
const auto add_vsp = std::find_if(
hndlr.m_instrs.begin(), hndlr.m_instrs.end(),
[&](emu_instr_t& instr) -> bool {
@@ -60,9 +60,7 @@ profiler_t sreg = {
i.operands[1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE;
});
- res.size = add_vsp->m_instr.operands[1].imm.value.u * 8;
-
- // MOV [RSP+REG], REG...
+ res.stack_size = add_vsp->m_instr.operands[1].imm.value.u * 8;
const auto mov_vreg_value = std::find_if(
hndlr.m_instrs.begin(), hndlr.m_instrs.end(),
[&](emu_instr_t& instr) -> bool {
@@ -74,6 +72,17 @@ profiler_t sreg = {
i.operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER;
});
+ uc_context* backup;
+ uc_context_alloc(hndlr.m_uc, &backup);
+ uc_context_save(hndlr.m_uc, backup);
+ uc_context_restore(hndlr.m_uc, mov_vreg_value->m_cpu);
+
+ const uc_x86_reg idx_reg =
+ vm::instrs::reg_map[mov_vreg_value->m_instr.operands[0].mem.index];
+
+ uc_reg_read(hndlr.m_uc, idx_reg, &res.imm.val);
+ uc_context_restore(hndlr.m_uc, backup);
+ uc_context_free(backup);
return res;
}};
}
\ No newline at end of file
diff --git a/src/vmutils.cpp b/src/vmutils.cpp
index c014666..dfdbd4c 100644
--- a/src/vmutils.cpp
+++ b/src/vmutils.cpp
@@ -22,6 +22,12 @@ bool is_jmp(const zydis_decoded_instr_t& instr) {
instr.mnemonic <= ZYDIS_MNEMONIC_JZ;
}
+bool is_mov(const zydis_decoded_instr_t& instr) {
+ return instr.mnemonic == ZYDIS_MNEMONIC_MOV ||
+ instr.mnemonic == ZYDIS_MNEMONIC_MOVSX ||
+ instr.mnemonic == ZYDIS_MNEMONIC_MOVZX;
+}
+
bool flatten(zydis_rtn_t& routine,
std::uintptr_t routine_addr,
bool keep_jmps,