|
|
|
@ -152,16 +152,14 @@ namespace vm
|
|
|
|
|
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;
|
|
|
|
|
return ( 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 );
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
if ( imm_fetch == vm_handler.end() )
|
|
|
|
@ -169,52 +167,51 @@ 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 =
|
|
|
|
|
auto transform_instr =
|
|
|
|
|
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;
|
|
|
|
|
return vm::transform::valid( instr_data.instr.mnemonic ) &&
|
|
|
|
|
instr_data.instr.operands[ 0 ].actions & ZYDIS_OPERAND_ACTION_WRITE &&
|
|
|
|
|
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 );
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
if ( key_transform == vm_handler.end() )
|
|
|
|
|
if ( transform_instr == 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 ) &&
|
|
|
|
|
auto generic0 = std::find_if( imm_fetch, transform_instr, []( const zydis_instr_t &instr_data ) -> bool {
|
|
|
|
|
return vm::transform::valid( instr_data.instr.mnemonic ) &&
|
|
|
|
|
instr_data.instr.operands[ 0 ].actions & ZYDIS_OPERAND_ACTION_WRITE &&
|
|
|
|
|
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;
|
|
|
|
|
transforms[ transform::type::generic0 ] = generic0 != transform_instr ? 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::rolling_key ] = transform_instr->instr;
|
|
|
|
|
auto instr_copy = transform_instr->instr;
|
|
|
|
|
instr_copy.operands[ 0 ].reg.value = transform_instr->instr.operands[ 1 ].reg.value;
|
|
|
|
|
instr_copy.operands[ 1 ].reg.value = transform_instr->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 )
|
|
|
|
|
for ( auto idx = static_cast< unsigned >( vm::transform::type::generic1 );
|
|
|
|
|
idx < static_cast< unsigned >( vm::transform::type::update_key ); ++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;
|
|
|
|
|
transform_instr =
|
|
|
|
|
std::find_if( ++transform_instr, vm_handler.end(), []( const zydis_instr_t &instr_data ) -> bool {
|
|
|
|
|
return vm::transform::valid( instr_data.instr.mnemonic ) &&
|
|
|
|
|
instr_data.instr.operands[0].actions & ZYDIS_OPERAND_ACTION_WRITE &&
|
|
|
|
|
util::reg::compare( instr_data.instr.operands[ 0 ].reg.value, ZYDIS_REGISTER_RAX );
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
if ( generic_transform == vm_handler.end() )
|
|
|
|
|
if ( transform_instr == vm_handler.end() )
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
transforms[ ( transform::type )( idx ) ] = generic_transform->instr;
|
|
|
|
|
transforms[ static_cast< vm::transform::type >( idx ) ] = transform_instr->instr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
@ -255,13 +252,10 @@ namespace vm
|
|
|
|
|
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;
|
|
|
|
|
return 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...
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
if ( result == vm_entry.end() )
|
|
|
|
@ -275,42 +269,34 @@ namespace vm
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
return 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 );
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
// 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() ||
|
|
|
|
|
if ( 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 ) )
|
|
|
|
|
( handler_fetch->instr.operands[ 0 ].reg.value != ZYDIS_REGISTER_RCX &&
|
|
|
|
|
handler_fetch->instr.operands[ 0 ].reg.value != 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;
|
|
|
|
|
return instr_data.instr.operands[ 0 ].reg.value ==
|
|
|
|
|
handler_fetch->instr.operands[ 0 ].reg.value &&
|
|
|
|
|
instr_data.instr.operands[ 0 ].actions & ZYDIS_OPERAND_ACTION_WRITE;
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
if ( handler_transform == vm_entry.end() )
|
|
|
|
|