|
|
@ -1,10 +1,12 @@
|
|
|
|
#include <vmlocate.hpp>
|
|
|
|
#include <vmlocate.hpp>
|
|
|
|
|
|
|
|
|
|
|
|
namespace vm::locate
|
|
|
|
namespace vm::locate {
|
|
|
|
{
|
|
|
|
std::uintptr_t sigscan(void* base,
|
|
|
|
std::uintptr_t sigscan( void *base, std::uint32_t size, const char *pattern, const char *mask )
|
|
|
|
std::uint32_t size,
|
|
|
|
{
|
|
|
|
const char* pattern,
|
|
|
|
static const auto check_mask = [ & ]( const char *base, const char *pattern, const char *mask ) -> bool {
|
|
|
|
const char* mask) {
|
|
|
|
|
|
|
|
static const auto check_mask = [&](const char* base, const char* pattern,
|
|
|
|
|
|
|
|
const char* mask) -> bool {
|
|
|
|
for (; *mask; ++base, ++pattern, ++mask)
|
|
|
|
for (; *mask; ++base, ++pattern, ++mask)
|
|
|
|
if (*mask == 'x' && *base != *pattern)
|
|
|
|
if (*mask == 'x' && *base != *pattern)
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
@ -12,8 +14,7 @@ namespace vm::locate
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
size -= std::strlen(mask);
|
|
|
|
size -= std::strlen(mask);
|
|
|
|
for ( auto i = 0; i <= size; ++i )
|
|
|
|
for (auto i = 0; i <= size; ++i) {
|
|
|
|
{
|
|
|
|
|
|
|
|
void* addr = (void*)&(((char*)base)[i]);
|
|
|
|
void* addr = (void*)&(((char*)base)[i]);
|
|
|
|
if (check_mask((char*)addr, pattern, mask))
|
|
|
|
if (check_mask((char*)addr, pattern, mask))
|
|
|
|
return reinterpret_cast<std::uintptr_t>(addr);
|
|
|
|
return reinterpret_cast<std::uintptr_t>(addr);
|
|
|
@ -22,17 +23,18 @@ namespace vm::locate
|
|
|
|
return {};
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::vector< vm_enter_t > get_vm_entries( std::uintptr_t module_base, std::uint32_t module_size )
|
|
|
|
std::vector<vm_enter_t> get_vm_entries(std::uintptr_t module_base,
|
|
|
|
{
|
|
|
|
std::uint32_t module_size) {
|
|
|
|
std::uintptr_t result = module_base;
|
|
|
|
std::uintptr_t result = module_base;
|
|
|
|
std::vector<vm_enter_t> entries;
|
|
|
|
std::vector<vm_enter_t> entries;
|
|
|
|
|
|
|
|
|
|
|
|
static const auto push_regs = [&](const zydis_routine_t& rtn) -> bool {
|
|
|
|
static const auto push_regs = [&](const zydis_routine_t& rtn) -> bool {
|
|
|
|
for ( unsigned reg = ZYDIS_REGISTER_RAX; reg < ZYDIS_REGISTER_R15; ++reg )
|
|
|
|
for (unsigned reg = ZYDIS_REGISTER_RAX; reg < ZYDIS_REGISTER_R15; ++reg) {
|
|
|
|
{
|
|
|
|
auto res = std::find_if(
|
|
|
|
auto res = std::find_if( rtn.begin(), rtn.end(), [ & ]( const zydis_instr_t &instr ) -> bool {
|
|
|
|
rtn.begin(), rtn.end(), [&](const zydis_instr_t& instr) -> bool {
|
|
|
|
return instr.instr.mnemonic == ZYDIS_MNEMONIC_PUSH &&
|
|
|
|
return instr.instr.mnemonic == ZYDIS_MNEMONIC_PUSH &&
|
|
|
|
instr.instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
|
|
|
|
instr.instr.operands[0].type ==
|
|
|
|
|
|
|
|
ZYDIS_OPERAND_TYPE_REGISTER &&
|
|
|
|
instr.instr.operands[0].reg.value == reg;
|
|
|
|
instr.instr.operands[0].reg.value == reg;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
@ -43,9 +45,9 @@ namespace vm::locate
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
do
|
|
|
|
do {
|
|
|
|
{
|
|
|
|
result = sigscan((void*)++result, module_size - (result - module_base),
|
|
|
|
result = sigscan( ( void * )++result, module_size - ( result - module_base ), PUSH_4B_IMM, PUSH_4B_MASK );
|
|
|
|
PUSH_4B_IMM, PUSH_4B_MASK);
|
|
|
|
|
|
|
|
|
|
|
|
zydis_routine_t rtn;
|
|
|
|
zydis_routine_t rtn;
|
|
|
|
if (!scn::executable(module_base, result))
|
|
|
|
if (!scn::executable(module_base, result))
|
|
|
@ -54,7 +56,8 @@ namespace vm::locate
|
|
|
|
if (!vm::util::flatten(rtn, result, false, 500, module_base))
|
|
|
|
if (!vm::util::flatten(rtn, result, false, 500, module_base))
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
// the last instruction in the stream should be a JMP to a register or a return instruction...
|
|
|
|
// the last instruction in the stream should be a JMP to a register or a
|
|
|
|
|
|
|
|
// return instruction...
|
|
|
|
const auto& last_instr = rtn[rtn.size() - 1];
|
|
|
|
const auto& last_instr = rtn[rtn.size() - 1];
|
|
|
|
if (!((last_instr.instr.mnemonic == ZYDIS_MNEMONIC_JMP &&
|
|
|
|
if (!((last_instr.instr.mnemonic == ZYDIS_MNEMONIC_JMP &&
|
|
|
|
last_instr.instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER) ||
|
|
|
|
last_instr.instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER) ||
|
|
|
@ -123,16 +126,6 @@ namespace vm::locate
|
|
|
|
if (!push_regs(rtn))
|
|
|
|
if (!push_regs(rtn))
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
// check for a mov r13, rax...
|
|
|
|
|
|
|
|
if ( !vm::locate::find( rtn, [ & ]( const zydis_instr_t &instr ) -> bool {
|
|
|
|
|
|
|
|
return instr.instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
|
|
|
|
|
|
|
|
instr.instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
|
|
|
|
|
|
|
|
instr.instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_R13 &&
|
|
|
|
|
|
|
|
instr.instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
|
|
|
|
|
|
|
|
instr.instr.operands[ 1 ].reg.value == ZYDIS_REGISTER_RAX;
|
|
|
|
|
|
|
|
} ) )
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// check for a mov reg, rsp
|
|
|
|
// check for a mov reg, rsp
|
|
|
|
if (!vm::locate::find(rtn, [&](const zydis_instr_t& instr) -> bool {
|
|
|
|
if (!vm::locate::find(rtn, [&](const zydis_instr_t& instr) -> bool {
|
|
|
|
return instr.instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
|
|
|
|
return instr.instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
|
|
|
@ -157,7 +150,8 @@ namespace vm::locate
|
|
|
|
// existing entry already exits...
|
|
|
|
// existing entry already exits...
|
|
|
|
|
|
|
|
|
|
|
|
auto push_val = (std::uint32_t)rtn[0].instr.operands[0].imm.value.u;
|
|
|
|
auto push_val = (std::uint32_t)rtn[0].instr.operands[0].imm.value.u;
|
|
|
|
if ( std::find_if( entries.begin(), entries.end(), [ & ]( const vm_enter_t &vm_enter ) -> bool {
|
|
|
|
if (std::find_if(entries.begin(), entries.end(),
|
|
|
|
|
|
|
|
[&](const vm_enter_t& vm_enter) -> bool {
|
|
|
|
return vm_enter.encrypted_rva == push_val;
|
|
|
|
return vm_enter.encrypted_rva == push_val;
|
|
|
|
}) != entries.end())
|
|
|
|
}) != entries.end())
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|