Compare commits

..

36 Commits
main ... master

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

@ -4,4 +4,5 @@
#include <vmctx.hpp>
#include <vminstrs.hpp>
#include <vmlocate.hpp>
#include <vmutils.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) {
const auto& instrs = hndlr.m_instrs;
const auto profile = std::find_if(
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;
// 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 =
@ -141,8 +178,9 @@ vinstr_t determine(hndlr_trace_t& hndlr) {
if (matched == instrs.end())
return false;
}
return true;
});
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,9 +72,10 @@ profiler_t jmp = {
i.operands[1].reg.value == write_dep;
});
if (mov_reg_write_dep == instrs.end()) return {};
vsp = mov_reg_write_dep->m_instr.operands[0].reg.value;
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...
const auto mov_reg_deref_vsp = std::find_if(
@ -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