forked from vmp3/vmprofiler
parent
11650b6d8a
commit
20ad0b5950
@ -0,0 +1,140 @@
|
||||
#pragma once
|
||||
#include <vmutils.hpp>
|
||||
|
||||
namespace vm::instrs {
|
||||
/// <summary>
|
||||
/// mnemonic representation of supported virtual instructions...
|
||||
/// </summary>
|
||||
enum class mnemonic_t {
|
||||
unknown,
|
||||
sreg,
|
||||
lreg,
|
||||
lconst,
|
||||
add,
|
||||
div,
|
||||
idiv,
|
||||
mul,
|
||||
imul,
|
||||
nand,
|
||||
read,
|
||||
write,
|
||||
shl,
|
||||
shld,
|
||||
shr,
|
||||
shrd,
|
||||
lvsp,
|
||||
svsp,
|
||||
writecr3,
|
||||
readcr3,
|
||||
writecr8,
|
||||
readcr8,
|
||||
cpuid,
|
||||
rdtsc,
|
||||
call,
|
||||
jmp,
|
||||
vmexit
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// the main virtual instruction structure which is returned by profilers...
|
||||
/// </summary>
|
||||
struct vinstr_t {
|
||||
/// <summary>
|
||||
/// mnemonic of the virtual instruction...
|
||||
/// </summary>
|
||||
mnemonic_t mnemonic;
|
||||
|
||||
/// <summary>
|
||||
/// size varient of the virtual instruction... I.E SREGQ would have a value of
|
||||
/// "64" here...where the SREGDW varient would have a "32" here...
|
||||
/// </summary>
|
||||
u8 size;
|
||||
|
||||
struct {
|
||||
/// <summary>
|
||||
/// true if the virtual instruction has an imm false if not...
|
||||
/// </summary>
|
||||
bool has_imm;
|
||||
|
||||
/// <summary>
|
||||
/// size in bits of the imm... 8, 16, 32, 64...
|
||||
/// </summary>
|
||||
u8 size;
|
||||
|
||||
/// <summary>
|
||||
/// imm value...
|
||||
/// </summary>
|
||||
u64 val;
|
||||
} imm;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// matcher function which returns true if an instruction matches a desired
|
||||
/// one...
|
||||
/// </summary>
|
||||
using matcher_t = std::function<bool(const zydis_reg_t vip,
|
||||
const zydis_reg_t vsp,
|
||||
const zydis_decoded_instr_t& instr)>;
|
||||
|
||||
/// <summary>
|
||||
/// virtual instruction structure generator... this can update the vip and vsp
|
||||
/// argument... it cannot update the instruction stream (hndlr)...
|
||||
/// </summary>
|
||||
using vinstr_gen_t = std::function<std::optional<vinstr_t>(zydis_reg_t& vip,
|
||||
zydis_reg_t& vsp,
|
||||
zydis_rtn_t& hndlr)>;
|
||||
|
||||
/// <summary>
|
||||
/// each virtual instruction has its own profiler_t structure which can generate
|
||||
/// all varients of the virtual instruction for each size...
|
||||
/// </summary>
|
||||
struct profiler_t {
|
||||
/// <summary>
|
||||
/// string name of the virtual instruction that this profile generates for...
|
||||
/// </summary>
|
||||
std::string name;
|
||||
|
||||
/// <summary>
|
||||
/// mnemonic representation of the virtual instruction...
|
||||
/// </summary>
|
||||
mnemonic_t mnemonic;
|
||||
|
||||
/// <summary>
|
||||
/// vector of matcher lambda's which return true if a given instruction
|
||||
/// matches...
|
||||
/// </summary>
|
||||
std::vector<matcher_t> matchers;
|
||||
|
||||
/// <summary>
|
||||
/// generates a virtual instruction structure...
|
||||
/// </summary>
|
||||
vinstr_gen_t generate;
|
||||
};
|
||||
|
||||
extern profiler_t jmp;
|
||||
inline std::vector<profiler_t*> profiles = {&jmp};
|
||||
|
||||
inline vinstr_t determine(zydis_reg_t& vip,
|
||||
zydis_reg_t& vsp,
|
||||
zydis_rtn_t& hndlr) {
|
||||
const auto profile = std::find_if(
|
||||
profiles.begin(), profiles.end(), [&](profiler_t* profile) -> bool {
|
||||
for (auto& matcher : profile->matchers) {
|
||||
const auto matched = std::find_if(hndlr.begin(), hndlr.end(),
|
||||
[&](zydis_instr_t& instr) -> bool {
|
||||
const auto& i = instr.instr;
|
||||
return matcher(vip, vsp, i);
|
||||
});
|
||||
if (matched == hndlr.end())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (profile == profiles.end())
|
||||
return vinstr_t{mnemonic_t::unknown};
|
||||
|
||||
auto result = (*profile)->generate(vip, vsp, hndlr);
|
||||
return result.has_value() ? result.value() : vinstr_t{mnemonic_t::unknown};
|
||||
}
|
||||
} // namespace vm::instrs
|
@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include <vmctx.hpp>
|
||||
#include <vmlocate.hpp>
|
||||
#include <vmutils.hpp>
|
||||
#include <vmutils.hpp>
|
||||
#include <vminstrs.hpp>
|
@ -0,0 +1,127 @@
|
||||
#include <vminstrs.hpp>
|
||||
|
||||
namespace vm::instrs {
|
||||
profiler_t jmp = {
|
||||
"JMP",
|
||||
mnemonic_t::jmp,
|
||||
// MOV REG, [VSP]
|
||||
{{[&](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 == vsp;
|
||||
},
|
||||
// ADD VSP, 8
|
||||
[&](const zydis_reg_t vip,
|
||||
const zydis_reg_t vsp,
|
||||
const zydis_decoded_instr_t& instr) -> bool {
|
||||
return instr.mnemonic == ZYDIS_MNEMONIC_ADD &&
|
||||
instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
|
||||
instr.operands[0].reg.value == vsp &&
|
||||
instr.operands[1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE &&
|
||||
instr.operands[1].imm.value.u == 8;
|
||||
},
|
||||
// MOV VIP, 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[0].reg.value == vip &&
|
||||
instr.operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER;
|
||||
}}},
|
||||
[&](zydis_reg_t& vip,
|
||||
zydis_reg_t& vsp,
|
||||
zydis_rtn_t& hndlr) -> std::optional<vinstr_t> {
|
||||
const auto xchg = std::find_if(
|
||||
hndlr.begin(), hndlr.end(), [&](const zydis_instr_t& instr) -> bool {
|
||||
const auto& i = instr.instr;
|
||||
return i.mnemonic == ZYDIS_MNEMONIC_XCHG &&
|
||||
i.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
|
||||
i.operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER &&
|
||||
// exclusive or... operand 1 or operand 2 can be VSP but they
|
||||
// both cannot be...
|
||||
((i.operands[1].reg.value == vsp ||
|
||||
i.operands[0].reg.value == vsp) &&
|
||||
!((i.operands[1].reg.value == vsp) &&
|
||||
(i.operands[0].reg.value == vsp)));
|
||||
});
|
||||
|
||||
// this JMP virtual instruction changes VSP as well as VIP...
|
||||
if (xchg != hndlr.end()) {
|
||||
// grab the register that isnt VSP in the XCHG...
|
||||
// xchg reg, vsp or xchg vsp, reg...
|
||||
zydis_reg_t write_dep = xchg->instr.operands[0].reg.value != vsp
|
||||
? xchg->instr.operands[0].reg.value
|
||||
: xchg->instr.operands[1].reg.value;
|
||||
|
||||
// update VIP... VSP becomes VIP... with the XCHG...
|
||||
vip = xchg->instr.operands[0].reg.value != vsp
|
||||
? xchg->instr.operands[1].reg.value
|
||||
: xchg->instr.operands[0].reg.value;
|
||||
|
||||
// find the next MOV REG, write_dep... this REG will be VSP...
|
||||
const auto mov_reg_write_dep = std::find_if(
|
||||
xchg, hndlr.end(), [&](const zydis_instr_t& instr) -> bool {
|
||||
const auto& i = instr.instr;
|
||||
return i.mnemonic == ZYDIS_MNEMONIC_MOV &&
|
||||
i.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
|
||||
i.operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER &&
|
||||
i.operands[1].reg.value == write_dep;
|
||||
});
|
||||
|
||||
if (mov_reg_write_dep == hndlr.end())
|
||||
return {};
|
||||
|
||||
vsp = mov_reg_write_dep->instr.operands[0].reg.value;
|
||||
} else {
|
||||
// find the MOV REG, [VSP] instruction...
|
||||
const auto mov_reg_deref_vsp = std::find_if(
|
||||
hndlr.begin(), hndlr.end(),
|
||||
[&](const zydis_instr_t& instr) -> bool {
|
||||
const auto& i = instr.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 == vsp;
|
||||
});
|
||||
|
||||
if (mov_reg_deref_vsp == hndlr.end())
|
||||
return {};
|
||||
|
||||
// find the MOV REG, mov_reg_deref_vsp->operands[0].reg.value
|
||||
const auto mov_vip_reg = std::find_if(
|
||||
mov_reg_deref_vsp, hndlr.end(),
|
||||
[&](const zydis_instr_t& instr) -> bool {
|
||||
const auto& i = instr.instr;
|
||||
return i.mnemonic == ZYDIS_MNEMONIC_MOV &&
|
||||
i.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
|
||||
i.operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER &&
|
||||
i.operands[1].reg.value ==
|
||||
mov_reg_deref_vsp->instr.operands[0].reg.value;
|
||||
});
|
||||
|
||||
if (mov_vip_reg == hndlr.end())
|
||||
return {};
|
||||
|
||||
vip = mov_vip_reg->instr.operands[0].reg.value;
|
||||
|
||||
// see if VSP gets updated as well...
|
||||
const auto mov_reg_vsp = std::find_if(
|
||||
mov_reg_deref_vsp, hndlr.end(),
|
||||
[&](const zydis_instr_t& instr) -> bool {
|
||||
const auto& i = instr.instr;
|
||||
return i.mnemonic == ZYDIS_MNEMONIC_MOV &&
|
||||
i.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
|
||||
i.operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER &&
|
||||
i.operands[1].reg.value == vsp;
|
||||
});
|
||||
|
||||
if (mov_reg_vsp != hndlr.end())
|
||||
vsp = mov_reg_vsp->instr.operands[0].reg.value;
|
||||
}
|
||||
return vinstr_t{mnemonic_t::jmp};
|
||||
}};
|
||||
}
|
Loading…
Reference in new issue