Compare commits

..

36 Commits
main ... master

Author SHA1 Message Date
xtremegamer1 fa64967bd7 fixed vmexit pop order
1 year ago
xtremegamer1 122120b65f Improved instruction profiling
1 year ago
xtremegamer1 343c7b95a4 fixed this fucking bullshit
1 year ago
xtremegamer1 f35a70749f changed deobfuscation to keep register jumps
1 year ago
xtremegamer1 e62c872fbe fixed svsp.cpp
1 year ago
xtremegamer1 adff58848c basically added a bool and stuff
1 year ago
xtremegamer1 09b4e52f3a ok so basicallt i
1 year ago
xtremegamer1 b6aaaaeef4 added pragma once
1 year ago
xtremegamer1 0c1b62b2ca minor fixes
1 year ago
xtremegamer1 8d124ec828 Corrected typos
1 year ago
xtremegamer1 c8695100e6 Fixed typo and fixed nor vs nand fuckup
1 year ago
xtremegamer1 1d685efa0c deleted a single line 😐
1 year ago
xtremegamer1 f40579dc0c Check for 64 bit GP
1 year ago
xtremegamer1 462157b22c Added load delta and push order
1 year ago
xtremegamer1 e74f291d56 Added or virtual instruction
1 year ago
xtremegamer1 885f987d04 Fixed vmenter location
1 year ago
xtremegamer1 dd3aeabbb0 Added a function to determine if a register is 32-bit general purpose
1 year ago
xtremegamer1 ff1790ae22 removed prints now that the memory leaks are gone
1 year ago
xtremegamer1 25c3008dc2 added my new instructions
1 year ago
xtremegamer1 512b19292c Fixed the awful generator
1 year ago
xtremegamer1 10c39981cc Hi besties 😐
1 year ago
xtremegamer1 da7292eb31 Added handlers
1 year ago
xtremegamer1 88c167bb67 FIxed handlers
1 year ago
xtremegamer1 b0126f6f48 Fixed handlers, added writedr7, fixed names
1 year ago
xtremegamer1 f253e88ec1 Added allocation tracker
1 year ago
xtremegamer1 70d797420c updated source files
1 year ago
xtremegamer1 7b13df4bf6 Added writedr7 instruction
1 year ago
xtremegamer1 0be31ec977 Added an extremely simple memory leak tracker
1 year ago
xtremegamer1 ddd58c2a98 Added some vmprofiles
1 year ago
xtremegamer1 0a8964d3ab Added some new vmprofiles
1 year ago
xtremegamer1 c39b783af8 removed profanity from commit message
1 year ago
xtremegamer1 4b80be1bdf Ok this should work now....
1 year ago
xtremegamer1 c43fc3ee1e Merge branch 'main' of https://github.com/xtremegamer1/vmprofiler
1 year ago
xtremegamer1 a19d9c6fb8 trying to fix submodule fuckup
1 year ago
xtremegamer1 48eaabf526 trying to fix submodule fuckup
1 year ago
xtremegamer1 e3ecef4d4a I still dont't understand git please help
1 year ago

@ -66,11 +66,20 @@ list(APPEND vmprofiler_SOURCES
"src/vmprofiles/nor.cpp"
"src/vmprofiles/read.cpp"
"src/vmprofiles/shr.cpp"
"src/vmprofiles/shrd.cpp"
"src/vmprofiles/shl.cpp"
"src/vmprofiles/shld.cpp"
"src/vmprofiles/sreg.cpp"
"src/vmprofiles/svsp.cpp"
"src/vmprofiles/vmexit.cpp"
"src/vmprofiles/write.cpp"
"src/vmprofiles/lcr0.cpp"
"src/vmprofiles/and.cpp"
"src/vmprofiles/or.cpp"
"src/vmprofiles/writedr7.cpp"
"src/vmutils.cpp"
"include/uc_allocation_tracker.hpp"
"src/uc_allocation_tracker.cpp"
"include/vmctx.hpp"
"include/vminstrs.hpp"
"include/vmlocate.hpp"

2
deps/linux-pe vendored

@ -1 +1 @@
Subproject commit 9b8764004a284fefe599c407f4ebbdf5a8aa4b0a
Subproject commit 4f83eae434696201f5075d65b11bf8329c6d218a

2
deps/unicorn vendored

@ -1 +1 @@
Subproject commit 63a445cbba18bf1313ac3699b5d25462b5d529f4
Subproject commit 6c1cbef6ac505d355033aef1176b684d02e1eb3a

@ -0,0 +1,8 @@
#pragma once
#include <unicorn\unicorn.h>
extern int g_allocation_tracker;
uc_err uct_context_alloc(uc_engine *uc, uc_context **context);
uc_err uct_context_free(uc_context *context);
void print_allocation_number();

@ -1,6 +1,7 @@
#pragma once
#include <vminstrs.hpp>
#include <vmutils.hpp>
#include <array>
namespace vm {
class vmctx_t {
@ -11,12 +12,13 @@ class vmctx_t {
std::uintptr_t vm_entry_rva);
bool init();
const std::uintptr_t m_module_base, m_image_base, m_vm_entry_rva,
m_image_size;
m_image_size, m_image_load_delta;
zydis_reg_t get_vip() const { return m_vip; }
zydis_reg_t get_vsp() const { return m_vsp; }
zydis_rtn_t get_vm_enter() const { return m_vm_entry; }
const std::array<ZydisRegister, 16>& get_vmentry_push_order() const;
private:
/// <summary>
/// m_vip and m_vsp are set to the native registers used for them by the vm
@ -29,5 +31,8 @@ class vmctx_t {
/// the virtual machine enter flattened and deobfuscated...
/// </summary>
zydis_rtn_t m_vm_entry;
//using array container instead of c-style array in order to pass by reference.
std::array<ZydisRegister, 16> vmentry_push_order;
};
} // namespace vm

@ -2,6 +2,7 @@
#include <unicorn/unicorn.h>
#include <vmutils.hpp>
#include <array>
#define VIRTUAL_REGISTER_COUNT 24
#define VIRTUAL_SEH_REGISTER 24
@ -10,12 +11,14 @@ namespace vm::instrs {
/// <summary>
/// mnemonic representation of supported virtual instructions...
/// </summary>
enum class mnemonic_t {
enum class mnemonic_t : uint8_t {
unknown,
sreg,
lreg,
lconst,
add,
_or,
_and, //The fucking idiots who wrote the standard thought reserving the word "and" was appropriate
div,
idiv,
mul,
@ -31,6 +34,7 @@ enum class mnemonic_t {
shrd,
lvsp,
svsp,
lcr0,
writecr3,
readcr3,
writecr8,
@ -39,7 +43,8 @@ enum class mnemonic_t {
rdtsc,
call,
jmp,
vmexit
vmexit,
writedr7
};
/// <summary>
@ -105,6 +110,8 @@ enum class vbranch_type {
/// virtual code block
/// </summary>
struct vblk_t {
bool is_branch;
/// <summary>
/// start address VIP of this basic block...
/// </summary>
@ -117,7 +124,7 @@ struct vblk_t {
/// <summary>
/// image based relative virtual address...
/// </summary>
std::uintptr_t img_base;
std::uintptr_t img_based;
} m_vip;
/// <summary>
@ -152,6 +159,8 @@ struct vblk_t {
std::uintptr_t rip;
} m_jmp;
std::array<ZydisRegister, 16> vmexit_pop_order;
/// <summary>
/// vector of virtual instructions for this basic block...
/// </summary>
@ -286,6 +295,8 @@ extern profiler_t sreg;
extern profiler_t lreg;
extern profiler_t lconst;
extern profiler_t add;
extern profiler_t _or;
extern profiler_t _and;
extern profiler_t lvsp;
extern profiler_t svsp;
extern profiler_t nand;
@ -293,16 +304,22 @@ extern profiler_t nop;
extern profiler_t nor;
extern profiler_t read;
extern profiler_t write;
extern profiler_t lcr0;
extern profiler_t writedr7;
extern profiler_t imul;
extern profiler_t shl;
extern profiler_t shld;
extern profiler_t shr;
extern profiler_t shrd;
extern profiler_t shrd;
extern profiler_t vmexit;
/// <summary>
/// unsorted vector of profiles... they get sorted once at runtime...
/// </summary>
inline std::vector<profiler_t*> profiles = {
&vmexit, &shr, &imul, &nor, &write, &svsp, &read, &nand,
&lvsp, &add, &jmp, &sreg, &lreg, &lconst, &nop};
&vmexit, &shl, &shld, &shr, &shrd, &imul, &nor, &write, &svsp, &read,
&nand, &lvsp, &add, &jmp, &_or, &_and, &sreg, &lreg, &lcr0, &lconst, &nop, &writedr7};
/// <summary>
/// no i did not make this by hand, you cannot clown upon me!

@ -5,3 +5,4 @@
#include <vminstrs.hpp>
#include <vmlocate.hpp>
#include <vmutils.hpp>
#include <uc_allocation_tracker.hpp>

@ -70,6 +70,10 @@ inline bool open_binary_file(const std::string& file,
/// <returns></returns>
bool is_jmp(const zydis_decoded_instr_t& instr);
bool is_32_bit_gp(const ZydisRegister reg);
bool is_64_bit_gp(const ZydisRegister reg);
/// <summary>
/// used by profiles to see if an instruction is a MOV/SX/ZX...
/// </summary>

@ -0,0 +1,22 @@
#include <uc_allocation_tracker.hpp>
#include <cstdio>
int g_allocation_tracker;
uc_err uct_context_alloc(uc_engine *uc, uc_context **context)
{
++g_allocation_tracker;
//std::printf("Allocations: %p\n", g_allocation_tracker);
return uc_context_alloc(uc, context);
}
uc_err uct_context_free(uc_context *context)
{
--g_allocation_tracker;
//std::printf("Allocations: %p\n", g_allocation_tracker);
return uc_context_free(context);
}
void print_allocation_number()
{
std::printf("uc_context allocations: %p\n", g_allocation_tracker);
}

@ -8,7 +8,8 @@ vmctx_t::vmctx_t(std::uintptr_t module_base,
: m_module_base(module_base),
m_image_base(image_base),
m_vm_entry_rva(vm_entry_rva),
m_image_size(image_size) {}
m_image_size(image_size),
m_image_load_delta(m_module_base - m_image_base) {}
bool vmctx_t::init() {
vm::utils::init();
@ -20,6 +21,40 @@ bool vmctx_t::init() {
vm::utils::deobfuscate(m_vm_entry);
//Get the order in which native registers are pushed
int push_index = 0;
for (const auto& instr : m_vm_entry)
{
if (instr.instr.mnemonic == ZYDIS_MNEMONIC_PUSH &&
instr.instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
vm::utils::is_64_bit_gp(instr.instr.operands[0].reg.value))
{
if (std::find(vmentry_push_order.begin(), vmentry_push_order.begin() + push_index,
instr.instr.operands[0].reg.value) != vmentry_push_order.begin() + push_index)
{
//Every register should only be pushed once
std::printf("Error initializing vmctx_t: vmenter pushes could not be parsed.\n");
vm::utils::print(m_vm_entry);
return false;
}
vmentry_push_order[push_index++] = instr.instr.operands[0].reg.value;
}
else if (instr.instr.mnemonic == ZYDIS_MNEMONIC_PUSHFQ)
{
if (std::find(vmentry_push_order.begin(), vmentry_push_order.begin() + push_index,
instr.instr.operands[0].reg.value) != vmentry_push_order.begin() + push_index)
{
// Same shit
std::printf("Error initializing vmctx_t: vmenter pushes could not be parsed.\n");
vm::utils::print(m_vm_entry);
return false;
}
vmentry_push_order[push_index++] = ZYDIS_REGISTER_RFLAGS;
}
if (push_index == 16)
break;
}
// find mov reg, [rsp+0x90]. this register will be VIP...
const auto vip_fetch = std::find_if(
m_vm_entry.begin(), m_vm_entry.end(),
@ -53,4 +88,8 @@ bool vmctx_t::init() {
m_vsp = vsp_fetch->instr.operands[0].reg.value;
return true;
}
const std::array<ZydisRegister, 16>& vm::vmctx_t::get_vmentry_push_order() const
{
return vmentry_push_order;
}
} // namespace vm

@ -1,5 +1,5 @@
#include <vminstrs.hpp>
#include <uc_allocation_tracker.hpp>
namespace vm::instrs {
void deobfuscate(hndlr_trace_t& trace) {
static const auto _uses_reg = [](zydis_decoded_operand_t& op,
@ -64,11 +64,13 @@ void deobfuscate(hndlr_trace_t& trace) {
if (std::find(blacklist.begin(), blacklist.end(),
itr->m_instr.mnemonic) != blacklist.end()) {
uct_context_free(itr->m_cpu);
trace.m_instrs.erase(itr);
break;
}
if (vm::utils::is_jmp(itr->m_instr)) {
if (vm::utils::is_jmp(itr->m_instr) && itr->m_instr.operands[0].type != ZYDIS_OPERAND_TYPE_REGISTER) {
uct_context_free(itr->m_cpu);
trace.m_instrs.erase(itr);
break;
}
@ -111,6 +113,7 @@ void deobfuscate(hndlr_trace_t& trace) {
_writes(read_result->m_instr, reg))
continue;
uct_context_free(itr->m_cpu);
trace.m_instrs.erase(itr);
break;
}
@ -128,8 +131,42 @@ void init() {
}
vinstr_t determine(hndlr_trace_t& hndlr) {
std::vector<emu_instr_t> trimmed_instrs = hndlr.m_instrs;
// find the last MOV REG, DWORD PTR [VIP] in the instruction stream, then
// remove any instructions from this instruction to the JMP/RET...
const auto rva_fetch = std::find_if(
trimmed_instrs.rbegin(), trimmed_instrs.rend(),
[& vip = hndlr.m_vip](
const vm::instrs::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 == vip && i.operands[1].size == 32;
});
if (rva_fetch != trimmed_instrs.rend())
trimmed_instrs.erase((rva_fetch + 1).base(), trimmed_instrs.end());
auto profile = std::find_if(
profiles.begin(), profiles.end(), [&](profiler_t* profile) -> bool {
for (auto& matcher : profile->matchers) {
const auto matched =
std::find_if(trimmed_instrs.begin(), trimmed_instrs.end(),
[&](const emu_instr_t& instr) -> bool {
const auto& i = instr.m_instr;
return matcher(hndlr.m_vip, hndlr.m_vsp, i);
});
if (matched == trimmed_instrs.end())
return false;
}
return true;
});
if (profile == profiles.end())
{
const auto& instrs = hndlr.m_instrs;
const auto profile = std::find_if(
// Try again with original instruction stream including those after the last MOV REG, DWORD PTR [VIP] just to be sure
profile = std::find_if(
profiles.begin(), profiles.end(), [&](profiler_t* profile) -> bool {
for (auto& matcher : profile->matchers) {
const auto matched =
@ -143,6 +180,7 @@ vinstr_t determine(hndlr_trace_t& hndlr) {
}
return true;
});
}
if (profile == profiles.end())
return vinstr_t{mnemonic_t::unknown};

@ -49,6 +49,18 @@ std::vector<vm_enter_t> get_vm_entries(std::uintptr_t module_base,
zydis_rtn_t rtn;
if (!vm::utils::scn::executable(module_base, result)) continue;
// Make sure that the form of the vmenter is a jmp immediately followed by a call imm
ZydisDecodedInstruction after_push;
if (ZYAN_SUCCESS(ZydisDecoderDecodeBuffer(vm::utils::g_decoder.get(),
(void*)(result + 5), 5, &after_push)))
{
if (after_push.mnemonic != ZYDIS_MNEMONIC_CALL ||
after_push.operands[0].type != ZYDIS_OPERAND_TYPE_IMMEDIATE)
continue;
}
else
continue;
if (!vm::utils::flatten(rtn, result, false, 500, module_base)) continue;
// the last instruction in the stream should be a JMP to a register or a

@ -46,6 +46,7 @@ profiler_t add = {
[](zydis_reg_t& vip, zydis_reg_t& vsp,
hndlr_trace_t& hndlr) -> std::optional<vinstr_t> {
vinstr_t res{mnemonic_t::add};
res.imm.has_imm = false;
// MOV REG, [VSP]
const auto mov_reg_vsp = std::find_if(
@ -71,7 +72,6 @@ profiler_t add = {
});
res.stack_size = mov_vsp_offset->m_instr.operands[1].size;
res.imm.size = mov_reg_vsp->m_instr.operands[1].size;
return res;
}};
}

@ -0,0 +1,63 @@
#include <vminstrs.hpp>
// Loads an address and value from the stack, ands the derefed address with the value
namespace vm::instrs {
profiler_t _and = {
"AND",
mnemonic_t::_and,
{{// MOV REG, [VSP] This is the address
LOAD_VALUE,
// MOV REG, [VSP+8]
[](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 &&
instr.operands[1].mem.disp.has_displacement,
instr.operands[1].mem.disp.value == 8;
},
// AND [REG], REG
[](const zydis_reg_t vip, const zydis_reg_t vsp,
const zydis_decoded_instr_t& instr) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_AND &&
instr.operands[0].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[0].mem.base != ZYDIS_REGISTER_NONE &&
instr.operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER;
},
// PUSHFQ
[](const zydis_reg_t vip, const zydis_reg_t vsp,
const zydis_decoded_instr_t& instr) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_PUSHFQ;
},
// POP [VSP]
[](const zydis_reg_t vip, const zydis_reg_t vsp,
const zydis_decoded_instr_t& instr) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_POP &&
instr.operands[0].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[0].mem.base == vsp;
}}},
[](zydis_reg_t& vip, zydis_reg_t& vsp,
hndlr_trace_t& hndlr) -> std::optional<vinstr_t> {
vinstr_t res{mnemonic_t::_and};
res.imm.has_imm = false;
// MOV REG [VSP+OFFSET]
const auto mov_vsp_offset = 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 == vsp &&
i.operands[1].mem.disp.has_displacement;
});
if (mov_vsp_offset == hndlr.m_instrs.end())
return std::nullopt;
res.stack_size = mov_vsp_offset->m_instr.operands[0].size;
return res;
}};
}

@ -72,8 +72,9 @@ profiler_t jmp = {
i.operands[1].reg.value == write_dep;
});
if (mov_reg_write_dep == instrs.end()) return {};
if (mov_reg_write_dep == instrs.end())
vsp = write_dep;
else
vsp = mov_reg_write_dep->m_instr.operands[0].reg.value;
} else {
// find the MOV REG, [VSP] instruction...
@ -87,7 +88,8 @@ profiler_t jmp = {
i.operands[1].mem.base == vsp;
});
if (mov_reg_deref_vsp == instrs.end()) return {};
if (mov_reg_deref_vsp == instrs.end())
return {};
// find the MOV REG, mov_reg_deref_vsp->operands[0].reg.value
const auto mov_vip_reg = std::find_if(
@ -100,10 +102,27 @@ profiler_t jmp = {
i.operands[1].reg.value ==
mov_reg_deref_vsp->m_instr.operands[0].reg.value;
});
//It is possible that mov_vip_reg is actually updating the rolling key, if so use original vip
const auto load_handler_rva = std::find_if(
mov_vip_reg, instrs.end(),
[&](const 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 &&
vm::utils::is_32_bit_gp(i.operands[0].reg.value) &&
i.operands[1].type == ZYDIS_OPERAND_TYPE_MEMORY &&
i.operands[1].mem.base ==
mov_vip_reg->m_instr.operands[0].reg.value;
});
if (mov_vip_reg == instrs.end()) return {};
if (mov_vip_reg == instrs.end())
return {};
vip = mov_vip_reg->m_instr.operands[0].reg.value;
vip = (load_handler_rva != instrs.end()) ?
mov_vip_reg->m_instr.operands[0].reg.value :
mov_vip_reg->m_instr.operands[1].reg.value;
//Ok so basically mov_vip_reg, despite its name, isn't guaranteed to be
//mov vip, reg, and can in fact be mov rkey, vip.
// see if VSP gets updated as well...
const auto mov_reg_vsp = std::find_if(
@ -123,6 +142,7 @@ profiler_t jmp = {
vinstr_t res;
res.mnemonic = mnemonic_t::jmp;
res.imm.has_imm = false;
res.stack_size = 64;
return res;
}};
}

@ -0,0 +1,44 @@
#include <vminstrs.hpp>
//Loads CR0 onto the stack
namespace vm::instrs {
profiler_t lcr0 = {
"LCR0",
mnemonic_t::lcr0,
{
// MOV REG, CR0
[](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_REGISTER &&
instr.operands[1].reg.value == ZYDIS_REGISTER_CR0;
},
// 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[0].mem.index == ZYDIS_REGISTER_NONE &&
instr.operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[1].reg.value != vsp;
}
},
[](zydis_reg_t& vip, zydis_reg_t& vsp,
hndlr_trace_t& hndlr) -> std::optional<vinstr_t> {
vinstr_t res{mnemonic_t::lcr0};
res.imm.has_imm = false;
res.stack_size = 64;
return res;
}
};
}

@ -15,7 +15,7 @@ profiler_t lvsp = {
}}},
[](zydis_reg_t& vip, zydis_reg_t& vsp,
hndlr_trace_t& hndlr) -> std::optional<vinstr_t> {
vinstr_t res{mnemonic_t::svsp};
vinstr_t res{mnemonic_t::lvsp};
res.imm.has_imm = false;
const auto load_vsp = std::find_if(

@ -21,10 +21,10 @@ profiler_t nand = {
return instr.mnemonic == ZYDIS_MNEMONIC_NOT &&
instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER;
},
// AND REG, REG
// OR REG, REG
[](const zydis_reg_t vip, const zydis_reg_t vsp,
const zydis_decoded_instr_t& instr) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_AND &&
return instr.mnemonic == ZYDIS_MNEMONIC_OR &&
instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER;
},

@ -21,10 +21,10 @@ profiler_t nor = {
return instr.mnemonic == ZYDIS_MNEMONIC_NOT &&
instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER;
},
// OR REG, REG
// AND REG, REG
[](const zydis_reg_t vip, const zydis_reg_t vsp,
const zydis_decoded_instr_t& instr) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_OR &&
return instr.mnemonic == ZYDIS_MNEMONIC_AND &&
instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER;
},
@ -51,7 +51,7 @@ profiler_t nor = {
}}},
[](zydis_reg_t& vip, zydis_reg_t& vsp,
hndlr_trace_t& hndlr) -> std::optional<vinstr_t> {
vinstr_t res{mnemonic_t::nand};
vinstr_t res{mnemonic_t::nor};
res.imm.has_imm = false;
// MOV [VSP+OFFSET], REG

@ -0,0 +1,60 @@
#include <vminstrs.hpp>
namespace vm::instrs {
profiler_t _or = {
"OR",
mnemonic_t::_or,
{{// MOV REG, [VSP]
LOAD_VALUE,
// MOV REG, [VSP+OFFSET]
[](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 &&
instr.operands[1].mem.disp.has_displacement;
},
// OR [REG], REG
[](const zydis_reg_t vip, const zydis_reg_t vsp,
const zydis_decoded_instr_t& instr) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_OR &&
instr.operands[0].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[0].mem.base != ZYDIS_REGISTER_NONE &&
instr.operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER;
},
// PUSHFQ
[](const zydis_reg_t vip, const zydis_reg_t vsp,
const zydis_decoded_instr_t& instr) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_PUSHFQ;
},
// POP [VSP]
[](const zydis_reg_t vip, const zydis_reg_t vsp,
const zydis_decoded_instr_t& instr) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_POP &&
instr.operands[0].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[0].mem.base == vsp;
}}},
[](zydis_reg_t& vip, zydis_reg_t& vsp,
hndlr_trace_t& hndlr) -> std::optional<vinstr_t> {
vinstr_t res{mnemonic_t::_or};
res.imm.has_imm = false;
// MOV REG [VSP+OFFSET]
const auto reg_vsp_offset = 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 == vsp &&
i.operands[1].mem.disp.has_displacement;
});
if (reg_vsp_offset == hndlr.m_instrs.end())
return std::nullopt;
res.stack_size = reg_vsp_offset->m_instr.operands[0].size;
return res;
}};
}

@ -26,13 +26,13 @@ profiler_t read = {
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 &&
return i.mnemonic == ZYDIS_MNEMONIC_MOV || i.mnemonic == ZYDIS_MNEMONIC_MOVZX &&
i.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
i.operands[1].type == ZYDIS_OPERAND_TYPE_MEMORY &&
i.operands[1].mem.base != vsp;
});
res.stack_size = mov_reg_reg->m_instr.operands[0].size;
res.stack_size = mov_reg_reg->m_instr.operands[1].size;
return res;
}};
}

@ -0,0 +1,63 @@
#include <vminstrs.hpp>
namespace vm::instrs {
profiler_t shl = {
"SHL",
mnemonic_t::shl,
{{// MOV REG, [VSP]
LOAD_VALUE,
// MOV REG, [VSP+OFFSET]
[](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 &&
instr.operands[1].mem.disp.has_displacement;
},
// SHL REG, REG
[](const zydis_reg_t vip, const zydis_reg_t vsp,
const zydis_decoded_instr_t& instr) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_SHL &&
instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER;
},
// MOV [VSP+OFFSET], 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[0].mem.disp.has_displacement &&
instr.operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER;
},
// PUSHFQ
[](const zydis_reg_t vip, const zydis_reg_t vsp,
const zydis_decoded_instr_t& instr) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_PUSHFQ;
},
// POP [VSP]
[](const zydis_reg_t vip, const zydis_reg_t vsp,
const zydis_decoded_instr_t& instr) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_POP &&
instr.operands[0].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[0].mem.base == vsp;
}}},
[](zydis_reg_t& vip, zydis_reg_t& vsp,
hndlr_trace_t& hndlr) -> std::optional<vinstr_t> {
vinstr_t res{mnemonic_t::shl};
res.imm.has_imm = false;
const auto shl_reg = 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_SHL &&
i.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
i.operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER;
});
res.stack_size = shl_reg->m_instr.operands[0].size;
return res;
}};
}

@ -0,0 +1,73 @@
#include <vminstrs.hpp>
namespace vm::instrs {
profiler_t shld = {
"SHLD",
mnemonic_t::shld,
{{// MOV REG, [VSP]
LOAD_VALUE,
// MOV REG, [VSP+OFFSET]
[](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 &&
instr.operands[1].mem.disp.has_displacement;
},
// MOV REG, [VSP+OFFSET]
[](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 &&
instr.operands[1].mem.disp.has_displacement;
},
// SHLD REG, REG
[](const zydis_reg_t vip, const zydis_reg_t vsp,
const zydis_decoded_instr_t& instr) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_SHLD &&
instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER;
},
// MOV [VSP+OFFSET], 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[0].mem.disp.has_displacement &&
instr.operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER;
},
// PUSHFQ
[](const zydis_reg_t vip, const zydis_reg_t vsp,
const zydis_decoded_instr_t& instr) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_PUSHFQ;
},
// POP [VSP]
[](const zydis_reg_t vip, const zydis_reg_t vsp,
const zydis_decoded_instr_t& instr) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_POP &&
instr.operands[0].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[0].mem.base == vsp;
}}},
[](zydis_reg_t& vip, zydis_reg_t& vsp,
hndlr_trace_t& hndlr) -> std::optional<vinstr_t> {
vinstr_t res{mnemonic_t::shld};
res.imm.has_imm = false;
const auto shld_reg = 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_SHLD &&
i.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
i.operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER;
});
res.stack_size = shld_reg->m_instr.operands[0].size;
return res;
}};
}

@ -0,0 +1,73 @@
#include <vminstrs.hpp>
namespace vm::instrs {
profiler_t shrd = {
"SHRD",
mnemonic_t::shrd,
{{// MOV REG, [VSP]
LOAD_VALUE,
// MOV REG, [VSP+OFFSET]
[](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 &&
instr.operands[1].mem.disp.has_displacement;
},
// MOV REG, [VSP+OFFSET]
[](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 &&
instr.operands[1].mem.disp.has_displacement;
},
// SHRD REG, REG
[](const zydis_reg_t vip, const zydis_reg_t vsp,
const zydis_decoded_instr_t& instr) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_SHRD &&
instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER;
},
// MOV [VSP+OFFSET], 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[0].mem.disp.has_displacement &&
instr.operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER;
},
// PUSHFQ
[](const zydis_reg_t vip, const zydis_reg_t vsp,
const zydis_decoded_instr_t& instr) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_PUSHFQ;
},
// POP [VSP]
[](const zydis_reg_t vip, const zydis_reg_t vsp,
const zydis_decoded_instr_t& instr) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_POP &&
instr.operands[0].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[0].mem.base == vsp;
}}},
[](zydis_reg_t& vip, zydis_reg_t& vsp,
hndlr_trace_t& hndlr) -> std::optional<vinstr_t> {
vinstr_t res{mnemonic_t::shrd};
res.imm.has_imm = false;
const auto shrd_reg = 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_SHRD &&
i.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
i.operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER;
});
res.stack_size = shrd_reg->m_instr.operands[0].size;
return res;
}};
}

@ -31,19 +31,20 @@ profiler_t svsp = {
}}},
[](zydis_reg_t& vip, zydis_reg_t& vsp,
hndlr_trace_t& hndlr) -> std::optional<vinstr_t> {
vinstr_t res{mnemonic_t::lvsp};
const auto sub_vsp = std::find_if(
vinstr_t res{mnemonic_t::svsp};
const auto mov_vsp_reg = 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;
return i.mnemonic == ZYDIS_MNEMONIC_MOV &&
i.operands[0].type == ZYDIS_OPERAND_TYPE_MEMORY &&
i.operands[0].mem.base == vsp &&
i.operands[0].mem.disp.has_displacement == false &&
i.operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER;
});
res.imm.has_imm = false;
res.stack_size = sub_vsp->m_instr.operands[1].imm.value.u;
res.stack_size = mov_vsp_reg->m_instr.operands[1].size;
return res;
}};
}

@ -29,6 +29,8 @@ profiler_t write = {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[0].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[0].mem.base != vsp &&
instr.operands[0].mem.base != ZYDIS_REGISTER_RSP &&
//!instr.operands[0].mem.disp.has_displacement &&
instr.operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[1].reg.value != vsp;
}}},

@ -0,0 +1,37 @@
#include <vminstrs.hpp>
//Write value on top of stack to dr7
namespace vm::instrs {
profiler_t writedr7 = {
"WRITEDR7",
mnemonic_t::writedr7,
{
// MOV REG, [VSP+OFFSET]
LOAD_VALUE,
// ADD VSP, OFFSET
[](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;
},
// MOV DR7, 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 == ZYDIS_REGISTER_DR7 &&
instr.operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[1].reg.value != vsp;
}
},
[](zydis_reg_t& vip, zydis_reg_t& vsp,
hndlr_trace_t& hndlr) -> std::optional<vinstr_t> {
vinstr_t res{mnemonic_t::writedr7};
res.stack_size == 64;
res.imm.has_imm = false;
return res;
}
};
}

@ -28,6 +28,16 @@ bool is_mov(const zydis_decoded_instr_t& instr) {
instr.mnemonic == ZYDIS_MNEMONIC_MOVZX;
}
bool is_32_bit_gp(const ZydisRegister reg)
{
return reg >= ZYDIS_REGISTER_EAX && reg <= ZYDIS_REGISTER_R15D;
}
bool is_64_bit_gp(const ZydisRegister reg)
{
return reg >= ZYDIS_REGISTER_RAX && reg <= ZYDIS_REGISTER_R15;
}
bool flatten(zydis_rtn_t& routine,
std::uintptr_t routine_addr,
bool keep_jmps,

Loading…
Cancel
Save