From 8d564257b262e47a4c01575d91492f035cd93c7e Mon Sep 17 00:00:00 2001 From: _xeroxz Date: Tue, 1 Jun 2021 19:41:04 -0700 Subject: [PATCH 1/8] remove useless if and just return instead... --- src/calc_jmp.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/calc_jmp.cpp b/src/calc_jmp.cpp index 0902287..cf0a41e 100644 --- a/src/calc_jmp.cpp +++ b/src/calc_jmp.cpp @@ -9,16 +9,14 @@ namespace vm 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; + 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 ( result == vm_entry.end() ) From 0115f85798948f25c6f1f52fc3f6a055204492b5 Mon Sep 17 00:00:00 2001 From: _xeroxz Date: Tue, 1 Jun 2021 20:30:45 -0700 Subject: [PATCH 2/8] 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() ) From 1aba5d017f5e31e3043987b941d641b136f88e10 Mon Sep 17 00:00:00 2001 From: _xeroxz Date: Tue, 1 Jun 2021 20:44:34 -0700 Subject: [PATCH 3/8] cleaned the code, removed useless if's, added operand action checks --- src/calc_jmp.cpp | 50 ++++++++++++------------------------------ src/vmhandler.cpp | 56 ++++++++++++++++++++--------------------------- src/vmutils.cpp | 2 -- 3 files changed, 38 insertions(+), 70 deletions(-) diff --git a/src/calc_jmp.cpp b/src/calc_jmp.cpp index cf0a41e..e612da1 100644 --- a/src/calc_jmp.cpp +++ b/src/calc_jmp.cpp @@ -30,8 +30,9 @@ namespace vm { auto result = std::find_if( calc_jmp.begin(), calc_jmp.end(), []( const zydis_instr_t &instr_data ) -> bool { - // look for any instruction with RSI being the first operand... - return instr_data.instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER && + // look for any instruction with RSI being the first operand and its being written too.. + return instr_data.instr.operands[ 0 ].actions & ZYDIS_OPERAND_ACTION_WRITE && + instr_data.instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER && instr_data.instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RSI; } ); @@ -43,45 +44,22 @@ namespace vm switch ( instr->mnemonic ) { case ZYDIS_MNEMONIC_LEA: - { + // if operand type is memory, then return advancement type + // based off of the disposition value... (neg == backward, pos == forward) if ( instr->operands[ 1 ].type == ZYDIS_OPERAND_TYPE_MEMORY ) - { - if ( instr->operands[ 1 ].mem.disp.value > 0 ) - return vmp2::exec_type_t::forward; - else - return vmp2::exec_type_t::backward; - } - // else we dont know what we are looking at... - return {}; - } + return instr->operands[ 1 ].mem.disp.value > 0 ? vmp2::exec_type_t::forward + : vmp2::exec_type_t::backward; + break; case ZYDIS_MNEMONIC_ADD: - { - // ADD RSI, IMM... if ( instr->operands[ 1 ].type == ZYDIS_OPERAND_TYPE_IMMEDIATE ) - { - // see if IMM is negitive... - if ( instr->operands[ 1 ].imm.value.s > 0 ) - return vmp2::exec_type_t::forward; - else // adding a negitive number is sub... - return vmp2::exec_type_t::backward; - } - // else we dont know what we are looking at... - return {}; - } + return instr->operands[ 1 ].imm.value.s > 0 ? vmp2::exec_type_t::forward + : vmp2::exec_type_t::backward; + break; case ZYDIS_MNEMONIC_SUB: - { - // SUB RSI, IMM... if ( instr->operands[ 1 ].type == ZYDIS_OPERAND_TYPE_IMMEDIATE ) - { - // see if IMM is negitive... - if ( instr->operands[ 1 ].imm.value.s > 0 ) - return vmp2::exec_type_t::backward; - else // subtracting a negitive number means you are adding... - return vmp2::exec_type_t::forward; - } - // else we dont know what we are looking at... - return {}; - } + return instr->operands[ 1 ].imm.value.s > 0 ? vmp2::exec_type_t::backward + : vmp2::exec_type_t::forward; + break; case ZYDIS_MNEMONIC_INC: return vmp2::exec_type_t::forward; case ZYDIS_MNEMONIC_DEC: diff --git a/src/vmhandler.cpp b/src/vmhandler.cpp index f84f109..0fec67c 100644 --- a/src/vmhandler.cpp +++ b/src/vmhandler.cpp @@ -19,14 +19,14 @@ namespace vm return false; }; + // find LEA RAX, [RDI+0xE0], else determine if the instruction is inside of calc_jmp... auto result = std::find_if( vm_handler.begin(), vm_handler.end(), []( const zydis_instr_t &instr ) -> bool { - if ( instr.instr.mnemonic == ZYDIS_MNEMONIC_LEA && + return 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 ); + instr.instr.operands[ 1 ].mem.disp.value == 0xE0 + ? true + : calc_jmp_check( instr.addr ); } ); // remove calc_jmp from the vm handler vector... @@ -42,16 +42,14 @@ namespace vm { 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; + 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 ( result != vm_handler.end() ) @@ -77,17 +75,15 @@ namespace vm for ( auto idx = 0u; idx < 256; ++idx ) { - const auto decrypt_val = vm::handler::table::decrypt( instr, vm_handler_table[ idx ] ); - handler_t vm_handler; vm::transform::map_t transforms; zydis_routine_t vm_handler_instrs; + const auto decrypt_val = vm::handler::table::decrypt( instr, vm_handler_table[ idx ] ); if ( !vm::handler::get( calc_jmp, vm_handler_instrs, ( decrypt_val - image_base ) + module_base ) ) return false; const auto has_imm = vm::handler::has_imm( vm_handler_instrs ); - const auto imm_size = vm::handler::imm_size( vm_handler_instrs ); if ( has_imm && !vm::handler::get_operand_transforms( vm_handler_instrs, transforms ) ) @@ -109,16 +105,14 @@ namespace vm 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 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 result != vm_handler.end(); @@ -129,16 +123,14 @@ namespace vm 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 && + 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 ) - return true; - return false; + instr_data.instr.operands[ 1 ].mem.base == ZYDIS_REGISTER_RSI; } ); if ( result == vm_handler.end() ) diff --git a/src/vmutils.cpp b/src/vmutils.cpp index cb8d53f..147b5f4 100644 --- a/src/vmutils.cpp +++ b/src/vmutils.cpp @@ -24,7 +24,6 @@ namespace vm ZydisFormatter formatter; ZydisFormatterInit( &formatter, ZYDIS_FORMATTER_STYLE_INTEL ); ZydisFormatterFormatInstruction( &formatter, &instr, buffer, sizeof( buffer ), 0u ); - puts( buffer ); } @@ -38,7 +37,6 @@ namespace vm { std::printf( "> 0x%p ", addr ); ZydisFormatterFormatInstruction( &formatter, &instr, buffer, sizeof( buffer ), addr ); - puts( buffer ); } } From 948499baafa72ec18f2e7504993957a1604fd050 Mon Sep 17 00:00:00 2001 From: _xeroxz Date: Tue, 1 Jun 2021 20:56:36 -0700 Subject: [PATCH 4/8] fixed vm handler table transformation issue --- src/vmhandler.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vmhandler.cpp b/src/vmhandler.cpp index 0fec67c..0d67547 100644 --- a/src/vmhandler.cpp +++ b/src/vmhandler.cpp @@ -286,7 +286,8 @@ namespace vm // 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 { - return instr_data.instr.operands[ 0 ].reg.value == + return vm::transform::valid( instr_data.instr.mnemonic ) && + instr_data.instr.operands[ 0 ].reg.value == handler_fetch->instr.operands[ 0 ].reg.value && instr_data.instr.operands[ 0 ].actions & ZYDIS_OPERAND_ACTION_WRITE; } ); From 1f748ab668ed8706444272229116b9edab6d2f72 Mon Sep 17 00:00:00 2001 From: _xeroxz Date: Tue, 1 Jun 2021 22:12:08 -0700 Subject: [PATCH 5/8] added NANDW virtual instruction --- include/vmprofiler.hpp | 16 ++++++------ src/vmprofiles/nand.cpp | 56 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 63 insertions(+), 9 deletions(-) diff --git a/include/vmprofiler.hpp b/include/vmprofiler.hpp index 2e9838d..ff058b5 100644 --- a/include/vmprofiler.hpp +++ b/include/vmprofiler.hpp @@ -75,7 +75,8 @@ namespace vm SHRW, NANDQ, - NANDDW + NANDDW, + NANDW }; enum extention_t @@ -153,6 +154,7 @@ namespace vm extern vm::handler::profile_t nandq; extern vm::handler::profile_t nanddw; + extern vm::handler::profile_t nandw; extern vm::handler::profile_t writeq; extern vm::handler::profile_t writedw; @@ -172,14 +174,14 @@ namespace vm extern vm::handler::profile_t vmexit; inline std::vector< vm::handler::profile_t * > all = { - &sregq, &sregdw, &sregw, &lregq, &lregdw, &lconstq, &lconstbzxw, - &lconstbsxdw, &lconstbsxq, &lconstdwsxq, &lconstwsxq, &lconstwsxdw, &lconstdw, &lconstw, - &addq, &adddw, &addw, + &sregq, &sregdw, &sregw, &lregq, &lregdw, &lconstq, &lconstbzxw, &lconstbsxdw, + &lconstbsxq, &lconstdwsxq, &lconstwsxq, &lconstwsxdw, &lconstdw, &lconstw, &addq, &adddw, + &addw, - &shlq, &shldw, &writeq, &writedw, &writeb, &nandq, &nanddw, + &shlq, &shldw, &writeq, &writedw, &writeb, &nandq, &nanddw, &nandw, - &shrq, &shrw, &readq, &readdw, &mulq, &pushvsp, &divq, - &jmp, &vmexit, &call }; + &shrq, &shrw, &readq, &readdw, &mulq, &pushvsp, &divq, &jmp, + &vmexit, &call }; } // namespace profile } // namespace handler } // namespace vm \ No newline at end of file diff --git a/src/vmprofiles/nand.cpp b/src/vmprofiles/nand.cpp index fcbf681..0fbcec0 100644 --- a/src/vmprofiles/nand.cpp +++ b/src/vmprofiles/nand.cpp @@ -75,14 +75,66 @@ namespace vm } } } }; vm::handler::profile_t nanddw = { + // NOT QWORD PTR [RBP] + // MOV EAX, [RBP] + // SUB RBP, 0x4 + // AND [RBP+0x8], EAX + // PUSHFQ + // POP [RBP] + "NANDDW", + NANDDW, + NULL, + { { // NOT QWORD PTR [RBP] + []( const zydis_decoded_instr_t &instr ) -> bool { + return instr.mnemonic == ZYDIS_MNEMONIC_NOT && + instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY && + instr.operands[ 0 ].size == 64 && instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RBP; + }, + // MOV EAX, [RBP] + []( const zydis_decoded_instr_t &instr ) -> bool { + return instr.mnemonic == ZYDIS_MNEMONIC_MOV && + instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER && + instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_EAX && + instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_MEMORY && + instr.operands[ 1 ].mem.base == ZYDIS_REGISTER_RBP; + }, + // SUB RBP, 0x4 + []( const zydis_decoded_instr_t &instr ) -> bool { + return instr.mnemonic == ZYDIS_MNEMONIC_SUB && + instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER && + instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RBP && + instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_IMMEDIATE && + instr.operands[ 1 ].imm.value.u == 0x4; + }, + // AND [RBP+0x8], EAX + []( const zydis_decoded_instr_t &instr ) -> bool { + return instr.mnemonic == ZYDIS_MNEMONIC_AND && + instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY && + instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RBP && + instr.operands[ 0 ].mem.disp.value == 0x8 && + instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_REGISTER && + instr.operands[ 1 ].reg.value == ZYDIS_REGISTER_EAX; + }, + // PUSHFQ + []( const zydis_decoded_instr_t &instr ) -> bool { + return instr.mnemonic == ZYDIS_MNEMONIC_PUSHFQ; + }, + // POP [RBP] + []( const zydis_decoded_instr_t &instr ) -> bool { + return instr.mnemonic == ZYDIS_MNEMONIC_POP && + instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY && + instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RBP; + } } } }; + + vm::handler::profile_t nandw = { // NOT DWORD PTR [RBP] // MOV AX, [RBP] // SUB RBP, 0x6 // AND [RBP+0x8], AX // PUSHFQ // POP [RBP] - "NANDDW", - NANDDW, + "NANDW", + NANDW, NULL, { { // NOT DWORD PTR [RBP] []( const zydis_decoded_instr_t &instr ) -> bool { From c932e71cdd4e4e26d6a4ac7e2f8019a98d54871d Mon Sep 17 00:00:00 2001 From: _xeroxz Date: Tue, 1 Jun 2021 22:26:58 -0700 Subject: [PATCH 6/8] added LRFLAGS virtual instruction --- include/vmprofiler.hpp | 4 +++- src/vmprofiles/lflags.cpp | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 src/vmprofiles/lflags.cpp diff --git a/include/vmprofiler.hpp b/include/vmprofiler.hpp index ff058b5..73a4a90 100644 --- a/include/vmprofiler.hpp +++ b/include/vmprofiler.hpp @@ -31,6 +31,7 @@ namespace vm enum mnemonic_t { INVALID, + LRFLAGS, PUSHVSP, MULQ, DIVQ, @@ -166,6 +167,7 @@ namespace vm extern vm::handler::profile_t shrq; extern vm::handler::profile_t shrw; + extern vm::handler::profile_t lrflags; extern vm::handler::profile_t call; extern vm::handler::profile_t pushvsp; extern vm::handler::profile_t mulq; @@ -181,7 +183,7 @@ namespace vm &shlq, &shldw, &writeq, &writedw, &writeb, &nandq, &nanddw, &nandw, &shrq, &shrw, &readq, &readdw, &mulq, &pushvsp, &divq, &jmp, - &vmexit, &call }; + &lrflags, &vmexit, &call }; } // namespace profile } // namespace handler } // namespace vm \ No newline at end of file diff --git a/src/vmprofiles/lflags.cpp b/src/vmprofiles/lflags.cpp new file mode 100644 index 0000000..ded18a8 --- /dev/null +++ b/src/vmprofiles/lflags.cpp @@ -0,0 +1,34 @@ +#include "../../include/vmprofiler.hpp" + +namespace vm +{ + namespace handler + { + namespace profile + { + vm::handler::profile_t lrflags = { + // PUSH [RBP] + // ADD RBP, 0x8 + // POPFQ + "LRFLAGS", + LRFLAGS, + NULL, + { { // PUSH [RBP] + []( const zydis_decoded_instr_t &instr ) -> bool { + return instr.mnemonic == ZYDIS_MNEMONIC_PUSH && + instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY && + instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RBP; + }, + // ADD RBP, 0x8 + []( const zydis_decoded_instr_t &instr ) -> bool { + return instr.mnemonic == ZYDIS_MNEMONIC_ADD && + instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER && + instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RBP; + }, + // POPFQ + []( const zydis_decoded_instr_t &instr ) -> bool { + return instr.mnemonic == ZYDIS_MNEMONIC_POPFQ; + } } } }; + } + } // namespace handler +} // namespace vm \ No newline at end of file From 231388d6fc1f49b3b8181cdcd347755ea087fd39 Mon Sep 17 00:00:00 2001 From: _xeroxz Date: Tue, 1 Jun 2021 22:27:58 -0700 Subject: [PATCH 7/8] fixed an issue in LRFLAGS profile --- src/vmprofiles/lflags.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vmprofiles/lflags.cpp b/src/vmprofiles/lflags.cpp index ded18a8..5b84ef6 100644 --- a/src/vmprofiles/lflags.cpp +++ b/src/vmprofiles/lflags.cpp @@ -23,7 +23,9 @@ namespace vm []( const zydis_decoded_instr_t &instr ) -> bool { return instr.mnemonic == ZYDIS_MNEMONIC_ADD && instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER && - instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RBP; + instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RBP && + instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_IMMEDIATE && + instr.operands[ 1 ].imm.value.u == 0x8; }, // POPFQ []( const zydis_decoded_instr_t &instr ) -> bool { From d4b01cdf1ae7eb3f7c8b10440d56b24322ecd67b Mon Sep 17 00:00:00 2001 From: _xeroxz Date: Tue, 1 Jun 2021 22:29:09 -0700 Subject: [PATCH 8/8] updated readme to master --- README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f2e8c0e..0f8bed8 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,9 @@ -# vmprofiler +
+
+ +
+
-Library To Profile VMProtect 2 Virtual Machines \ No newline at end of file +# vmprofiler - Library To Profile VMProtect 2 Virtual Machines + +vmprofiler is a c++ library which is used to statically analyze VMProtect 2 polymorphic virtual machines. This project is inherited in vmprofiler-qt, vmprofiler-cli, and vmemu. This is the base project for all other VMProtect 2 projects inside of this group on githacks. \ No newline at end of file