changed a bunch of stuff, cleaned the source

merge-requests/2/head
_xeroxz 3 years ago
parent b9dc2520fe
commit 47a46d1c58

@ -172,6 +172,42 @@ namespace vm
{ZYDIS_MNEMONIC_DEC, ZYDIS_MNEMONIC_INC}
};
inline void inverse_transforms(transform::map_t& transforms, transform::map_t& inverse)
{
inverse[transform::type::generic0] = transforms[transform::type::generic0];
inverse[transform::type::generic0].mnemonic =
transform::inverse[transforms[transform::type::generic0].mnemonic];
inverse[transform::type::rolling_key] = transforms[transform::type::rolling_key];
inverse[transform::type::rolling_key].mnemonic =
transform::inverse[transforms[transform::type::rolling_key].mnemonic];
inverse[transform::type::generic1] = transforms[transform::type::generic1];
inverse[transform::type::generic1].mnemonic =
transform::inverse[transforms[transform::type::generic1].mnemonic];
inverse[transform::type::generic2] = transforms[transform::type::generic2];
inverse[transform::type::generic2].mnemonic =
transform::inverse[transforms[transform::type::generic2].mnemonic];
inverse[transform::type::generic3] = transforms[transform::type::generic3];
inverse[transform::type::generic3].mnemonic =
transform::inverse[transforms[transform::type::generic3].mnemonic];
inverse[transform::type::update_key] = transforms[transform::type::update_key];
inverse[transform::type::update_key].mnemonic =
transform::inverse[transforms[transform::type::update_key].mnemonic];
}
inline auto inverse_transform(std::vector<zydis_decoded_instr_t>& instrs) -> bool
{
for (auto idx = 0u; idx < instrs.size() - 1; ++idx)
if (!(instrs[idx].mnemonic = inverse[instrs[idx].mnemonic]))
return false;
return true;
}
// max size of a and b is 64 bits, a and b is then converted to
// the number of bits in bitsize, the transformation is applied,
// finally the result is converted back to 64bits... zero extended...

@ -1,51 +0,0 @@
#pragma once
#include <transform.hpp>
#include <vmutils.h>
#include <vmprofiler.hpp>
namespace vm
{
std::pair<std::uint64_t, std::uint64_t> decrypt_operand(transform::map_t& transforms,
std::uint64_t operand, std::uint64_t rolling_key);
std::pair<std::uint64_t, std::uint64_t> encrypt_operand(transform::map_t& transforms,
std::uint64_t operand, std::uint64_t rolling_key);
void inverse_transforms(transform::map_t& transforms, transform::map_t& inverse);
bool get_calc_jmp(const zydis_routine_t& vm_entry, zydis_routine_t& calc_jmp);
bool get_vinstr_rva_transform(
const zydis_routine_t& vm_entry, zydis_decoded_instr_t* transform_instr);
struct handler_t
{
u8 imm_size; // size in bits...
vm::transform::map_t transforms;
vm::handler::profile_t* profile;
zydis_routine_t instrs;
std::uintptr_t address;
};
namespace handler
{
bool has_imm(const zydis_routine_t& vm_handler);
std::uint8_t imm_size(const zydis_routine_t& vm_handler);
bool get(zydis_routine_t& vm_entry, zydis_routine_t& vm_handler, std::uintptr_t handler_addr);
// may throw an exception...
bool get_all(std::uintptr_t module_base, std::uintptr_t image_base,
zydis_routine_t& vm_entry, std::uintptr_t* vm_handler_table, std::vector<vm::handler_t>& vm_handlers);
// can be used on calc_jmp...
bool get_operand_transforms(const zydis_routine_t& vm_handler, transform::map_t& transforms);
vm::handler::profile_t* get_profile(vm::handler_t& vm_handler);
namespace table
{
std::uintptr_t* get(const zydis_routine_t& vm_entry);
bool get_transform(const zydis_routine_t& vm_entry, zydis_decoded_instr_t* transform_instr);
std::uint64_t encrypt(zydis_decoded_instr_t& transform_instr, std::uint64_t val);
std::uint64_t decrypt(zydis_decoded_instr_t& transform_instr, std::uint64_t val);
}
}
}

@ -1,29 +0,0 @@
#pragma once
#include <vm.h>
#include <vmp2.hpp>
namespace vm
{
class vmctx_t
{
public:
explicit vmctx_t(
vmp2::file_header* file_header,
vmp2::entry_t* entry_list,
std::vector<vm::handler_t>& vm_handlers,
std::uintptr_t module_base,
std::uintptr_t image_base
);
std::pair<std::string, const vmp2::entry_t*> step() const;
private:
std::uintptr_t get_imm(vmp2::exec_type_t exec_type_t,
std::uint32_t vip_offset, std::uint8_t imm_size) const;
mutable std::uint32_t idx;
const std::uintptr_t image_base, module_base;
const vmp2::entry_t* entry_list;
const vmp2::file_header* file_header;
std::vector<vm::handler_t> vm_handlers;
};
}

@ -1,5 +1,5 @@
#pragma once
#include "vm.h"
#include <vmprofiler.hpp>
namespace vmp2
{

@ -3,6 +3,24 @@
namespace vm
{
namespace calc_jmp
{
bool get(const zydis_routine_t& vm_entry, zydis_routine_t& calc_jmp);
}
namespace instrs
{
// decrypt transformations for encrypted virtual instruction rva...
bool get_rva_decrypt(const zydis_routine_t& vm_entry,
std::vector<zydis_decoded_instr_t>& transform_instrs);
std::pair<std::uint64_t, std::uint64_t> decrypt_operand(transform::map_t& transforms,
std::uint64_t operand, std::uint64_t rolling_key);
std::pair<std::uint64_t, std::uint64_t> encrypt_operand(transform::map_t& transforms,
std::uint64_t operand, std::uint64_t rolling_key);
}
namespace handler
{
using instr_callback_t = bool(*)(const zydis_decoded_instr_t& instr);
@ -65,6 +83,36 @@ namespace vm
extention_t extention;
};
struct handler_t
{
u8 imm_size; // size in bits...
vm::transform::map_t transforms;
vm::handler::profile_t* profile;
zydis_routine_t instrs;
std::uintptr_t address;
};
bool has_imm(const zydis_routine_t& vm_handler);
std::uint8_t imm_size(const zydis_routine_t& vm_handler);
bool get(zydis_routine_t& vm_entry, zydis_routine_t& vm_handler, std::uintptr_t handler_addr);
// may throw an exception...
bool get_all(std::uintptr_t module_base, std::uintptr_t image_base,
zydis_routine_t& vm_entry, std::uintptr_t* vm_handler_table, std::vector<handler_t>& vm_handlers);
// can be used on calc_jmp...
bool get_operand_transforms(const zydis_routine_t& vm_handler, transform::map_t& transforms);
vm::handler::profile_t* get_profile(handler_t& vm_handler);
namespace table
{
std::uintptr_t* get(const zydis_routine_t& vm_entry);
bool get_transform(const zydis_routine_t& vm_entry, zydis_decoded_instr_t* transform_instr);
std::uint64_t encrypt(zydis_decoded_instr_t& transform_instr, std::uint64_t val);
std::uint64_t decrypt(zydis_decoded_instr_t& transform_instr, std::uint64_t val);
}
namespace profile
{
extern vm::handler::profile_t sregq;

@ -0,0 +1,33 @@
#include <vmprofiler.hpp>
namespace vm
{
namespace calc_jmp
{
bool get(const zydis_routine_t& vm_entry, zydis_routine_t& calc_jmp)
{
auto result = std::find_if(vm_entry.begin(), vm_entry.end(),
[](const zydis_instr_t& instr_data) -> bool
{
// mov/movsx/movzx rax/eax/ax/al, [rsi]
if (instr_data.instr.operand_count > 1 &&
(instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOV ||
instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVSX ||
instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVZX) &&
instr_data.instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
util::reg::to64(instr_data.instr.operands[0].reg.value) == ZYDIS_REGISTER_RAX &&
instr_data.instr.operands[1].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr_data.instr.operands[1].mem.base == ZYDIS_REGISTER_RSI)
return true;
return false;
}
);
if (result == vm_entry.end())
return false;
calc_jmp.insert(calc_jmp.end(), result, vm_entry.end());
return true;
}
}
}

@ -1,115 +0,0 @@
#include "vmctx.h"
namespace vm
{
vmctx_t::vmctx_t(
vmp2::file_header* file_header,
vmp2::entry_t* entry_list,
std::vector<vm::handler_t>& vm_handlers,
std::uintptr_t module_base,
std::uintptr_t image_base
)
: module_base(module_base),
image_base(image_base),
entry_list(entry_list),
file_header(file_header),
vm_handlers(vm_handlers),
idx(0)
{}
std::pair<std::string, const vmp2::entry_t*> vmctx_t::step() const
{
if (idx >= file_header->entry_count)
return {};
const auto vm_handler = &vm_handlers[entry_list[idx].handler_idx];
if (vm_handler->imm_size)
{
const auto operand = get_imm(file_header->advancement,
entry_list[idx].vip, vm_handler->imm_size / 8);
auto transforms = vm_handler->transforms;
auto [decrypted_operand, rolling_key] =
vm::decrypt_operand(transforms,
operand, entry_list[idx].decrypt_key);
if (vm_handler->profile)
{
if (vm_handler->profile->extention ==
vm::handler::extention_t::sign_extend)
{
switch (vm_handler->imm_size)
{
case 8:
{
if ((u8)(decrypted_operand >> 7))
decrypted_operand += ~0xFFull;
break;
}
case 16:
{
if ((u16)(decrypted_operand >> 15))
decrypted_operand += ~0xFFFFull;
break;
}
case 32:
{
if ((u32)(decrypted_operand >> 31))
decrypted_operand += ~0xFFFFFFFFull;
break;
}
default:
throw std::invalid_argument(
"invalid imm size for sign extention...\n");
}
}
}
char buff[256];
if (vm_handler->profile)
{
snprintf(buff, sizeof buff, "%s 0x%p",
vm_handler->profile->name, decrypted_operand);
}
else
{
snprintf(buff, sizeof buff, "UNK(%d) 0x%p",
entry_list[idx].handler_idx, decrypted_operand);
}
return { buff, &entry_list[idx++] };
}
if (vm_handler->profile)
return { vm_handler->profile->name, &entry_list[idx++] };
char buff[256];
snprintf(buff, sizeof buff, "UNK(%d)", entry_list[idx++].handler_idx);
return { buff, &entry_list[idx++] };
}
std::uintptr_t vmctx_t::get_imm(vmp2::exec_type_t exec_type_t,
std::uint32_t vip_offset, std::uint8_t imm_size) const
{
std::uintptr_t operand = 0u;
if (file_header->advancement == vmp2::exec_type_t::forward)
{
const auto operand_ptr =
reinterpret_cast<void*>((entry_list[idx].vip -
file_header->module_base) + module_base);
memcpy(&operand, operand_ptr, imm_size);
}
else
{
const auto operand_ptr =
reinterpret_cast<void*>(((entry_list[idx].vip -
file_header->module_base) + module_base) - imm_size);
memcpy(&operand, operand_ptr, imm_size);
}
return operand;
}
}

@ -1,244 +1,7 @@
#include "vm.h"
#include <vmprofiler.hpp>
namespace vm
{
std::pair<std::uint64_t, std::uint64_t> decrypt_operand(transform::map_t& transforms,
std::uint64_t operand, std::uint64_t rolling_key)
{
const auto generic_decrypt_0 = &transforms[transform::type::generic0];
const auto key_decrypt = &transforms[transform::type::rolling_key];
const auto generic_decrypt_1 = &transforms[transform::type::generic1];
const auto generic_decrypt_2 = &transforms[transform::type::generic2];
const auto generic_decrypt_3 = &transforms[transform::type::generic3];
const auto update_key = &transforms[transform::type::update_key];
if (generic_decrypt_0->mnemonic != ZYDIS_MNEMONIC_INVALID)
{
operand = transform::apply(
generic_decrypt_0->operands[0].size,
generic_decrypt_0->mnemonic, operand,
// check to see if this instruction has an IMM...
transform::has_imm(generic_decrypt_0) ?
generic_decrypt_0->operands[1].imm.value.u : 0);
}
// apply transformation with rolling decrypt key...
operand = transform::apply(key_decrypt->operands[0].size,
key_decrypt->mnemonic, operand, rolling_key);
// apply three generic transformations...
{
operand = transform::apply(
generic_decrypt_1->operands[0].size,
generic_decrypt_1->mnemonic, operand,
// check to see if this instruction has an IMM...
transform::has_imm(generic_decrypt_1) ?
generic_decrypt_1->operands[1].imm.value.u : 0);
operand = transform::apply(
generic_decrypt_2->operands[0].size,
generic_decrypt_2->mnemonic, operand,
// check to see if this instruction has an IMM...
transform::has_imm(generic_decrypt_2) ?
generic_decrypt_2->operands[1].imm.value.u : 0);
operand = transform::apply(
generic_decrypt_3->operands[0].size,
generic_decrypt_3->mnemonic, operand,
// check to see if this instruction has an IMM...
transform::has_imm(generic_decrypt_3) ?
generic_decrypt_3->operands[1].imm.value.u : 0);
}
// update rolling key...
auto result = transform::apply(update_key->operands[0].size,
update_key->mnemonic, rolling_key, operand);
// update decryption key correctly...
switch (update_key->operands[0].size)
{
case 8:
rolling_key = (rolling_key & ~0xFFull) + result;
break;
case 16:
rolling_key = (rolling_key & ~0xFFFFull) + result;
break;
default:
rolling_key = result;
break;
}
return { operand, rolling_key };
}
void inverse_transforms(transform::map_t& transforms, transform::map_t& inverse)
{
inverse[transform::type::generic0] = transforms[transform::type::generic0];
inverse[transform::type::generic0].mnemonic =
transform::inverse[transforms[transform::type::generic0].mnemonic];
inverse[transform::type::rolling_key] = transforms[transform::type::rolling_key];
inverse[transform::type::rolling_key].mnemonic =
transform::inverse[transforms[transform::type::rolling_key].mnemonic];
inverse[transform::type::generic1] = transforms[transform::type::generic1];
inverse[transform::type::generic1].mnemonic =
transform::inverse[transforms[transform::type::generic1].mnemonic];
inverse[transform::type::generic2] = transforms[transform::type::generic2];
inverse[transform::type::generic2].mnemonic =
transform::inverse[transforms[transform::type::generic2].mnemonic];
inverse[transform::type::generic3] = transforms[transform::type::generic3];
inverse[transform::type::generic3].mnemonic =
transform::inverse[transforms[transform::type::generic3].mnemonic];
inverse[transform::type::update_key] = transforms[transform::type::update_key];
inverse[transform::type::update_key].mnemonic =
transform::inverse[transforms[transform::type::update_key].mnemonic];
}
std::pair<std::uint64_t, std::uint64_t> encrypt_operand(transform::map_t& transforms,
std::uint64_t operand, std::uint64_t rolling_key)
{
transform::map_t inverse;
inverse_transforms(transforms, inverse);
const auto generic_decrypt_0 = &inverse[transform::type::generic0];
const auto key_decrypt = &inverse[transform::type::rolling_key];
const auto generic_decrypt_1 = &inverse[transform::type::generic1];
const auto generic_decrypt_2 = &inverse[transform::type::generic2];
const auto generic_decrypt_3 = &inverse[transform::type::generic3];
const auto update_key = &inverse[transform::type::update_key];
auto result = transform::apply(update_key->operands[0].size,
update_key->mnemonic, rolling_key, operand);
// make sure we update the rolling decryption key correctly...
switch (update_key->operands[0].size)
{
case 8:
rolling_key = (rolling_key & ~0xFFull) + result;
break;
case 16:
rolling_key = (rolling_key & ~0xFFFFull) + result;
break;
default:
rolling_key = result;
break;
}
{
operand = transform::apply(
generic_decrypt_3->operands[0].size,
generic_decrypt_3->mnemonic, operand,
// check to see if this instruction has an IMM...
transform::has_imm(generic_decrypt_3) ?
generic_decrypt_3->operands[1].imm.value.u : 0);
operand = transform::apply(
generic_decrypt_2->operands[0].size,
generic_decrypt_2->mnemonic, operand,
// check to see if this instruction has an IMM...
transform::has_imm(generic_decrypt_2) ?
generic_decrypt_2->operands[1].imm.value.u : 0);
operand = transform::apply(
generic_decrypt_1->operands[0].size,
generic_decrypt_1->mnemonic, operand,
// check to see if this instruction has an IMM...
transform::has_imm(generic_decrypt_1) ?
generic_decrypt_1->operands[1].imm.value.u : 0);
}
operand = transform::apply(key_decrypt->operands[0].size,
key_decrypt->mnemonic, operand, rolling_key);
if (generic_decrypt_0->mnemonic != ZYDIS_MNEMONIC_INVALID)
{
operand = transform::apply(
generic_decrypt_0->operands[0].size,
generic_decrypt_0->mnemonic, operand,
// check to see if this instruction has an IMM...
transform::has_imm(generic_decrypt_0) ?
generic_decrypt_0->operands[1].imm.value.u : 0);
}
return { operand, rolling_key };
}
bool get_calc_jmp(const zydis_routine_t& vm_entry, zydis_routine_t& calc_jmp)
{
auto result = std::find_if(vm_entry.begin(), vm_entry.end(),
[](const zydis_instr_t& instr_data) -> bool
{
// mov/movsx/movzx rax/eax/ax/al, [rsi]
if (instr_data.instr.operand_count > 1 &&
(instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOV ||
instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVSX ||
instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVZX) &&
instr_data.instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
util::reg::to64(instr_data.instr.operands[0].reg.value) == ZYDIS_REGISTER_RAX &&
instr_data.instr.operands[1].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr_data.instr.operands[1].mem.base == ZYDIS_REGISTER_RSI)
return true;
return false;
}
);
if (result == vm_entry.end())
return false;
calc_jmp.insert(calc_jmp.end(), result, vm_entry.end());
return true;
}
bool get_vinstr_rva_transform(
const zydis_routine_t& vm_entry, zydis_decoded_instr_t* transform_instr)
{
//
// find mov esi, [rsp+0xA0]
//
auto result = std::find_if(vm_entry.begin(), vm_entry.end(),
[](const zydis_instr_t& instr_data) -> bool
{
if (instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr_data.instr.operand_count == 2 &&
instr_data.instr.operands[0].reg.value == ZYDIS_REGISTER_ESI &&
instr_data.instr.operands[1].mem.base == ZYDIS_REGISTER_RSP &&
instr_data.instr.operands[1].mem.disp.has_displacement &&
instr_data.instr.operands[1].mem.disp.value == 0xA0)
return true;
return false;
}
);
if (result == vm_entry.end())
return false;
//
// find the next instruction with ESI as the dest...
//
result = std::find_if(++result, vm_entry.end(),
[](const zydis_instr_t& instr_data) -> bool
{
if (instr_data.instr.operands[0].reg.value == ZYDIS_REGISTER_ESI)
return true;
return false;
}
);
if (result == vm_entry.end())
return false;
*transform_instr = result->instr;
transform_instr->mnemonic = transform::inverse[result->instr.mnemonic];
return true;
}
namespace handler
{
bool get(zydis_routine_t& calc_jmp, zydis_routine_t& vm_handler, std::uintptr_t handler_addr)
@ -248,7 +11,7 @@ namespace vm
vm::util::deobfuscate(vm_handler);
static const auto calc_jmp_check =
static const auto calc_jmp_check =
[&](std::uintptr_t addr) -> bool
{
for (const auto& [instr, instr_raw, instr_addr] : calc_jmp)
@ -259,8 +22,8 @@ namespace vm
};
auto result = std::find_if(
vm_handler.begin(), vm_handler.end(),
[](const zydis_instr_t& instr) -> bool
vm_handler.begin(), vm_handler.end(),
[](const zydis_instr_t& instr) -> bool
{
if (instr.instr.mnemonic == ZYDIS_MNEMONIC_LEA &&
instr.instr.operands[0].reg.value == ZYDIS_REGISTER_RAX &&
@ -311,15 +74,15 @@ namespace vm
return true;
}
bool get_all(std::uintptr_t module_base, std::uintptr_t image_base,
zydis_routine_t& vm_entry, std::uintptr_t* vm_handler_table, std::vector<vm::handler_t>& vm_handlers)
bool get_all(std::uintptr_t module_base, std::uintptr_t image_base,
zydis_routine_t& vm_entry, std::uintptr_t* vm_handler_table, std::vector<vm::handler::handler_t>& vm_handlers)
{
zydis_decoded_instr_t instr;
if (!vm::handler::table::get_transform(vm_entry, &instr))
return false;
zydis_routine_t calc_jmp;
if (!vm::get_calc_jmp(vm_entry, calc_jmp))
if (!vm::calc_jmp::get(vm_entry, calc_jmp))
return false;
for (auto idx = 0u; idx < 256; ++idx)
@ -328,7 +91,7 @@ namespace vm
vm::handler::table::decrypt(
instr, vm_handler_table[idx]);
vm::handler_t vm_handler;
handler_t vm_handler;
vm::transform::map_t transforms;
zydis_routine_t vm_handler_instrs;
@ -358,7 +121,7 @@ namespace vm
bool has_imm(const zydis_routine_t& vm_handler)
{
const auto result = std::find_if(
vm_handler.begin(), vm_handler.end(),
vm_handler.begin(), vm_handler.end(),
[](const zydis_instr_t& instr_data) -> bool
{
// mov/movsx/movzx rax/eax/ax/al, [rsi]
@ -429,8 +192,8 @@ namespace vm
// this finds the first transformation which looks like:
// transform rax, rbx <--- note these registers can be smaller so we to64 them...
auto key_transform = std::find_if(imm_fetch, vm_handler.end(),
[](const zydis_instr_t& instr_data) -> bool
auto key_transform = std::find_if(imm_fetch, vm_handler.end(),
[](const zydis_instr_t& instr_data) -> bool
{
if (util::reg::compare(instr_data.instr.operands[0].reg.value, ZYDIS_REGISTER_RAX) &&
util::reg::compare(instr_data.instr.operands[1].reg.value, ZYDIS_REGISTER_RBX))
@ -489,10 +252,10 @@ namespace vm
return true;
}
vm::handler::profile_t* get_profile(vm::handler_t& vm_handler)
vm::handler::profile_t* get_profile(handler_t& vm_handler)
{
static const auto vcontains =
[](vm::handler::profile_t* vprofile, vm::handler_t* vm_handler) -> bool
[](vm::handler::profile_t* vprofile, handler_t* vm_handler) -> bool
{
if (vprofile->imm_size != vm_handler->imm_size)
return false;

@ -0,0 +1,191 @@
#include <vmprofiler.hpp>
namespace vm
{
namespace instrs
{
std::pair<std::uint64_t, std::uint64_t> decrypt_operand(transform::map_t& transforms,
std::uint64_t operand, std::uint64_t rolling_key)
{
const auto generic_decrypt_0 = &transforms[transform::type::generic0];
const auto key_decrypt = &transforms[transform::type::rolling_key];
const auto generic_decrypt_1 = &transforms[transform::type::generic1];
const auto generic_decrypt_2 = &transforms[transform::type::generic2];
const auto generic_decrypt_3 = &transforms[transform::type::generic3];
const auto update_key = &transforms[transform::type::update_key];
if (generic_decrypt_0->mnemonic != ZYDIS_MNEMONIC_INVALID)
{
operand = transform::apply(
generic_decrypt_0->operands[0].size,
generic_decrypt_0->mnemonic, operand,
// check to see if this instruction has an IMM...
transform::has_imm(generic_decrypt_0) ?
generic_decrypt_0->operands[1].imm.value.u : 0);
}
// apply transformation with rolling decrypt key...
operand = transform::apply(key_decrypt->operands[0].size,
key_decrypt->mnemonic, operand, rolling_key);
// apply three generic transformations...
{
operand = transform::apply(
generic_decrypt_1->operands[0].size,
generic_decrypt_1->mnemonic, operand,
// check to see if this instruction has an IMM...
transform::has_imm(generic_decrypt_1) ?
generic_decrypt_1->operands[1].imm.value.u : 0);
operand = transform::apply(
generic_decrypt_2->operands[0].size,
generic_decrypt_2->mnemonic, operand,
// check to see if this instruction has an IMM...
transform::has_imm(generic_decrypt_2) ?
generic_decrypt_2->operands[1].imm.value.u : 0);
operand = transform::apply(
generic_decrypt_3->operands[0].size,
generic_decrypt_3->mnemonic, operand,
// check to see if this instruction has an IMM...
transform::has_imm(generic_decrypt_3) ?
generic_decrypt_3->operands[1].imm.value.u : 0);
}
// update rolling key...
auto result = transform::apply(update_key->operands[0].size,
update_key->mnemonic, rolling_key, operand);
// update decryption key correctly...
switch (update_key->operands[0].size)
{
case 8:
rolling_key = (rolling_key & ~0xFFull) + result;
break;
case 16:
rolling_key = (rolling_key & ~0xFFFFull) + result;
break;
default:
rolling_key = result;
break;
}
return { operand, rolling_key };
}
std::pair<std::uint64_t, std::uint64_t> encrypt_operand(transform::map_t& transforms,
std::uint64_t operand, std::uint64_t rolling_key)
{
transform::map_t inverse;
inverse_transforms(transforms, inverse);
const auto generic_decrypt_0 = &inverse[transform::type::generic0];
const auto key_decrypt = &inverse[transform::type::rolling_key];
const auto generic_decrypt_1 = &inverse[transform::type::generic1];
const auto generic_decrypt_2 = &inverse[transform::type::generic2];
const auto generic_decrypt_3 = &inverse[transform::type::generic3];
const auto update_key = &inverse[transform::type::update_key];
auto result = transform::apply(update_key->operands[0].size,
update_key->mnemonic, rolling_key, operand);
// make sure we update the rolling decryption key correctly...
switch (update_key->operands[0].size)
{
case 8:
rolling_key = (rolling_key & ~0xFFull) + result;
break;
case 16:
rolling_key = (rolling_key & ~0xFFFFull) + result;
break;
default:
rolling_key = result;
break;
}
{
operand = transform::apply(
generic_decrypt_3->operands[0].size,
generic_decrypt_3->mnemonic, operand,
// check to see if this instruction has an IMM...
transform::has_imm(generic_decrypt_3) ?
generic_decrypt_3->operands[1].imm.value.u : 0);
operand = transform::apply(
generic_decrypt_2->operands[0].size,
generic_decrypt_2->mnemonic, operand,
// check to see if this instruction has an IMM...
transform::has_imm(generic_decrypt_2) ?
generic_decrypt_2->operands[1].imm.value.u : 0);
operand = transform::apply(
generic_decrypt_1->operands[0].size,
generic_decrypt_1->mnemonic, operand,
// check to see if this instruction has an IMM...
transform::has_imm(generic_decrypt_1) ?
generic_decrypt_1->operands[1].imm.value.u : 0);
}
operand = transform::apply(key_decrypt->operands[0].size,
key_decrypt->mnemonic, operand, rolling_key);
if (generic_decrypt_0->mnemonic != ZYDIS_MNEMONIC_INVALID)
{
operand = transform::apply(
generic_decrypt_0->operands[0].size,
generic_decrypt_0->mnemonic, operand,
// check to see if this instruction has an IMM...
transform::has_imm(generic_decrypt_0) ?
generic_decrypt_0->operands[1].imm.value.u : 0);
}
return { operand, rolling_key };
}
bool get_rva_decrypt(
const zydis_routine_t& vm_entry, std::vector<zydis_decoded_instr_t>& transform_instrs)
{
//
// find mov esi, [rsp+0xA0]
//
auto result = std::find_if(vm_entry.begin(), vm_entry.end(),
[](const zydis_instr_t& instr_data) -> bool
{
if (instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr_data.instr.operand_count == 2 &&
instr_data.instr.operands[0].reg.value == ZYDIS_REGISTER_ESI &&
instr_data.instr.operands[1].mem.base == ZYDIS_REGISTER_RSP &&
instr_data.instr.operands[1].mem.disp.has_displacement &&
instr_data.instr.operands[1].mem.disp.value == 0xA0)
return true;
return false;
}
);
if (result == vm_entry.end())
return false;
//
// find the next three instruction with ESI as the dest...
//
for (auto idx = 0u; idx < 3; ++idx)
{
result = std::find_if(++result, vm_entry.end(),
[](const zydis_instr_t& instr_data) -> bool
{
return instr_data.instr.operands[0].reg.value == ZYDIS_REGISTER_ESI;
}
);
if (result == vm_entry.end())
return false;
transform_instrs.push_back(result->instr);
}
return true;
}
}
}

@ -100,8 +100,9 @@
</ProjectReference>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="vm.cpp" />
<ClCompile Include="vmctx.cpp" />
<ClCompile Include="calc_jmp.cpp" />
<ClCompile Include="vmhandler.cpp" />
<ClCompile Include="vminstrs.cpp" />
<ClCompile Include="vmprofiles\add.cpp" />
<ClCompile Include="vmprofiles\div.cpp" />
<ClCompile Include="vmprofiles\jmp.cpp" />
@ -163,9 +164,6 @@
<ClInclude Include="..\dependencies\zydis\msvc\ZycoreExportConfig.h" />
<ClInclude Include="..\dependencies\zydis\msvc\ZydisExportConfig.h" />
<ClInclude Include="..\include\transform.hpp" />
<ClInclude Include="..\include\vm.h" />
<ClInclude Include="..\include\vmctx.h" />
<ClInclude Include="..\include\vmp2.hpp" />
<ClInclude Include="..\include\vmprofiler.hpp" />
<ClInclude Include="..\include\vmutils.h" />
</ItemGroup>

@ -29,15 +29,9 @@
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="vm.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vmutils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vmctx.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vmprofiles\add.cpp">
<Filter>Source Files\vmprofiles</Filter>
</ClCompile>
@ -80,20 +74,20 @@
<ClCompile Include="vmprofiles\shr.cpp">
<Filter>Source Files\vmprofiles</Filter>
</ClCompile>
<ClCompile Include="calc_jmp.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vmhandler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vminstrs.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\include\transform.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\vm.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\vmctx.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\vmp2.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\vmprofiler.hpp">
<Filter>Header Files</Filter>
</ClInclude>

@ -9,114 +9,8 @@ namespace vm
{
zydis_register_t to64(zydis_register_t reg)
{
switch (reg)
{
case ZYDIS_REGISTER_AL:
return ZYDIS_REGISTER_RAX;
case ZYDIS_REGISTER_CL:
return ZYDIS_REGISTER_RCX;
case ZYDIS_REGISTER_DL:
return ZYDIS_REGISTER_RDX;
case ZYDIS_REGISTER_BL:
return ZYDIS_REGISTER_RBX;
case ZYDIS_REGISTER_AH:
return ZYDIS_REGISTER_RAX;
case ZYDIS_REGISTER_CH:
return ZYDIS_REGISTER_RCX;
case ZYDIS_REGISTER_DH:
return ZYDIS_REGISTER_RDX;
case ZYDIS_REGISTER_BH:
return ZYDIS_REGISTER_RBX;
case ZYDIS_REGISTER_SPL:
return ZYDIS_REGISTER_RSP;
case ZYDIS_REGISTER_BPL:
return ZYDIS_REGISTER_RBP;
case ZYDIS_REGISTER_SIL:
return ZYDIS_REGISTER_RSI;
case ZYDIS_REGISTER_DIL:
return ZYDIS_REGISTER_RDI;
case ZYDIS_REGISTER_R8B:
return ZYDIS_REGISTER_R8;
case ZYDIS_REGISTER_R9B:
return ZYDIS_REGISTER_R9;
case ZYDIS_REGISTER_R10B:
return ZYDIS_REGISTER_R10;
case ZYDIS_REGISTER_R11B:
return ZYDIS_REGISTER_R11;
case ZYDIS_REGISTER_R12B:
return ZYDIS_REGISTER_R12;
case ZYDIS_REGISTER_R13B:
return ZYDIS_REGISTER_R13;
case ZYDIS_REGISTER_R14B:
return ZYDIS_REGISTER_R14;
case ZYDIS_REGISTER_R15B:
return ZYDIS_REGISTER_R15;
case ZYDIS_REGISTER_AX:
return ZYDIS_REGISTER_RAX;
case ZYDIS_REGISTER_CX:
return ZYDIS_REGISTER_RCX;
case ZYDIS_REGISTER_DX:
return ZYDIS_REGISTER_RDX;
case ZYDIS_REGISTER_BX:
return ZYDIS_REGISTER_RBX;
case ZYDIS_REGISTER_SP:
return ZYDIS_REGISTER_RSP;
case ZYDIS_REGISTER_BP:
return ZYDIS_REGISTER_RBP;
case ZYDIS_REGISTER_SI:
return ZYDIS_REGISTER_RSI;
case ZYDIS_REGISTER_DI:
return ZYDIS_REGISTER_RDI;
case ZYDIS_REGISTER_R8W:
return ZYDIS_REGISTER_R8;
case ZYDIS_REGISTER_R9W:
return ZYDIS_REGISTER_R9;
case ZYDIS_REGISTER_R10W:
return ZYDIS_REGISTER_R10;
case ZYDIS_REGISTER_R11W:
return ZYDIS_REGISTER_R11;
case ZYDIS_REGISTER_R12W:
return ZYDIS_REGISTER_R12;
case ZYDIS_REGISTER_R13W:
return ZYDIS_REGISTER_R13;
case ZYDIS_REGISTER_R14W:
return ZYDIS_REGISTER_R14;
case ZYDIS_REGISTER_R15W:
return ZYDIS_REGISTER_R15;
case ZYDIS_REGISTER_EAX:
return ZYDIS_REGISTER_RAX;
case ZYDIS_REGISTER_ECX:
return ZYDIS_REGISTER_RCX;
case ZYDIS_REGISTER_EDX:
return ZYDIS_REGISTER_RDX;
case ZYDIS_REGISTER_EBX:
return ZYDIS_REGISTER_RBX;
case ZYDIS_REGISTER_ESP:
return ZYDIS_REGISTER_RSP;
case ZYDIS_REGISTER_EBP:
return ZYDIS_REGISTER_RBP;
case ZYDIS_REGISTER_ESI:
return ZYDIS_REGISTER_RSI;
case ZYDIS_REGISTER_EDI:
return ZYDIS_REGISTER_RDI;
case ZYDIS_REGISTER_R8D:
return ZYDIS_REGISTER_R8;
case ZYDIS_REGISTER_R9D:
return ZYDIS_REGISTER_R9;
case ZYDIS_REGISTER_R10D:
return ZYDIS_REGISTER_R10;
case ZYDIS_REGISTER_R11D:
return ZYDIS_REGISTER_R11;
case ZYDIS_REGISTER_R12D:
return ZYDIS_REGISTER_R12;
case ZYDIS_REGISTER_R13D:
return ZYDIS_REGISTER_R13;
case ZYDIS_REGISTER_R14D:
return ZYDIS_REGISTER_R14;
case ZYDIS_REGISTER_R15D:
return ZYDIS_REGISTER_R15;
}
return reg;
return ZydisRegisterGetLargestEnclosing(
ZYDIS_MACHINE_MODE_LONG_64, reg);
}
bool compare(zydis_register_t a, zydis_register_t b)

Loading…
Cancel
Save