From 0115f85798948f25c6f1f52fc3f6a055204492b5 Mon Sep 17 00:00:00 2001 From: _xeroxz Date: Tue, 1 Jun 2021 20:30:45 -0700 Subject: [PATCH] fixed some issues with getting operand decryption transforms --- include/transform.hpp | 9 +++- include/vmutils.h | 1 + src/vmhandler.cpp | 114 ++++++++++++++++++------------------------ 3 files changed, 58 insertions(+), 66 deletions(-) diff --git a/include/transform.hpp b/include/transform.hpp index d24facb..bc2ef88 100644 --- a/include/transform.hpp +++ b/include/transform.hpp @@ -136,19 +136,24 @@ namespace vm template < class T > inline const auto _dec = []( T a, T b ) -> T { return a - 1; }; template < class T > - inline std::map< ZydisMnemonic, transform_t< T > > transforms = { + inline std::map< zydis_mnemonic_t, transform_t< T > > transforms = { { ZYDIS_MNEMONIC_ADD, _add< T > }, { ZYDIS_MNEMONIC_XOR, _xor< T > }, { ZYDIS_MNEMONIC_BSWAP, _bswap< T > }, { ZYDIS_MNEMONIC_SUB, _sub< T > }, { ZYDIS_MNEMONIC_NEG, _neg< T > }, { ZYDIS_MNEMONIC_NOT, _not< T > }, { ZYDIS_MNEMONIC_ROR, _ror< T > }, { ZYDIS_MNEMONIC_ROL, _rol< T > }, { ZYDIS_MNEMONIC_INC, _inc< T > }, { ZYDIS_MNEMONIC_DEC, _dec< T > } }; - inline std::map< ZydisMnemonic, ZydisMnemonic > inverse = { + inline std::map< zydis_mnemonic_t, zydis_mnemonic_t > inverse = { { ZYDIS_MNEMONIC_ADD, ZYDIS_MNEMONIC_SUB }, { ZYDIS_MNEMONIC_XOR, ZYDIS_MNEMONIC_XOR }, { ZYDIS_MNEMONIC_BSWAP, ZYDIS_MNEMONIC_BSWAP }, { ZYDIS_MNEMONIC_SUB, ZYDIS_MNEMONIC_ADD }, { ZYDIS_MNEMONIC_NEG, ZYDIS_MNEMONIC_NEG }, { ZYDIS_MNEMONIC_NOT, ZYDIS_MNEMONIC_NOT }, { ZYDIS_MNEMONIC_ROR, ZYDIS_MNEMONIC_ROL }, { ZYDIS_MNEMONIC_ROL, ZYDIS_MNEMONIC_ROR }, { ZYDIS_MNEMONIC_INC, ZYDIS_MNEMONIC_DEC }, { ZYDIS_MNEMONIC_DEC, ZYDIS_MNEMONIC_INC } }; + inline bool valid( zydis_mnemonic_t op ) + { + return transforms< std::uint8_t >.find( op ) != transforms< std::uint8_t >.end(); + } + inline void inverse_transforms( transform::map_t &transforms, transform::map_t &inverse ) { inverse[ transform::type::generic0 ] = transforms[ transform::type::generic0 ]; diff --git a/include/vmutils.h b/include/vmutils.h index aa1811b..9a9bac0 100644 --- a/include/vmutils.h +++ b/include/vmutils.h @@ -12,6 +12,7 @@ using u128 = __m128; using zydis_decoded_instr_t = ZydisDecodedInstruction; using zydis_register_t = ZydisRegister; +using zydis_mnemonic_t = ZydisMnemonic; struct zydis_instr_t { diff --git a/src/vmhandler.cpp b/src/vmhandler.cpp index 22b89fb..f84f109 100644 --- a/src/vmhandler.cpp +++ b/src/vmhandler.cpp @@ -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() )