fixed clang-format disaster

merge-requests/2/head
_xeroxz 3 years ago
parent 3e6974e35e
commit fc46c63445

@ -1,10 +0,0 @@
---
BreakBeforeBraces: GNU
CompactNamespaces: 'false'
FixNamespaceComments: 'true'
NamespaceIndentation: All
ObjCBinPackProtocolList: Always
Standard: Cpp11
UseTab: Always
...

@ -2,34 +2,32 @@
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;
});
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;
if (result == vm_entry.end())
return false;
calc_jmp.insert(calc_jmp.end(), result, vm_entry.end());
return true;
}
} // namespace calc_jmp
} // namespace vm
calc_jmp.insert(calc_jmp.end(), result, vm_entry.end());
return true;
}
}
}

@ -2,407 +2,398 @@
namespace vm
{
namespace handler
{
bool get(zydis_routine_t &calc_jmp, zydis_routine_t &vm_handler,
std::uintptr_t handler_addr)
{
if (!vm::util::flatten(vm_handler, handler_addr))
return false;
vm::util::deobfuscate(vm_handler);
static const auto calc_jmp_check = [&](std::uintptr_t addr) -> bool {
for (const auto &[instr, instr_raw, instr_addr] : calc_jmp)
if (instr_addr == addr)
return true;
return false;
};
auto result = std::find_if(
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 &&
instr.instr.operands[1].mem.base == ZYDIS_REGISTER_RDI &&
instr.instr.operands[1].mem.disp.value == 0xE0)
return true;
return calc_jmp_check(instr.addr);
});
// remove calc_jmp from the vm handler vector...
if (result != vm_handler.end())
vm_handler.erase(result, vm_handler.end());
else // locate the last mov al, [rsi],
// then remove all instructions after that...
namespace handler
{
zydis_routine_t::iterator last = vm_handler.end();
result = vm_handler.begin();
while (result != vm_handler.end())
{
result = std::find_if(
++result, vm_handler.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_handler.end())
last = result;
}
if (last != vm_handler.end())
vm_handler.erase(last, vm_handler.end());
}
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::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::calc_jmp::get(vm_entry, calc_jmp))
return false;
for (auto idx = 0u; idx < 256; ++idx)
{
const auto decrypt_val =
vm::handler::table::decrypt(instr, vm_handler_table[idx]);
bool get(zydis_routine_t& calc_jmp, zydis_routine_t& vm_handler, std::uintptr_t handler_addr)
{
if (!vm::util::flatten(vm_handler, handler_addr))
return false;
vm::util::deobfuscate(vm_handler);
static const auto calc_jmp_check =
[&](std::uintptr_t addr) -> bool
{
for (const auto& [instr, instr_raw, instr_addr] : calc_jmp)
if (instr_addr == addr)
return true;
return false;
};
auto result = std::find_if(
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 &&
instr.instr.operands[1].mem.base == ZYDIS_REGISTER_RDI &&
instr.instr.operands[1].mem.disp.value == 0xE0)
return true;
return calc_jmp_check(instr.addr);
}
);
// remove calc_jmp from the vm handler vector...
if (result != vm_handler.end())
vm_handler.erase(result, vm_handler.end());
else // locate the last mov al, [rsi],
// then remove all instructions after that...
{
zydis_routine_t::iterator last = vm_handler.end();
result = vm_handler.begin();
while (result != vm_handler.end())
{
result = std::find_if(
++result, vm_handler.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_handler.end())
last = result;
}
if (last != vm_handler.end())
vm_handler.erase(last, vm_handler.end());
}
return true;
}
handler_t vm_handler;
vm::transform::map_t transforms;
zydis_routine_t vm_handler_instrs;
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;
if (!vm::handler::get(calc_jmp, vm_handler_instrs,
(decrypt_val - image_base) + module_base))
return false;
zydis_routine_t calc_jmp;
if (!vm::calc_jmp::get(vm_entry, calc_jmp))
return false;
const auto has_imm = vm::handler::has_imm(vm_handler_instrs);
for (auto idx = 0u; idx < 256; ++idx)
{
const auto decrypt_val =
vm::handler::table::decrypt(
instr, vm_handler_table[idx]);
const auto imm_size = vm::handler::imm_size(vm_handler_instrs);
handler_t vm_handler;
vm::transform::map_t transforms;
zydis_routine_t vm_handler_instrs;
if (has_imm && !vm::handler::get_operand_transforms(vm_handler_instrs,
transforms))
return false;
if (!vm::handler::get(calc_jmp, vm_handler_instrs, (decrypt_val - image_base) + module_base))
return false;
vm_handler.address = (decrypt_val - image_base) + module_base;
vm_handler.instrs = vm_handler_instrs;
vm_handler.imm_size = imm_size;
vm_handler.transforms = transforms;
vm_handler.profile = vm::handler::get_profile(vm_handler);
vm_handlers.push_back(vm_handler);
}
const auto has_imm =
vm::handler::has_imm(vm_handler_instrs);
return true;
}
bool has_imm(const zydis_routine_t &vm_handler)
{
const auto result = std::find_if(
vm_handler.begin(), vm_handler.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;
});
return result != vm_handler.end();
}
std::uint8_t imm_size(const zydis_routine_t &vm_handler)
{
const auto result = std::find_if(
vm_handler.begin(), vm_handler.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_handler.end())
return 0u;
return result->instr.operands[1].size;
}
bool get_operand_transforms(const zydis_routine_t &vm_handler,
transform::map_t &transforms)
{
auto imm_fetch = std::find_if(
vm_handler.begin(), vm_handler.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 (imm_fetch == vm_handler.end())
return false;
// 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 {
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))
return true;
return false;
});
if (key_transform == vm_handler.end())
return false;
// look for a primer/instruction that alters RAX prior to the 5
// transformations...
auto generic0 = std::find_if(
imm_fetch + 1, key_transform,
[](const zydis_instr_t &instr_data) -> bool {
return 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);
});
zydis_decoded_instr_t nogeneric0;
nogeneric0.mnemonic = ZYDIS_MNEMONIC_INVALID;
transforms[transform::type::generic0] =
generic0 != key_transform ? generic0->instr : nogeneric0;
// last transformation is the same as the first except src and dest are
// swwapped...
transforms[transform::type::rolling_key] = key_transform->instr;
auto instr_copy = key_transform->instr;
instr_copy.operands[0].reg.value =
key_transform->instr.operands[1].reg.value;
instr_copy.operands[1].reg.value =
key_transform->instr.operands[0].reg.value;
transforms[transform::type::update_key] = instr_copy;
// three generic transformations...
auto generic_transform = key_transform;
for (auto idx = 2u; idx < 5; ++idx)
{
generic_transform = std::find_if(
++generic_transform, vm_handler.end(),
[](const zydis_instr_t &instr_data) -> bool {
if (util::reg::compare(instr_data.instr.operands[0].reg.value,
ZYDIS_REGISTER_RAX))
return true;
const auto imm_size =
vm::handler::imm_size(vm_handler_instrs);
return false;
});
if (has_imm && !vm::handler::get_operand_transforms(vm_handler_instrs, transforms))
return false;
if (generic_transform == vm_handler.end())
return false;
vm_handler.address = (decrypt_val - image_base) + module_base;
vm_handler.instrs = vm_handler_instrs;
vm_handler.imm_size = imm_size;
vm_handler.transforms = transforms;
vm_handler.profile = vm::handler::get_profile(vm_handler);
vm_handlers.push_back(vm_handler);
}
transforms[(transform::type)(idx)] = generic_transform->instr;
}
return true;
}
return true;
}
vm::handler::profile_t *get_profile(handler_t &vm_handler)
{
static const auto vcontains = [](vm::handler::profile_t *vprofile,
handler_t *vm_handler) -> bool {
if (vprofile->imm_size != vm_handler->imm_size)
return false;
for (auto &instr : vprofile->signature)
{
const auto contains = std::find_if(
vm_handler->instrs.begin(), vm_handler->instrs.end(),
[&](zydis_instr_t &instr_data) -> bool {
return instr(instr_data.instr);
});
if (contains == vm_handler->instrs.end())
return false;
}
return true;
};
for (auto profile : vm::handler::profile::all)
if (vcontains(profile, &vm_handler))
return profile;
return nullptr;
}
namespace table
{
std::uintptr_t *get(const zydis_routine_t &vm_entry)
{
const auto result = std::find_if(
vm_entry.begin(), vm_entry.end(),
[](const zydis_instr_t &instr_data) -> bool {
const auto instr = &instr_data.instr;
// lea r12, vm_handlers... (always r12)...
if (instr->mnemonic == ZYDIS_MNEMONIC_LEA &&
instr->operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr->operands[0].reg.value == ZYDIS_REGISTER_R12 &&
!instr->raw.sib.base) // no register used for the sib base...
return true;
return false;
});
if (result == vm_entry.end())
return nullptr;
std::uintptr_t ptr = 0u;
ZydisCalcAbsoluteAddress(&result->instr, &result->instr.operands[1],
result->addr, &ptr);
return reinterpret_cast<std::uintptr_t *>(ptr);
}
bool get_transform(const zydis_routine_t &vm_entry,
zydis_decoded_instr_t *transform_instr)
{
zydis_register_t rcx_or_rdx = ZYDIS_REGISTER_NONE;
auto handler_fetch = std::find_if(
vm_entry.begin(), vm_entry.end(),
[&](const zydis_instr_t &instr_data) -> bool {
const auto instr = &instr_data.instr;
if (instr->mnemonic == ZYDIS_MNEMONIC_MOV &&
instr->operand_count == 2 &&
instr->operands[1].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr->operands[1].mem.base == ZYDIS_REGISTER_R12 &&
instr->operands[1].mem.index == ZYDIS_REGISTER_RAX &&
instr->operands[1].mem.scale == 8 &&
instr->operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
(instr->operands[0].reg.value == ZYDIS_REGISTER_RDX ||
instr->operands[0].reg.value == ZYDIS_REGISTER_RCX))
bool has_imm(const zydis_routine_t& vm_handler)
{
rcx_or_rdx = instr->operands[0].reg.value;
return true;
const auto result = std::find_if(
vm_handler.begin(), vm_handler.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;
}
);
return result != vm_handler.end();
}
return false;
});
// check to see if we found the fetch instruction and if the next
// instruction is not the end of the vector...
if (handler_fetch == vm_entry.end() ||
++handler_fetch == vm_entry.end() ||
// must be RCX or RDX... else something went wrong...
(rcx_or_rdx != ZYDIS_REGISTER_RCX &&
rcx_or_rdx != ZYDIS_REGISTER_RDX))
return false;
// find the next instruction that writes to RCX or RDX...
// the register is determined by the vm handler fetch above...
auto handler_transform = std::find_if(
handler_fetch, vm_entry.end(),
[&](const zydis_instr_t &instr_data) -> bool {
if (instr_data.instr.operands[0].reg.value == rcx_or_rdx &&
instr_data.instr.operands[0].actions &
ZYDIS_OPERAND_ACTION_WRITE)
return true;
return false;
});
if (handler_transform == vm_entry.end())
return false;
*transform_instr = handler_transform->instr;
return true;
}
std::uint64_t encrypt(zydis_decoded_instr_t &transform_instr,
std::uint64_t val)
{
assert(transform_instr.operands[0].size == 64,
"invalid transformation for vm handler table entries...");
const auto operation = vm::transform::inverse[transform_instr.mnemonic];
const auto bitsize = transform_instr.operands[0].size;
const auto imm = vm::transform::has_imm(&transform_instr)
? transform_instr.operands[1].imm.value.u
: 0u;
return vm::transform::apply(bitsize, operation, val, imm);
}
std::uint64_t decrypt(zydis_decoded_instr_t &transform_instr,
std::uint64_t val)
{
assert(transform_instr.operands[0].size == 64,
"invalid transformation for vm handler table entries...");
const auto operation = transform_instr.mnemonic;
const auto bitsize = transform_instr.operands[0].size;
const auto imm = vm::transform::has_imm(&transform_instr)
? transform_instr.operands[1].imm.value.u
: 0u;
return vm::transform::apply(bitsize, operation, val, imm);
}
} // namespace table
} // namespace handler
} // namespace vm
std::uint8_t imm_size(const zydis_routine_t& vm_handler)
{
const auto result = std::find_if(
vm_handler.begin(), vm_handler.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_handler.end())
return 0u;
return result->instr.operands[1].size;
}
bool get_operand_transforms(const zydis_routine_t& vm_handler, transform::map_t& transforms)
{
auto imm_fetch = std::find_if(
vm_handler.begin(), vm_handler.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 (imm_fetch == vm_handler.end())
return false;
// 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
{
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))
return true;
return false;
}
);
if (key_transform == vm_handler.end())
return false;
// look for a primer/instruction that alters RAX prior to the 5 transformations...
auto generic0 = std::find_if(imm_fetch + 1, key_transform,
[](const zydis_instr_t& instr_data) -> bool
{
return 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);
}
);
zydis_decoded_instr_t nogeneric0;
nogeneric0.mnemonic = ZYDIS_MNEMONIC_INVALID;
transforms[transform::type::generic0] =
generic0 != key_transform ? generic0->instr : nogeneric0;
// last transformation is the same as the first except src and dest are swwapped...
transforms[transform::type::rolling_key] = key_transform->instr;
auto instr_copy = key_transform->instr;
instr_copy.operands[0].reg.value = key_transform->instr.operands[1].reg.value;
instr_copy.operands[1].reg.value = key_transform->instr.operands[0].reg.value;
transforms[transform::type::update_key] = instr_copy;
// three generic transformations...
auto generic_transform = key_transform;
for (auto idx = 2u; idx < 5; ++idx)
{
generic_transform = std::find_if(++generic_transform, vm_handler.end(),
[](const zydis_instr_t& instr_data) -> bool
{
if (util::reg::compare(instr_data.instr.operands[0].reg.value, ZYDIS_REGISTER_RAX))
return true;
return false;
}
);
if (generic_transform == vm_handler.end())
return false;
transforms[(transform::type)(idx)] = generic_transform->instr;
}
return true;
}
vm::handler::profile_t* get_profile(handler_t& vm_handler)
{
static const auto vcontains =
[](vm::handler::profile_t* vprofile, handler_t* vm_handler) -> bool
{
if (vprofile->imm_size != vm_handler->imm_size)
return false;
for (auto& instr : vprofile->signature)
{
const auto contains = std::find_if
(
vm_handler->instrs.begin(),
vm_handler->instrs.end(),
[&](zydis_instr_t& instr_data) -> bool
{ return instr(instr_data.instr); }
);
if (contains == vm_handler->instrs.end())
return false;
}
return true;
};
for (auto profile : vm::handler::profile::all)
if (vcontains(profile, &vm_handler))
return profile;
return nullptr;
}
namespace table
{
std::uintptr_t* get(const zydis_routine_t& vm_entry)
{
const auto result = std::find_if(
vm_entry.begin(), vm_entry.end(),
[](const zydis_instr_t& instr_data) -> bool
{
const auto instr = &instr_data.instr;
// lea r12, vm_handlers... (always r12)...
if (instr->mnemonic == ZYDIS_MNEMONIC_LEA &&
instr->operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr->operands[0].reg.value == ZYDIS_REGISTER_R12 &&
!instr->raw.sib.base) // no register used for the sib base...
return true;
return false;
}
);
if (result == vm_entry.end())
return nullptr;
std::uintptr_t ptr = 0u;
ZydisCalcAbsoluteAddress(&result->instr,
&result->instr.operands[1], result->addr, &ptr);
return reinterpret_cast<std::uintptr_t*>(ptr);
}
bool get_transform(const zydis_routine_t& vm_entry, zydis_decoded_instr_t* transform_instr)
{
zydis_register_t rcx_or_rdx = ZYDIS_REGISTER_NONE;
auto handler_fetch = std::find_if(
vm_entry.begin(), vm_entry.end(),
[&](const zydis_instr_t& instr_data) -> bool
{
const auto instr = &instr_data.instr;
if (instr->mnemonic == ZYDIS_MNEMONIC_MOV &&
instr->operand_count == 2 &&
instr->operands[1].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr->operands[1].mem.base == ZYDIS_REGISTER_R12 &&
instr->operands[1].mem.index == ZYDIS_REGISTER_RAX &&
instr->operands[1].mem.scale == 8 &&
instr->operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
(instr->operands[0].reg.value == ZYDIS_REGISTER_RDX ||
instr->operands[0].reg.value == ZYDIS_REGISTER_RCX))
{
rcx_or_rdx = instr->operands[0].reg.value;
return true;
}
return false;
}
);
// check to see if we found the fetch instruction and if the next instruction
// is not the end of the vector...
if (handler_fetch == vm_entry.end() || ++handler_fetch == vm_entry.end() ||
// must be RCX or RDX... else something went wrong...
(rcx_or_rdx != ZYDIS_REGISTER_RCX && rcx_or_rdx != ZYDIS_REGISTER_RDX))
return false;
// find the next instruction that writes to RCX or RDX...
// the register is determined by the vm handler fetch above...
auto handler_transform = std::find_if(
handler_fetch, vm_entry.end(),
[&](const zydis_instr_t& instr_data) -> bool
{
if (instr_data.instr.operands[0].reg.value == rcx_or_rdx &&
instr_data.instr.operands[0].actions & ZYDIS_OPERAND_ACTION_WRITE)
return true;
return false;
}
);
if (handler_transform == vm_entry.end())
return false;
*transform_instr = handler_transform->instr;
return true;
}
std::uint64_t encrypt(zydis_decoded_instr_t& transform_instr, std::uint64_t val)
{
assert(transform_instr.operands[0].size == 64,
"invalid transformation for vm handler table entries...");
const auto operation = vm::transform::inverse[transform_instr.mnemonic];
const auto bitsize = transform_instr.operands[0].size;
const auto imm = vm::transform::has_imm(&transform_instr) ?
transform_instr.operands[1].imm.value.u : 0u;
return vm::transform::apply(bitsize, operation, val, imm);
}
std::uint64_t decrypt(zydis_decoded_instr_t& transform_instr, std::uint64_t val)
{
assert(transform_instr.operands[0].size == 64,
"invalid transformation for vm handler table entries...");
const auto operation = transform_instr.mnemonic;
const auto bitsize = transform_instr.operands[0].size;
const auto imm = vm::transform::has_imm(&transform_instr) ?
transform_instr.operands[1].imm.value.u : 0u;
return vm::transform::apply(bitsize, operation, val, imm);
}
}
}
}

@ -2,191 +2,190 @@
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)
namespace instrs
{
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);
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;
}
}
// 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;
}
} // namespace instrs
} // namespace vm
}

@ -1,206 +1,227 @@
< ? xml version = "1.0" encoding =
"utf-8" ? > <Project ToolsVersion = "4.0" xmlns =
"http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup><Filter Include = "Source Files">
<UniqueIdentifier>{4FC737F1 - C7A5 - 4376 - A066 -
2A32D752A2FF}</ UniqueIdentifier>
<Extensions> cpp;
c;
cc;
cxx;
c++;
cppm;
ixx;
def;
odl;
idl;
hpj;
bat;
asm;
asmx</ Extensions></ Filter><Filter Include = "Header Files"><UniqueIdentifier>{
93995380 - 89BD - 4b04 - 88EB - 625FBE52EBFB}</ UniqueIdentifier>
<Extensions> h;
hh;
hpp;
hxx;
h++;
hm;
inl;
inc;
ipp;
xsd</ Extensions></ Filter><Filter Include = "Header Files\Zydis">
<UniqueIdentifier>{b85373f1 - 1f33 - 4b4f - aadd -
04432b6d62f0}</ UniqueIdentifier></ Filter>
<Filter Include = "Header Files\Zycore"><UniqueIdentifier>{
f57dabfd - 2fe1 - 46a9 - 96d5 - 990cd620eda3}</ UniqueIdentifier>
</ Filter><Filter Include = "Header Files\Zydis\Generated">
<UniqueIdentifier>{40b5c3d5 - 2a68 - 4f45 - b655 -
b621ef669204}</ UniqueIdentifier></ Filter>
<Filter Include = "Header Files\Zydis\Internal"><UniqueIdentifier>{
4dc3025a - a1f4 - 460d - b992 - 1ed53e44f2c0}</ UniqueIdentifier>
</ Filter><Filter Include = "Header Files\Zycore\API"><UniqueIdentifier>{
a4d9e340 - 8f8c - 4606 - bce8 - 58b86119c829}</ UniqueIdentifier>
</ Filter><Filter Include = "Source Files\vmprofiles"><UniqueIdentifier>{
388154c1 - cb08 - 493f - 88fb - 7e16cfffa010}</ UniqueIdentifier>
</ Filter></ ItemGroup><ItemGroup><ClCompile Include = "vmutils.cpp">
<Filter> Source Files</ Filter></ ClCompile>
<ClCompile Include = "vmprofiles\add.cpp">
<Filter> Source Files\vmprofiles</ Filter></ ClCompile>
<ClCompile Include = "vmprofiles\div.cpp">
<Filter> Source Files\vmprofiles</ Filter></ ClCompile>
<ClCompile Include = "vmprofiles\jmp.cpp">
<Filter> Source Files\vmprofiles</ Filter></ ClCompile>
<ClCompile Include = "vmprofiles\lconst.cpp">
<Filter> Source Files\vmprofiles</ Filter></ ClCompile>
<ClCompile Include = "vmprofiles\lreg.cpp">
<Filter> Source Files\vmprofiles</ Filter></ ClCompile>
<ClCompile Include = "vmprofiles\mul.cpp">
<Filter> Source Files\vmprofiles</ Filter></ ClCompile>
<ClCompile Include = "vmprofiles\nand.cpp">
<Filter> Source Files\vmprofiles</ Filter></ ClCompile>
<ClCompile Include = "vmprofiles\pushvsp.cpp">
<Filter> Source Files\vmprofiles</ Filter></ ClCompile>
<ClCompile Include = "vmprofiles\read.cpp">
<Filter> Source Files\vmprofiles</ Filter></ ClCompile>
<ClCompile Include = "vmprofiles\sreg.cpp">
<Filter> Source Files\vmprofiles</ Filter></ ClCompile>
<ClCompile Include = "vmprofiles\vmexit.cpp">
<Filter> Source Files\vmprofiles</ Filter></ ClCompile>
<ClCompile Include = "vmprofiles\write.cpp">
<Filter> Source Files\vmprofiles</ Filter></ ClCompile>
<ClCompile Include = "vmprofiles\shl.cpp">
<Filter> Source Files\vmprofiles</ Filter></ ClCompile>
<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\vmprofiler.hpp">
<Filter> Header Files</ Filter></ ClInclude>
<ClInclude Include = "..\include\vmutils.h"><Filter> Header Files</ Filter>
</ ClInclude><ClInclude Include = ".."
"\dependencies\zydis\include\Zydis\Genera"
"ted\EnumInstructionCategory.h">
<Filter> Header Files\Zydis\Generated</ Filter></ ClInclude>
<ClInclude Include =
"..\dependencies\zydis\include\Zydis\Generated\EnumISAExt.h">
<Filter> Header Files\Zydis\Generated</ Filter></ ClInclude>
<ClInclude Include =
"..\dependencies\zydis\include\Zydis\Generated\EnumISASet.h">
<Filter> Header Files\Zydis\Generated</ Filter></ ClInclude>
<ClInclude Include =
"..\dependencies\zydis\include\Zydis\Generated\EnumMnemonic.h">
<Filter> Header Files\Zydis\Generated</ Filter></ ClInclude>
<ClInclude Include =
"..\dependencies\zydis\include\Zydis\Generated\EnumRegister.h">
<Filter> Header Files\Zydis\Generated</ Filter></ ClInclude>
<ClInclude Include =
"..\dependencies\zydis\include\Zydis\Internal\DecoderData.h">
<Filter> Header Files\Zydis\Internal</ Filter></ ClInclude>
<ClInclude Include =
"..\dependencies\zydis\include\Zydis\Internal\FormatterATT.h">
<Filter> Header Files\Zydis\Internal</ Filter></ ClInclude>
<ClInclude Include =
"..\dependencies\zydis\include\Zydis\Internal\FormatterBase.h">
<Filter> Header Files\Zydis\Internal</ Filter></ ClInclude>
<ClInclude Include =
"..\dependencies\zydis\include\Zydis\Internal\FormatterIntel.h">
<Filter> Header Files\Zydis\Internal</ Filter></ ClInclude>
<ClInclude Include =
"..\dependencies\zydis\include\Zydis\Internal\SharedData.h">
<Filter> Header Files\Zydis\Internal</ Filter></ ClInclude>
<ClInclude Include =
"..\dependencies\zydis\include\Zydis\Internal\String.h">
<Filter> Header Files\Zydis\Internal</ Filter></ ClInclude>
<ClInclude Include = "..\dependencies\zydis\include\Zydis\Decoder.h">
<Filter> Header Files\Zydis</ Filter></ ClInclude>
<ClInclude Include = "..\dependencies\zydis\include\Zydis\DecoderTypes.h">
<Filter> Header Files\Zydis</ Filter></ ClInclude>
<ClInclude Include = "..\dependencies\zydis\include\Zydis\Formatter.h">
<Filter> Header Files\Zydis</ Filter></ ClInclude>
<ClInclude Include =
"..\dependencies\zydis\include\Zydis\FormatterBuffer.h">
<Filter> Header Files\Zydis</ Filter></ ClInclude>
<ClInclude Include = "..\dependencies\zydis\include\Zydis\MetaInfo.h">
<Filter> Header Files\Zydis</ Filter></ ClInclude>
<ClInclude Include = "..\dependencies\zydis\include\Zydis\Mnemonic.h">
<Filter> Header Files\Zydis</ Filter></ ClInclude>
<ClInclude Include = "..\dependencies\zydis\include\Zydis\Register.h">
<Filter> Header Files\Zydis</ Filter></ ClInclude>
<ClInclude Include = "..\dependencies\zydis\include\Zydis\SharedTypes.h">
<Filter> Header Files\Zydis</ Filter></ ClInclude>
<ClInclude Include = "..\dependencies\zydis\include\Zydis\ShortString.h">
<Filter> Header Files\Zydis</ Filter></ ClInclude>
<ClInclude Include = "..\dependencies\zydis\include\Zydis\Status.h">
<Filter> Header Files\Zydis</ Filter></ ClInclude>
<ClInclude Include = "..\dependencies\zydis\include\Zydis\Utils.h">
<Filter> Header Files\Zydis</ Filter></ ClInclude>
<ClInclude Include = "..\dependencies\zydis\include\Zydis\Zydis.h">
<Filter> Header Files\Zydis</ Filter></ ClInclude>
<ClInclude Include =
"..\dependencies\zydis\dependencies\zycore\include\Zycore\API\Memory."
"h">
<Filter> Header Files\Zycore\API</ Filter></ ClInclude>
<ClInclude Include = ".."
"\dependencies\zydis\dependencies\zycore\include\Zycor"
"e\API\Synchronization.h">
<Filter> Header Files\Zycore\API</ Filter></ ClInclude>
<ClInclude Include = ".."
"\dependencies\zydis\dependencies\zycore\include\Zycor"
"e\API\Terminal.h">
<Filter> Header Files\Zycore\API</ Filter></ ClInclude>
<ClInclude Include =
"..\dependencies\zydis\dependencies\zycore\include\Zycore\API\Thread."
"h">
<Filter> Header Files\Zycore\API</ Filter></ ClInclude>
<ClInclude Include =
"..\dependencies\zydis\dependencies\zycore\include\Zycore\Allocator.h">
<Filter> Header Files\Zycore</ Filter></ ClInclude>
<ClInclude Include =
"..\dependencies\zydis\dependencies\zycore\include\Zycore\ArgParse.h">
<Filter> Header Files\Zycore</ Filter></ ClInclude>
<ClInclude Include =
"..\dependencies\zydis\dependencies\zycore\include\Zycore\Bitset.h">
<Filter> Header Files\Zycore</ Filter></ ClInclude>
<ClInclude Include =
"..\dependencies\zydis\dependencies\zycore\include\Zycore\Comparison."
"h">
<Filter> Header Files\Zycore</ Filter></ ClInclude>
<ClInclude Include =
"..\dependencies\zydis\dependencies\zycore\include\Zycore\Defines.h">
<Filter> Header Files\Zycore</ Filter></ ClInclude>
<ClInclude Include =
"..\dependencies\zydis\dependencies\zycore\include\Zycore\Format.h">
<Filter> Header Files\Zycore</ Filter></ ClInclude>
<ClInclude Include =
"..\dependencies\zydis\dependencies\zycore\include\Zycore\LibC.h">
<Filter> Header Files\Zycore</ Filter></ ClInclude>
<ClInclude Include =
"..\dependencies\zydis\dependencies\zycore\include\Zycore\List.h">
<Filter> Header Files\Zycore</ Filter></ ClInclude>
<ClInclude Include =
"..\dependencies\zydis\dependencies\zycore\include\Zycore\Object.h">
<Filter> Header Files\Zycore</ Filter></ ClInclude>
<ClInclude Include =
"..\dependencies\zydis\dependencies\zycore\include\Zycore\Status.h">
<Filter> Header Files\Zycore</ Filter></ ClInclude>
<ClInclude Include =
"..\dependencies\zydis\dependencies\zycore\include\Zycore\String.h">
<Filter> Header Files\Zycore</ Filter></ ClInclude>
<ClInclude Include =
"..\dependencies\zydis\dependencies\zycore\include\Zycore\Types.h">
<Filter> Header Files\Zycore</ Filter></ ClInclude>
<ClInclude Include =
"..\dependencies\zydis\dependencies\zycore\include\Zycore\Vector.h">
<Filter> Header Files\Zycore</ Filter></ ClInclude>
<ClInclude Include =
"..\dependencies\zydis\dependencies\zycore\include\Zycore\Zycore.h">
<Filter> Header Files\Zycore</ Filter></ ClInclude>
<ClInclude Include = "..\dependencies\zydis\msvc\ZycoreExportConfig.h">
<Filter> Header Files</ Filter></ ClInclude>
<ClInclude Include = "..\dependencies\zydis\msvc\ZydisExportConfig.h">
<Filter> Header Files</ Filter></ ClInclude></ ItemGroup></ Project>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Header Files\Zydis">
<UniqueIdentifier>{b85373f1-1f33-4b4f-aadd-04432b6d62f0}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\Zycore">
<UniqueIdentifier>{f57dabfd-2fe1-46a9-96d5-990cd620eda3}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\Zydis\Generated">
<UniqueIdentifier>{40b5c3d5-2a68-4f45-b655-b621ef669204}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\Zydis\Internal">
<UniqueIdentifier>{4dc3025a-a1f4-460d-b992-1ed53e44f2c0}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\Zycore\API">
<UniqueIdentifier>{a4d9e340-8f8c-4606-bce8-58b86119c829}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\vmprofiles">
<UniqueIdentifier>{388154c1-cb08-493f-88fb-7e16cfffa010}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="vmutils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vmprofiles\add.cpp">
<Filter>Source Files\vmprofiles</Filter>
</ClCompile>
<ClCompile Include="vmprofiles\div.cpp">
<Filter>Source Files\vmprofiles</Filter>
</ClCompile>
<ClCompile Include="vmprofiles\jmp.cpp">
<Filter>Source Files\vmprofiles</Filter>
</ClCompile>
<ClCompile Include="vmprofiles\lconst.cpp">
<Filter>Source Files\vmprofiles</Filter>
</ClCompile>
<ClCompile Include="vmprofiles\lreg.cpp">
<Filter>Source Files\vmprofiles</Filter>
</ClCompile>
<ClCompile Include="vmprofiles\mul.cpp">
<Filter>Source Files\vmprofiles</Filter>
</ClCompile>
<ClCompile Include="vmprofiles\nand.cpp">
<Filter>Source Files\vmprofiles</Filter>
</ClCompile>
<ClCompile Include="vmprofiles\pushvsp.cpp">
<Filter>Source Files\vmprofiles</Filter>
</ClCompile>
<ClCompile Include="vmprofiles\read.cpp">
<Filter>Source Files\vmprofiles</Filter>
</ClCompile>
<ClCompile Include="vmprofiles\sreg.cpp">
<Filter>Source Files\vmprofiles</Filter>
</ClCompile>
<ClCompile Include="vmprofiles\vmexit.cpp">
<Filter>Source Files\vmprofiles</Filter>
</ClCompile>
<ClCompile Include="vmprofiles\write.cpp">
<Filter>Source Files\vmprofiles</Filter>
</ClCompile>
<ClCompile Include="vmprofiles\shl.cpp">
<Filter>Source Files\vmprofiles</Filter>
</ClCompile>
<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\vmprofiler.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\vmutils.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\include\Zydis\Generated\EnumInstructionCategory.h">
<Filter>Header Files\Zydis\Generated</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\include\Zydis\Generated\EnumISAExt.h">
<Filter>Header Files\Zydis\Generated</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\include\Zydis\Generated\EnumISASet.h">
<Filter>Header Files\Zydis\Generated</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\include\Zydis\Generated\EnumMnemonic.h">
<Filter>Header Files\Zydis\Generated</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\include\Zydis\Generated\EnumRegister.h">
<Filter>Header Files\Zydis\Generated</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\include\Zydis\Internal\DecoderData.h">
<Filter>Header Files\Zydis\Internal</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\include\Zydis\Internal\FormatterATT.h">
<Filter>Header Files\Zydis\Internal</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\include\Zydis\Internal\FormatterBase.h">
<Filter>Header Files\Zydis\Internal</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\include\Zydis\Internal\FormatterIntel.h">
<Filter>Header Files\Zydis\Internal</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\include\Zydis\Internal\SharedData.h">
<Filter>Header Files\Zydis\Internal</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\include\Zydis\Internal\String.h">
<Filter>Header Files\Zydis\Internal</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\include\Zydis\Decoder.h">
<Filter>Header Files\Zydis</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\include\Zydis\DecoderTypes.h">
<Filter>Header Files\Zydis</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\include\Zydis\Formatter.h">
<Filter>Header Files\Zydis</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\include\Zydis\FormatterBuffer.h">
<Filter>Header Files\Zydis</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\include\Zydis\MetaInfo.h">
<Filter>Header Files\Zydis</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\include\Zydis\Mnemonic.h">
<Filter>Header Files\Zydis</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\include\Zydis\Register.h">
<Filter>Header Files\Zydis</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\include\Zydis\SharedTypes.h">
<Filter>Header Files\Zydis</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\include\Zydis\ShortString.h">
<Filter>Header Files\Zydis</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\include\Zydis\Status.h">
<Filter>Header Files\Zydis</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\include\Zydis\Utils.h">
<Filter>Header Files\Zydis</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\include\Zydis\Zydis.h">
<Filter>Header Files\Zydis</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\dependencies\zycore\include\Zycore\API\Memory.h">
<Filter>Header Files\Zycore\API</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\dependencies\zycore\include\Zycore\API\Synchronization.h">
<Filter>Header Files\Zycore\API</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\dependencies\zycore\include\Zycore\API\Terminal.h">
<Filter>Header Files\Zycore\API</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\dependencies\zycore\include\Zycore\API\Thread.h">
<Filter>Header Files\Zycore\API</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\dependencies\zycore\include\Zycore\Allocator.h">
<Filter>Header Files\Zycore</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\dependencies\zycore\include\Zycore\ArgParse.h">
<Filter>Header Files\Zycore</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\dependencies\zycore\include\Zycore\Bitset.h">
<Filter>Header Files\Zycore</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\dependencies\zycore\include\Zycore\Comparison.h">
<Filter>Header Files\Zycore</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\dependencies\zycore\include\Zycore\Defines.h">
<Filter>Header Files\Zycore</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\dependencies\zycore\include\Zycore\Format.h">
<Filter>Header Files\Zycore</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\dependencies\zycore\include\Zycore\LibC.h">
<Filter>Header Files\Zycore</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\dependencies\zycore\include\Zycore\List.h">
<Filter>Header Files\Zycore</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\dependencies\zycore\include\Zycore\Object.h">
<Filter>Header Files\Zycore</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\dependencies\zycore\include\Zycore\Status.h">
<Filter>Header Files\Zycore</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\dependencies\zycore\include\Zycore\String.h">
<Filter>Header Files\Zycore</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\dependencies\zycore\include\Zycore\Types.h">
<Filter>Header Files\Zycore</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\dependencies\zycore\include\Zycore\Vector.h">
<Filter>Header Files\Zycore</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\dependencies\zycore\include\Zycore\Zycore.h">
<Filter>Header Files\Zycore</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\msvc\ZycoreExportConfig.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\dependencies\zydis\msvc\ZydisExportConfig.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

@ -3,229 +3,226 @@
namespace vm
{
namespace util
{
namespace reg
namespace util
{
zydis_register_t to64(zydis_register_t reg)
{
return ZydisRegisterGetLargestEnclosing(ZYDIS_MACHINE_MODE_LONG_64,
reg);
}
bool compare(zydis_register_t a, zydis_register_t b)
{
return to64(a) == to64(b);
}
} // namespace reg
void print(const zydis_decoded_instr_t &instr)
{
char buffer[256];
ZydisFormatter formatter;
ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL);
ZydisFormatterFormatInstruction(&formatter, &instr, buffer,
sizeof(buffer), 0u);
puts(buffer);
}
void print(zydis_routine_t &routine)
{
char buffer[256];
ZydisFormatter formatter;
ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL);
for (auto [instr, raw, addr] : routine)
{
std::printf("> 0x%p ", addr);
ZydisFormatterFormatInstruction(&formatter, &instr, buffer,
sizeof(buffer), addr);
puts(buffer);
}
}
bool is_jmp(const zydis_decoded_instr_t &instr)
{
switch (instr.mnemonic)
{
case ZYDIS_MNEMONIC_JB:
case ZYDIS_MNEMONIC_JBE:
case ZYDIS_MNEMONIC_JCXZ:
case ZYDIS_MNEMONIC_JECXZ:
case ZYDIS_MNEMONIC_JKNZD:
case ZYDIS_MNEMONIC_JKZD:
case ZYDIS_MNEMONIC_JL:
case ZYDIS_MNEMONIC_JLE:
case ZYDIS_MNEMONIC_JMP:
case ZYDIS_MNEMONIC_JNB:
case ZYDIS_MNEMONIC_JNBE:
case ZYDIS_MNEMONIC_JNL:
case ZYDIS_MNEMONIC_JNLE:
case ZYDIS_MNEMONIC_JNO:
case ZYDIS_MNEMONIC_JNP:
case ZYDIS_MNEMONIC_JNS:
case ZYDIS_MNEMONIC_JNZ:
case ZYDIS_MNEMONIC_JO:
case ZYDIS_MNEMONIC_JP:
case ZYDIS_MNEMONIC_JRCXZ:
case ZYDIS_MNEMONIC_JS:
case ZYDIS_MNEMONIC_JZ:
return true;
default:
break;
}
return false;
}
bool flatten(zydis_routine_t &routine, std::uintptr_t routine_addr,
bool keep_jmps)
{
ZydisDecoder decoder;
zydis_decoded_instr_t instr;
ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LONG_64,
ZYDIS_ADDRESS_WIDTH_64);
while (ZYAN_SUCCESS(ZydisDecoderDecodeBuffer(
&decoder, reinterpret_cast<void *>(routine_addr), 0x1000, &instr)))
{
std::vector<u8> raw_instr;
raw_instr.insert(raw_instr.begin(), (u8 *)routine_addr,
(u8 *)routine_addr + instr.length);
if (is_jmp(instr))
{
if (instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER)
{
routine.push_back({instr, raw_instr, routine_addr});
return true;
}
if (keep_jmps)
routine.push_back({instr, raw_instr, routine_addr});
ZydisCalcAbsoluteAddress(&instr, &instr.operands[0], routine_addr,
&routine_addr);
}
else if (instr.mnemonic == ZYDIS_MNEMONIC_RET)
{
routine.push_back({instr, raw_instr, routine_addr});
return true;
}
else
{
routine.push_back({instr, raw_instr, routine_addr});
routine_addr += instr.length;
}
}
return false;
}
void deobfuscate(zydis_routine_t &routine)
{
static const auto _uses = [](ZydisDecodedOperand &op,
zydis_register_t reg) -> bool {
switch (op.type)
{
case ZYDIS_OPERAND_TYPE_MEMORY:
{
return reg::compare(op.mem.base, reg) ||
reg::compare(op.mem.index, reg);
}
case ZYDIS_OPERAND_TYPE_REGISTER:
{
return reg::compare(op.reg.value, reg);
}
}
return false;
};
static const auto _writes = [](zydis_decoded_instr_t &inst) -> bool {
for (auto idx = 0; idx < inst.operand_count; ++idx)
if (inst.operands[idx].actions & ZYDIS_OPERAND_ACTION_MASK_WRITE)
return true;
return false;
};
static const auto _remove =
[](zydis_routine_t &routine, zydis_routine_t::iterator itr,
zydis_register_t reg, u32 opcode_size) -> void {
for (; itr >= routine.begin(); --itr)
{
const auto instruction = &itr->instr;
bool stop = false;
if (instruction->mnemonic == ZYDIS_MNEMONIC_JMP)
continue;
for (auto op_idx = 0u; op_idx < instruction->operand_count;
++op_idx)
{
const auto op = &instruction->operands[op_idx];
if (!_uses(*op, reg))
continue;
if (op->type == ZYDIS_OPERAND_TYPE_MEMORY)
{
stop = true;
continue;
}
if (opcode_size < 32 && op->size > opcode_size)
continue;
if (op->actions & ZYDIS_OPERAND_ACTION_MASK_WRITE)
op->actions &= ~ZYDIS_OPERAND_ACTION_MASK_WRITE;
else
stop = true;
}
if (!_writes(*instruction))
routine.erase(itr);
else if (stop)
break;
}
};
for (const auto &instr_data : routine)
{
if (routine.empty() || routine.size() == 1 ||
instr_data.instr.mnemonic == ZYDIS_MNEMONIC_JMP)
continue;
for (auto itr = routine.begin() + 1; itr != routine.end(); itr++)
{
if (itr->instr.mnemonic == ZYDIS_MNEMONIC_JMP ||
itr->instr.mnemonic == ZYDIS_MNEMONIC_RET)
break;
// find the write operations that happen...
for (auto idx = 0u; idx < itr->instr.operand_count; ++idx)
{
const auto op = &itr->instr.operands[idx];
// if its a read, continue to next opcode...
if (op->actions & ZYDIS_OPERAND_ACTION_MASK_READ)
continue;
// if its not a write then continue to next opcode...
if (!(op->actions & ZYDIS_OPERAND_ACTION_MASK_WRITE))
continue;
// if this operand is not a register then we continue...
if (op->type != ZYDIS_OPERAND_TYPE_REGISTER)
continue;
// else we see if we can remove dead writes to this
// register...
_remove(routine, itr - 1, op->reg.value, op->size);
}
}
}
namespace reg
{
zydis_register_t to64(zydis_register_t reg)
{
return ZydisRegisterGetLargestEnclosing(
ZYDIS_MACHINE_MODE_LONG_64, reg);
}
bool compare(zydis_register_t a, zydis_register_t b)
{
return to64(a) == to64(b);
}
}
void print(const zydis_decoded_instr_t& instr)
{
char buffer[256];
ZydisFormatter formatter;
ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL);
ZydisFormatterFormatInstruction(&formatter, &instr,
buffer, sizeof(buffer), 0u);
puts(buffer);
}
void print(zydis_routine_t& routine)
{
char buffer[256];
ZydisFormatter formatter;
ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL);
for (auto [instr, raw, addr] : routine)
{
std::printf("> 0x%p ", addr);
ZydisFormatterFormatInstruction(&formatter, &instr,
buffer, sizeof(buffer), addr);
puts(buffer);
}
}
bool is_jmp(const zydis_decoded_instr_t& instr)
{
switch (instr.mnemonic)
{
case ZYDIS_MNEMONIC_JB:
case ZYDIS_MNEMONIC_JBE:
case ZYDIS_MNEMONIC_JCXZ:
case ZYDIS_MNEMONIC_JECXZ:
case ZYDIS_MNEMONIC_JKNZD:
case ZYDIS_MNEMONIC_JKZD:
case ZYDIS_MNEMONIC_JL:
case ZYDIS_MNEMONIC_JLE:
case ZYDIS_MNEMONIC_JMP:
case ZYDIS_MNEMONIC_JNB:
case ZYDIS_MNEMONIC_JNBE:
case ZYDIS_MNEMONIC_JNL:
case ZYDIS_MNEMONIC_JNLE:
case ZYDIS_MNEMONIC_JNO:
case ZYDIS_MNEMONIC_JNP:
case ZYDIS_MNEMONIC_JNS:
case ZYDIS_MNEMONIC_JNZ:
case ZYDIS_MNEMONIC_JO:
case ZYDIS_MNEMONIC_JP:
case ZYDIS_MNEMONIC_JRCXZ:
case ZYDIS_MNEMONIC_JS:
case ZYDIS_MNEMONIC_JZ:
return true;
default:
break;
}
return false;
}
bool flatten(zydis_routine_t& routine, std::uintptr_t routine_addr, bool keep_jmps)
{
ZydisDecoder decoder;
zydis_decoded_instr_t instr;
ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_ADDRESS_WIDTH_64);
while (ZYAN_SUCCESS(ZydisDecoderDecodeBuffer(&decoder, reinterpret_cast<void*>(
routine_addr), 0x1000, &instr)))
{
std::vector<u8> raw_instr;
raw_instr.insert(raw_instr.begin(),
(u8*)routine_addr,
(u8*)routine_addr + instr.length);
if (is_jmp(instr))
{
if (instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER)
{
routine.push_back({ instr, raw_instr, routine_addr });
return true;
}
if (keep_jmps)
routine.push_back({ instr, raw_instr, routine_addr });
ZydisCalcAbsoluteAddress(&instr, &instr.operands[0], routine_addr, &routine_addr);
}
else if (instr.mnemonic == ZYDIS_MNEMONIC_RET)
{
routine.push_back({ instr, raw_instr, routine_addr });
return true;
}
else
{
routine.push_back({ instr, raw_instr, routine_addr });
routine_addr += instr.length;
}
}
return false;
}
void deobfuscate(zydis_routine_t& routine)
{
static const auto _uses =
[](ZydisDecodedOperand& op, zydis_register_t reg) -> bool
{
switch (op.type)
{
case ZYDIS_OPERAND_TYPE_MEMORY:
{
return reg::compare(op.mem.base, reg) || reg::compare(op.mem.index, reg);
}
case ZYDIS_OPERAND_TYPE_REGISTER:
{
return reg::compare(op.reg.value, reg);
}
}
return false;
};
static const auto _writes =
[](zydis_decoded_instr_t& inst) -> bool
{
for (auto idx = 0; idx < inst.operand_count; ++idx)
if (inst.operands[idx].actions & ZYDIS_OPERAND_ACTION_MASK_WRITE)
return true;
return false;
};
static const auto _remove =
[](zydis_routine_t& routine, zydis_routine_t::iterator itr,
zydis_register_t reg, u32 opcode_size) -> void
{
for (; itr >= routine.begin(); --itr)
{
const auto instruction = &itr->instr;
bool stop = false;
if (instruction->mnemonic == ZYDIS_MNEMONIC_JMP)
continue;
for (auto op_idx = 0u; op_idx < instruction->operand_count; ++op_idx)
{
const auto op = &instruction->operands[op_idx];
if (!_uses(*op, reg))
continue;
if (op->type == ZYDIS_OPERAND_TYPE_MEMORY)
{
stop = true;
continue;
}
if (opcode_size < 32 && op->size > opcode_size)
continue;
if (op->actions & ZYDIS_OPERAND_ACTION_MASK_WRITE)
op->actions &= ~ZYDIS_OPERAND_ACTION_MASK_WRITE;
else stop = true;
}
if (!_writes(*instruction))
routine.erase(itr);
else if (stop) break;
}
};
for (const auto& instr_data : routine)
{
if (routine.empty() || routine.size() == 1 ||
instr_data.instr.mnemonic == ZYDIS_MNEMONIC_JMP)
continue;
for (auto itr = routine.begin() + 1; itr != routine.end(); itr++)
{
if (itr->instr.mnemonic == ZYDIS_MNEMONIC_JMP ||
itr->instr.mnemonic == ZYDIS_MNEMONIC_RET)
break;
// find the write operations that happen...
for (auto idx = 0u; idx < itr->instr.operand_count; ++idx)
{
const auto op = &itr->instr.operands[idx];
// if its a read, continue to next opcode...
if (op->actions & ZYDIS_OPERAND_ACTION_MASK_READ)
continue;
// if its not a write then continue to next opcode...
if (!(op->actions & ZYDIS_OPERAND_ACTION_MASK_WRITE))
continue;
// if this operand is not a register then we continue...
if (op->type != ZYDIS_OPERAND_TYPE_REGISTER)
continue;
// else we see if we can remove dead writes to this register...
_remove(routine, itr - 1, op->reg.value, op->size);
}
}
}
}
}
} // namespace util
} // namespace vm
}
Loading…
Cancel
Save