You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
vmprofiler/src/vminstrs.cpp

166 lines
7.5 KiB

#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;
}
} // namespace instrs
} // namespace vm