From 3b0942a276d25bd5cea7ab889ee3e137a0442bfa Mon Sep 17 00:00:00 2001 From: _xeroxz <_xeroxz@back.engineer> Date: Tue, 30 Nov 2021 14:22:16 -0800 Subject: [PATCH 1/2] ported the project to linux --- include/transform.hpp | 6 +- include/vmlocate.hpp | 1 - include/vmutils.hpp | 47 +++++++- src/vmhandler.cpp | 10 +- src/vmlocate.cpp | 253 +----------------------------------------- 5 files changed, 54 insertions(+), 263 deletions(-) diff --git a/include/transform.hpp b/include/transform.hpp index 5ada35a..c282cd4 100644 --- a/include/transform.hpp +++ b/include/transform.hpp @@ -152,11 +152,11 @@ namespace vm::transform template < class T > inline const auto _bswap = []( T a, T b ) -> T { if constexpr ( std::is_same_v< T, std::uint64_t > ) - return _byteswap_uint64( a ); + return bswap_64( a ); if constexpr ( std::is_same_v< T, std::uint32_t > ) - return _byteswap_ulong( a ); + return bswap_32( a ); if constexpr ( std::is_same_v< T, std::uint16_t > ) - return _byteswap_ushort( a ); + return bswap_16( a ); throw std::invalid_argument( "invalid type size..." ); }; diff --git a/include/vmlocate.hpp b/include/vmlocate.hpp index da957e5..d96e484 100644 --- a/include/vmlocate.hpp +++ b/include/vmlocate.hpp @@ -2,7 +2,6 @@ #include #include #include -#include #define ABS_TO_IMG( addr, mod_base, img_base ) ( addr - mod_base ) + img_base #define LEA_R12_SIG "\x4C\x8D\x25\x00\x00\x00\x00" diff --git a/include/vmutils.hpp b/include/vmutils.hpp index d762322..876c072 100644 --- a/include/vmutils.hpp +++ b/include/vmutils.hpp @@ -6,7 +6,52 @@ #include #include -#include +#ifdef _MSC_VER + +#include +#define bswap_32(x) _byteswap_ulong(x) +#define bswap_64(x) _byteswap_uint64(x) +#define bswap_16(x) _byteswap_ushort(x) + +#elif defined(__APPLE__) + +// Mac OS X / Darwin features +#include +#define bswap_32(x) OSSwapInt32(x) +#define bswap_64(x) OSSwapInt64(x) + +#elif defined(__sun) || defined(sun) + +#include +#define bswap_32(x) BSWAP_32(x) +#define bswap_64(x) BSWAP_64(x) + +#elif defined(__FreeBSD__) + +#include +#define bswap_32(x) bswap32(x) +#define bswap_64(x) bswap64(x) + +#elif defined(__OpenBSD__) + +#include +#define bswap_32(x) swap32(x) +#define bswap_64(x) swap64(x) + +#elif defined(__NetBSD__) + +#include +#include +#if defined(__BSWAP_RENAME) && !defined(__bswap_32) +#define bswap_32(x) bswap32(x) +#define bswap_64(x) bswap64(x) +#endif + +#else + +#include + +#endif using u8 = unsigned char; using u16 = unsigned short; diff --git a/src/vmhandler.cpp b/src/vmhandler.cpp index 6d6cd0c..d0e6b98 100644 --- a/src/vmhandler.cpp +++ b/src/vmhandler.cpp @@ -204,7 +204,7 @@ namespace vm::handler if ( result == vm_entry.end() ) return nullptr; - auto ptr = 0ull; + ZyanU64 ptr = 0ull; ZydisCalcAbsoluteAddress( &result->instr, &result->instr.operands[ 1 ], result->addr, &ptr ); return reinterpret_cast< std::uintptr_t * >( ptr ); @@ -251,9 +251,7 @@ namespace vm::handler std::uint64_t encrypt( zydis_decoded_instr_t &transform_instr, std::uint64_t val ) { - assert( transform_instr.operands[ 0 ].size == 64, - "invalid transformation for vm handler table entries..." ); - + assert( transform_instr.operands[ 0 ].size == 64 ); const auto operation = vm::transform::inverse[ transform_instr.mnemonic ]; const auto bitsize = transform_instr.operands[ 0 ].size; const auto imm = @@ -264,9 +262,7 @@ namespace vm::handler std::uint64_t decrypt( zydis_decoded_instr_t &transform_instr, std::uint64_t val ) { - assert( transform_instr.operands[ 0 ].size == 64, - "invalid transformation for vm handler table entries..." ); - + assert( transform_instr.operands[ 0 ].size == 64 ); const auto operation = transform_instr.mnemonic; const auto bitsize = transform_instr.operands[ 0 ].size; const auto imm = diff --git a/src/vmlocate.cpp b/src/vmlocate.cpp index 7a64720..0c6d4bf 100644 --- a/src/vmlocate.cpp +++ b/src/vmlocate.cpp @@ -4,261 +4,12 @@ namespace vm::locate { std::vector< vm_handler_table_info_t > all_handler_tables( std::uintptr_t module_base ) { - std::vector< vm_handler_table_info_t > result; - auto module_info = reinterpret_cast< win::image_t<> * >( module_base ); - auto sections = module_info->get_nt_headers()->get_sections(); - auto num_sections = module_info->get_file_header()->num_sections; - auto umtils = xtils::um_t::get_instance(); - - static const auto lea_r12_validate = []( std::uintptr_t addr ) -> bool { - ZydisDecodedInstruction instr; - ZydisDecoder decoder; - ZydisRegister jmp_reg = ZYDIS_REGISTER_NONE; - ZydisDecoderInit( &decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_ADDRESS_WIDTH_64 ); - - unsigned instr_count = 0u; - bool found_table_idx = false, found_valid_jmp = false; - - while ( ZYAN_SUCCESS( - ZydisDecoderDecodeBuffer( &decoder, reinterpret_cast< void * >( addr ), 0x1000, &instr ) ) ) - { - ++instr_count; - if ( instr_count >= 0x1000 || - instr.mnemonic == ZYDIS_MNEMONIC_INVALID ) // prevent run offs and misalignment... - break; - - // determine if we are looking at a JMP RCX/JMP RDX... - if ( vm::util::is_jmp( instr ) ) - { - if ( instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER && - ( instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RDX || - instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RCX ) ) - { - if ( jmp_reg == ZYDIS_REGISTER_NONE || jmp_reg != instr.operands[ 0 ].reg.value ) - break; - - // else we set it to true and break... - found_valid_jmp = true; - break; - } - - // take JCC branch no matter what... - ZydisCalcAbsoluteAddress( &instr, &instr.operands[ 0 ], addr, &addr ); - - // dont execute anymore address advancement code... - continue; - } - // else if the instruction is a MOV RDX/RCX, [R12+RAX*0x8]... we know this is an index into - // the vm handler table and thus this lea r12, xxxx is probably legit... - else if ( instr.mnemonic == ZYDIS_MNEMONIC_MOV && - instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER && - ( instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RDX || - instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RCX ) && - 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 == 0x8 ) - { - found_table_idx = true; - jmp_reg = instr.operands[ 0 ].reg.value; - } - else if ( instr.mnemonic == ZYDIS_MNEMONIC_RET || instr.mnemonic == ZYDIS_MNEMONIC_CALL ) - break; - - // advance the instruction address "addr"... - addr += instr.length; - } - - return found_table_idx && found_valid_jmp; - }; - - ZydisDecodedInstruction instr; - ZydisDecoder decoder; - ZydisDecoderInit( &decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_ADDRESS_WIDTH_64 ); - - for ( auto idx = 0u; idx < num_sections; ++idx ) - { - // if the section is executable and not discardable... scan it for lea r12, xxxx and ensure its loading - // a virtual machine handler table into r12... - if ( sections[ idx ].characteristics.mem_execute && !sections[ idx ].characteristics.mem_discardable ) - { - void *scan_result = reinterpret_cast< void * >( sections[ idx ].virtual_address + module_base ); - - do - { - // compute how far away from the beginning of the section we are... - auto section_size = reinterpret_cast< std::uintptr_t >( scan_result ) - - ( sections[ idx ].virtual_address + module_base ); - - // scan from the last scans result to the end of the section for lea r12's... - scan_result = umtils->sigscan( scan_result, sections[ idx ].virtual_size - section_size, - LEA_R12_SIG, LEA_R12_MASK ); - - if ( scan_result ) - { - // check to see if we are looking at: - // 1.) a legit "lea r12, xxxx" and not a misaligned instruction... - // 2.) if the instruction stream is followed in zydis it ends with a jmp rcx/jmp rdx... - if ( lea_r12_validate( reinterpret_cast< std::uintptr_t >( scan_result ) ) ) - { - if ( ZYAN_SUCCESS( ZydisDecoderDecodeBuffer( - &decoder, scan_result, sections[ idx ].virtual_size - section_size, &instr ) ) ) - { - vm_handler_table_info_t vm_handler_table_info; - vm_handler_table_info.rva = - ( instr.operands[ 1 ].mem.disp.value + - reinterpret_cast< std::uintptr_t >( scan_result ) + instr.length ) - - module_base; - - vm_handler_table_info.lea_r12_rva = - reinterpret_cast< std::uintptr_t >( scan_result ) - module_base; - - vm_handler_table_info.lea_r12_instr = instr; - result.push_back( vm_handler_table_info ); - } - } - - scan_result = reinterpret_cast< void * >( reinterpret_cast< std::uintptr_t >( scan_result ) + - sizeof LEA_R12_SIG ); - } - - } while ( scan_result ); - } - } - return result; + return {}; } std::vector< std::pair< std::uint32_t, std::uint32_t > > all_vm_enters( std::uintptr_t module_base, std::vector< vm_handler_table_info_t > &vm_handler_tables ) { - std::vector< std::pair< std::uint32_t, std::uint32_t > > result; - auto module_info = reinterpret_cast< win::image_t<> * >( module_base ); - auto sections = module_info->get_nt_headers()->get_sections(); - auto num_sections = module_info->get_file_header()->num_sections; - auto umtils = xtils::um_t::get_instance(); - auto module_end = module_base + module_info->get_nt_headers()->optional_header.size_image; - - static const auto validate_vm_enter = [ & ]( std::uintptr_t addr ) -> bool { - ZydisDecodedInstruction instr; - ZydisDecoder decoder; - ZydisDecoderInit( &decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_ADDRESS_WIDTH_64 ); - - unsigned instr_count = 0u; - bool found_valid_jmp = false; - std::vector< ZydisDecodedInstruction > instr_stream; - - while ( addr >= module_base && addr < module_end && - ZYAN_SUCCESS( - ZydisDecoderDecodeBuffer( &decoder, reinterpret_cast< void * >( addr ), 0x1000, &instr ) ) ) - { - if ( !instr_count && instr.mnemonic != ZYDIS_MNEMONIC_PUSH ) - break; - - ++instr_count; // handle run offs and misaligned instructions... - if ( instr_count > 500 || instr.mnemonic == ZYDIS_MNEMONIC_INVALID || - instr.mnemonic == ZYDIS_MNEMONIC_RET || instr.mnemonic == ZYDIS_MNEMONIC_CALL ) - return false; - - // determine if we are looking at a JMP RCX/JMP RDX... - if ( vm::util::is_jmp( instr ) ) - { - if ( instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER && - ( instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RDX || - instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RCX ) ) - { - - // else we set it to true and break... - found_valid_jmp = true; - instr_stream.push_back( instr ); - break; - } - - // take JCC branch no matter what... - ZydisCalcAbsoluteAddress( &instr, &instr.operands[ 0 ], addr, &addr ); - - // dont execute anymore address advancement code... - continue; - } - - instr_stream.push_back( instr ); - addr += instr.length; - } - - if ( !found_valid_jmp ) - return false; - - // second instruction in the flattened stream should be a push... - // this is also an optimization so we dont have to hit that 0^2 std::find_if every time... - if ( instr_stream[ 1 ].mnemonic != ZYDIS_MNEMONIC_PUSH ) - return false; - - if ( std::find_if( instr_stream.begin() + 1, instr_stream.end(), - [ & ]( const ZydisDecodedInstruction &instr ) { - return instr.mnemonic == ZYDIS_MNEMONIC_PUSH && - instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_IMMEDIATE; - } ) == instr_stream.end() ) - return false; - - // scan over the instruction stream to see if it contains an lea r12, xxxx which is a known vm handler table - // load into r12... this is O^2 and very slow... whatever... - return std::find_if( - instr_stream.begin(), instr_stream.end(), [ & ]( const ZydisDecodedInstruction &instr ) { - return instr.mnemonic == ZYDIS_MNEMONIC_LEA && - instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_MEMORY && - std::find_if( vm_handler_tables.begin(), vm_handler_tables.end(), - [ & ]( const vm_handler_table_info_t &table_info ) { - return table_info.lea_r12_instr.operands[ 1 ].mem.disp.value == - instr.operands[ 1 ].mem.disp.value; - } ) != vm_handler_tables.end(); - } ) != instr_stream.end(); - }; - - ZydisDecodedInstruction instr; - ZydisDecoder decoder; - ZydisDecoderInit( &decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_ADDRESS_WIDTH_64 ); - - // for each section... - for ( auto idx = 0u; idx < num_sections; ++idx ) - { - // we are only interested in executable (non-discardable) sections... - if ( sections[ idx ].characteristics.mem_execute && !sections[ idx ].characteristics.mem_discardable ) - { - void *scan_result = reinterpret_cast< void * >( sections[ idx ].virtual_address + module_base ); - - do - { - // compute how far away from the beginning of the section we are... - auto section_size = reinterpret_cast< std::uintptr_t >( scan_result ) - - ( sections[ idx ].virtual_address + module_base ); - - if ( section_size > sections[ idx ].virtual_size ) - break; - - scan_result = umtils->sigscan( scan_result, sections[ idx ].virtual_size - section_size, - PUSH_4B_IMM, PUSH_4B_MASK ); - - if ( scan_result ) - { - if ( validate_vm_enter( reinterpret_cast< std::uintptr_t >( scan_result ) ) && - ZYAN_SUCCESS( ZydisDecoderDecodeBuffer( &decoder, scan_result, 0x1000, &instr ) ) ) - { - if ( std::find_if( result.begin(), result.end(), - [ & ]( const std::pair< std::uint32_t, std::uint32_t > &info ) { - return info.second == instr.operands[ 0 ].imm.value.u; - } ) == result.end() ) - { - result.push_back( { reinterpret_cast< std::uintptr_t >( scan_result ) - module_base, - instr.operands[ 0 ].imm.value.u } ); - } - } - - scan_result = reinterpret_cast< void * >( reinterpret_cast< std::uintptr_t >( scan_result ) + - sizeof PUSH_4B_IMM ); - } - - } while ( scan_result ); - } - } - - return result; + return {}; } } // namespace vm::locate \ No newline at end of file From c746d04f1b0c0f8880b8fb792c7663dfafb3c980 Mon Sep 17 00:00:00 2001 From: _xeroxz <_xeroxz@back.engineer> Date: Tue, 30 Nov 2021 14:34:25 -0800 Subject: [PATCH 2/2] removed xtils because its not linux friendly... --- .gitmodules | 5 +---- cmake.toml | 4 +++- dependencies/cmake.toml | 7 +------ dependencies/xtils | 1 - 4 files changed, 5 insertions(+), 12 deletions(-) delete mode 160000 dependencies/xtils diff --git a/.gitmodules b/.gitmodules index cd02e7d..eff0e94 100644 --- a/.gitmodules +++ b/.gitmodules @@ -3,7 +3,4 @@ url = https://github.com/zyantific/zydis.git [submodule "dependencies/linux-pe"] path = dependencies/linux-pe - url = https://github.com/can1357/linux-pe.git -[submodule "dependencies/xtils"] - path = dependencies/xtils - url = https://githacks.org/_xeroxz/xtils.git + url = https://github.com/can1357/linux-pe.git \ No newline at end of file diff --git a/cmake.toml b/cmake.toml index a564db4..92f82d8 100644 --- a/cmake.toml +++ b/cmake.toml @@ -11,14 +11,16 @@ sources = [ "src/**.cpp", "include/**.hpp", ] + include-directories = [ "include", ] + link-libraries = [ "Zydis", - "xtils", "linux-pe", ] + compile-definitions = [ "NOMINMAX" ] \ No newline at end of file diff --git a/dependencies/cmake.toml b/dependencies/cmake.toml index f0c67bc..4fb83a8 100644 --- a/dependencies/cmake.toml +++ b/dependencies/cmake.toml @@ -9,9 +9,4 @@ ZYDIS_LIBFUZZER = false [target.linux-pe] type = "interface" -include-directories = ["linux-pe/includes/"] - -[target.xtils] -type = "interface" -include-directories = ["xtils"] -compile-definitions = ["UNICODE"] \ No newline at end of file +include-directories = ["linux-pe/includes/"] \ No newline at end of file diff --git a/dependencies/xtils b/dependencies/xtils deleted file mode 160000 index fdcafdb..0000000 --- a/dependencies/xtils +++ /dev/null @@ -1 +0,0 @@ -Subproject commit fdcafdbbcb3f34c33b9cffb2be569b9aa5f42a57