From 3e8df3258ced14c26b8109d77d359482d98bf785 Mon Sep 17 00:00:00 2001 From: _xeroxz Date: Sun, 25 Jul 2021 18:27:51 -0700 Subject: [PATCH] added linux-pe dep, added vm::locate code... --- .gitmodules | 3 + CMakeLists.txt | 7 + cmake.toml | 8 +- dependencies/CMakeLists.txt | 18 +++ dependencies/cmake.toml | 4 + dependencies/linux-pe | 1 + dependencies/vmprofiler | 2 +- include/vmlocate.hpp | 25 ++++ src/icon.aps | Bin 0 -> 233768 bytes src/main.cpp | 50 ++++++- src/vmlocate.cpp | 264 ++++++++++++++++++++++++++++++++++++ 11 files changed, 374 insertions(+), 8 deletions(-) create mode 160000 dependencies/linux-pe create mode 100644 include/vmlocate.hpp create mode 100644 src/icon.aps create mode 100644 src/vmlocate.cpp diff --git a/.gitmodules b/.gitmodules index ef4e931..676e438 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "dependencies/xtils"] path = dependencies/xtils url = https://githacks.org/_xeroxz/xtils.git +[submodule "dependencies/linux-pe"] + path = dependencies/linux-pe + url = https://github.com/can1357/linux-pe.git diff --git a/CMakeLists.txt b/CMakeLists.txt index a46e41e..3620be9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,6 +41,8 @@ set(vmprofiler-cli_SOURCES "") list(APPEND vmprofiler-cli_SOURCES "src/main.cpp" + "src/vmlocate.cpp" + "include/vmlocate.hpp" "src/icon.rc" ) @@ -62,10 +64,15 @@ endif() source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${vmprofiler-cli_SOURCES}) +target_include_directories(vmprofiler-cli PRIVATE + include +) + target_link_libraries(vmprofiler-cli PRIVATE cli-parser xtils vmprofiler + linux-pe ) unset(CMKR_TARGET) diff --git a/cmake.toml b/cmake.toml index 4c57847..591d6b5 100644 --- a/cmake.toml +++ b/cmake.toml @@ -7,10 +7,16 @@ name = "vmprofiler-cli" type = "executable" sources = [ "src/main.cpp", - "src/icon.rc", + "src/vmlocate.cpp", + "include/vmlocate.hpp", + "src/icon.rc" +] +include-directories = [ + "include", ] link-libraries = [ "cli-parser", "xtils", "vmprofiler", + "linux-pe" ] \ No newline at end of file diff --git a/dependencies/CMakeLists.txt b/dependencies/CMakeLists.txt index 2f81bf4..3fb13b1 100644 --- a/dependencies/CMakeLists.txt +++ b/dependencies/CMakeLists.txt @@ -34,6 +34,24 @@ target_include_directories(cli-parser INTERFACE unset(CMKR_TARGET) unset(CMKR_SOURCES) +# Target linux-pe +set(CMKR_TARGET linux-pe) +set(linux-pe_SOURCES "") + +set(CMKR_SOURCES ${linux-pe_SOURCES}) +add_library(linux-pe INTERFACE) + +if(linux-pe_SOURCES) + target_sources(linux-pe INTERFACE ${linux-pe_SOURCES}) +endif() + +target_include_directories(linux-pe INTERFACE + "linux-pe/includes/" +) + +unset(CMKR_TARGET) +unset(CMKR_SOURCES) + # Target xtils set(CMKR_TARGET xtils) set(xtils_SOURCES "") diff --git a/dependencies/cmake.toml b/dependencies/cmake.toml index 875ccdb..e19d630 100644 --- a/dependencies/cmake.toml +++ b/dependencies/cmake.toml @@ -4,6 +4,10 @@ type = "interface" include-directories = ["cli-parser"] +[target.linux-pe] +type = "interface" +include-directories = ["linux-pe/includes/"] + [target.xtils] type = "interface" include-directories = ["xtils"] diff --git a/dependencies/linux-pe b/dependencies/linux-pe new file mode 160000 index 0000000..db2b7af --- /dev/null +++ b/dependencies/linux-pe @@ -0,0 +1 @@ +Subproject commit db2b7af6e6beae1bc391ff8f8e5c97b963dc3258 diff --git a/dependencies/vmprofiler b/dependencies/vmprofiler index e8eb794..7240a2a 160000 --- a/dependencies/vmprofiler +++ b/dependencies/vmprofiler @@ -1 +1 @@ -Subproject commit e8eb794dc1c853807b406815e308f3d201fa2a93 +Subproject commit 7240a2a23c7d789d5973de04458c7ebca16a81d0 diff --git a/include/vmlocate.hpp b/include/vmlocate.hpp new file mode 100644 index 0000000..da957e5 --- /dev/null +++ b/include/vmlocate.hpp @@ -0,0 +1,25 @@ +#pragma once +#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" +#define LEA_R12_MASK "xxx????" + +#define PUSH_4B_IMM "\x68\x00\x00\x00\x00" +#define PUSH_4B_MASK "x????" + +namespace vm::locate +{ + struct vm_handler_table_info_t + { + std::uint32_t rva, lea_r12_rva; + zydis_decoded_instr_t lea_r12_instr; + }; + + std::vector< vm_handler_table_info_t > all_handler_tables( std::uintptr_t module_base ); + 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 ); +} // namespace vm::locate \ No newline at end of file diff --git a/src/icon.aps b/src/icon.aps new file mode 100644 index 0000000000000000000000000000000000000000..f4667c48e1092929312a2b0e3c36e769be872bae GIT binary patch literal 233768 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 Q@W*f1Or;Hvj+t literal 0 HcmV?d00001 diff --git a/src/main.cpp b/src/main.cpp index cbeced4..57097bd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,16 +1,12 @@ #include +#include #include #include #include #include -#include #include -#include -#include -#include - -#define ABS_TO_IMG( addr, mod_base, img_base ) ( addr - mod_base ) + img_base +#include int __cdecl main( int argc, const char *argv[] ) { @@ -21,6 +17,12 @@ int __cdecl main( int argc, const char *argv[] ) parser.add_argument().name( "--showhandlers" ).description( "show all vm handlers..." ); parser.add_argument().name( "--showhandler" ).description( "show a specific vm handler given its index..." ); parser.add_argument().name( "--vmp2file" ).description( "path to .vmp2 file..." ); + parser.add_argument() + .name( "--indexes" ) + .description( "displays vm handler table indexes for a given vm handler name such as 'READQ', or 'WRITEQ'..." ); + parser.add_argument() + .name( "--scanfortables" ) + .description( "scans all executable sections for vm handler tables..." ); parser.add_argument() .name( "--showblockinstrs" ) .description( "show the virtual instructions of a specific code block..." ); @@ -45,6 +47,32 @@ int __cdecl main( int argc, const char *argv[] ) return 0; } + if ( parser.exists( "bin" ) && parser.exists( "scanfortables" ) ) + { + if ( !std::filesystem::exists( parser.get< std::string >( "bin" ) ) ) + { + std::printf( "> path to protected file is invalid... check your cli args...\n" ); + return -1; + } + + const auto module_base = reinterpret_cast< std::uintptr_t >( + LoadLibraryExA( parser.get< std::string >( "bin" ).c_str(), NULL, DONT_RESOLVE_DLL_REFERENCES ) ); + + auto result = vm::locate::all_handler_tables( module_base ); + std::vector< std::uint32_t > handler_table_rvas; + + std::for_each( result.begin(), result.end(), [ & ]( const vm::locate::vm_handler_table_info_t &data ) { + if ( std::find( handler_table_rvas.begin(), handler_table_rvas.end(), data.rva ) == + handler_table_rvas.end() ) + handler_table_rvas.push_back( data.rva ); + } ); + + std::printf( "{\n" ); + for ( auto &table_rva : handler_table_rvas ) + std::printf( "\t0x%x,\n", table_rva ); + std::printf( "}\n" ); + } + if ( parser.exists( "bin" ) && parser.exists( "vmentry" ) ) { if ( !std::filesystem::exists( parser.get< std::string >( "bin" ) ) ) @@ -140,6 +168,16 @@ int __cdecl main( int argc, const char *argv[] ) } std::puts( "\n" ); } + else if ( parser.exists( "indexes" ) ) + { + const auto handler_name = parser.get< std::string >( "indexes" ); + std::printf( "{\n" ); + for ( auto idx = 0u; idx < vmctx.vm_handlers.size(); ++idx ) + if ( vmctx.vm_handlers[ idx ].profile && + !strcmp( vmctx.vm_handlers[ idx ].profile->name, handler_name.c_str() ) ) + std::printf( "\t0x%x,\n", idx ); + std::printf( "}\n" ); + } } if ( !parser.exists( "vmp2file" ) ) diff --git a/src/vmlocate.cpp b/src/vmlocate.cpp new file mode 100644 index 0000000..7a64720 --- /dev/null +++ b/src/vmlocate.cpp @@ -0,0 +1,264 @@ +#include + +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; + } + + 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; + } +} // namespace vm::locate \ No newline at end of file