diff --git a/.gitmodules b/.gitmodules index 72a6132..cd02e7d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,9 @@ [submodule "dependencies/zydis"] path = dependencies/zydis url = https://github.com/zyantific/zydis.git -[submodule "dependencies/vtil"] - path = dependencies/vtil - url = https://github.com/vtil-project/VTIL-Core +[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 diff --git a/CMakeLists.txt b/CMakeLists.txt index 3883b3f..5ac7ddd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,18 +44,7 @@ list(APPEND vmprofiler_SOURCES "src/vmctx.cpp" "src/vmhandler.cpp" "src/vminstrs.cpp" - "src/vmlifters/add.cpp" - "src/vmlifters/jmp.cpp" - "src/vmlifters/lconst.cpp" - "src/vmlifters/lflags.cpp" - "src/vmlifters/lreg.cpp" - "src/vmlifters/lvsp.cpp" - "src/vmlifters/nand.cpp" - "src/vmlifters/pushvsp.cpp" - "src/vmlifters/read.cpp" - "src/vmlifters/shr.cpp" - "src/vmlifters/sreg.cpp" - "src/vmlifters/vmexit.cpp" + "src/vmlocate.cpp" "src/vmprofiles/add.cpp" "src/vmprofiles/call.cpp" "src/vmprofiles/div.cpp" @@ -81,6 +70,7 @@ list(APPEND vmprofiler_SOURCES "include/vmhandlers.hpp" "include/vminstrs.hpp" "include/vmlifters.hpp" + "include/vmlocate.hpp" "include/vmp2.hpp" "include/vmprofiler.hpp" "include/vmprofiles.hpp" @@ -104,13 +94,18 @@ target_compile_definitions(vmprofiler PUBLIC NOMINMAX ) +target_compile_features(vmprofiler PUBLIC + cxx_std_20 +) + target_include_directories(vmprofiler PUBLIC include ) target_link_libraries(vmprofiler PUBLIC - VTIL Zydis + xtils + linux-pe ) unset(CMKR_TARGET) diff --git a/cmake.toml b/cmake.toml index 358d68b..a564db4 100644 --- a/cmake.toml +++ b/cmake.toml @@ -5,6 +5,8 @@ name = "vmprofiler" [target.vmprofiler] type = "static" +compile-features = ["cxx_std_20"] + sources = [ "src/**.cpp", "include/**.hpp", @@ -13,8 +15,9 @@ include-directories = [ "include", ] link-libraries = [ - "VTIL", "Zydis", + "xtils", + "linux-pe", ] compile-definitions = [ "NOMINMAX" diff --git a/dependencies/CMakeLists.txt b/dependencies/CMakeLists.txt index 3320591..3a82519 100644 --- a/dependencies/CMakeLists.txt +++ b/dependencies/CMakeLists.txt @@ -13,16 +13,6 @@ option(ZYDIS_BUILD_TOOLS OFF) option(ZYDIS_FUZZ_AFL_FAST OFF) option(ZYDIS_LIBFUZZER OFF) -# vtil -set(CMKR_CMAKE_FOLDER ${CMAKE_FOLDER}) -if(CMAKE_FOLDER) - set(CMAKE_FOLDER "${CMAKE_FOLDER}/vtil") -else() - set(CMAKE_FOLDER vtil) -endif() -add_subdirectory(vtil) -set(CMAKE_FOLDER ${CMKR_CMAKE_FOLDER}) - # zydis set(CMKR_CMAKE_FOLDER ${CMAKE_FOLDER}) if(CMAKE_FOLDER) @@ -33,3 +23,43 @@ endif() add_subdirectory(zydis) set(CMAKE_FOLDER ${CMKR_CMAKE_FOLDER}) +# 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 "") + +set(CMKR_SOURCES ${xtils_SOURCES}) +add_library(xtils INTERFACE) + +if(xtils_SOURCES) + target_sources(xtils INTERFACE ${xtils_SOURCES}) +endif() + +target_compile_definitions(xtils INTERFACE + UNICODE +) + +target_include_directories(xtils INTERFACE + xtils +) + +unset(CMKR_TARGET) +unset(CMKR_SOURCES) + diff --git a/dependencies/cmake.toml b/dependencies/cmake.toml index e36ef4f..f0c67bc 100644 --- a/dependencies/cmake.toml +++ b/dependencies/cmake.toml @@ -5,6 +5,13 @@ ZYDIS_BUILD_TOOLS = false ZYDIS_FUZZ_AFL_FAST = false ZYDIS_LIBFUZZER = false -[subdir.vtil] +[subdir.zydis] -[subdir.zydis] \ No newline at end of file +[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 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/vtil b/dependencies/vtil deleted file mode 160000 index ff94eef..0000000 --- a/dependencies/vtil +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ff94eef4483b07fbe970b7b80bbfae3b52524f16 diff --git a/dependencies/xtils b/dependencies/xtils new file mode 160000 index 0000000..fdcafdb --- /dev/null +++ b/dependencies/xtils @@ -0,0 +1 @@ +Subproject commit fdcafdbbcb3f34c33b9cffb2be569b9aa5f42a57 diff --git a/include/vmlifters.hpp b/include/vmlifters.hpp index 955f840..9632608 100644 --- a/include/vmlifters.hpp +++ b/include/vmlifters.hpp @@ -1,3 +1,4 @@ +#pragma once #include #include #include 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/include/vmprofiler.hpp b/include/vmprofiler.hpp index 8b40e7c..b577c40 100644 --- a/include/vmprofiler.hpp +++ b/include/vmprofiler.hpp @@ -7,4 +7,4 @@ #include #include #include -#include \ No newline at end of file +#include \ No newline at end of file diff --git a/src/vmlifters/add.cpp b/src/vmlifters/add.cpp deleted file mode 100644 index 65fe6d7..0000000 --- a/src/vmlifters/add.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include - -namespace vm::lifters -{ - vm::lifters::lifter_t addq = { - // vsp[0] = vsp[1] + vsp[0]; - vm::handler::ADDQ, []( vtil::basic_block *blk, vm::instrs::virt_instr_t *vinstr, vmp2::v3::code_block_t* code_blk ) { - auto [ t0, t1 ] = blk->tmp( 64, 64 ); - blk->pop( t0 ); - blk->pop( t1 ); - blk->add( t1, t0 ); - blk->push( t1 ); - blk->pushf(); - } }; - - vm::lifters::lifter_t adddw = { - // vsp[0] = vsp[1] + vsp[0]; - vm::handler::ADDDW, []( vtil::basic_block *blk, vm::instrs::virt_instr_t *vinstr, vmp2::v3::code_block_t* code_blk ) { - auto [ t0, t1 ] = blk->tmp( 32, 32 ); - blk->pop( t0 ); - blk->pop( t1 ); - blk->add( t1, t0 ); - blk->push( t1 ); - blk->pushf(); - } }; - - vm::lifters::lifter_t addw = { - // vsp[0] = vsp[1] + vsp[0]; - vm::handler::ADDW, []( vtil::basic_block *blk, vm::instrs::virt_instr_t *vinstr, vmp2::v3::code_block_t* code_blk ) { - auto [ t0, t1 ] = blk->tmp( 16, 16 ); - blk->pop( t0 ); - blk->pop( t1 ); - blk->add( t1, t0 ); - blk->push( t1 ); - blk->pushf(); - } }; -} // namespace vm::lifters \ No newline at end of file diff --git a/src/vmlifters/jmp.cpp b/src/vmlifters/jmp.cpp deleted file mode 100644 index 6769e43..0000000 --- a/src/vmlifters/jmp.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include - -namespace vm::lifters -{ - vm::lifters::lifter_t jmp = { - // jmp - vm::handler::JMP, - []( vtil::basic_block *blk, vm::instrs::virt_instr_t *vinstr, vmp2::v3::code_block_t *code_blk ) { - if ( code_blk->jcc.has_jcc ) - { - // TODO: figure out what bit the JCC is determined on... - blk->js( vtil::REG_FLAGS.select( 1, 11 ), code_blk->jcc.block_addr[ 0 ] - vinstr->trace_data.regs.r13, - code_blk->jcc.block_addr[ 1 ] - vinstr->trace_data.regs.r13 ); - } - else - blk->jmp( vinstr->trace_data.vsp.qword[ 0 ] - vinstr->trace_data.regs.r13 ); - } }; -} \ No newline at end of file diff --git a/src/vmlifters/lconst.cpp b/src/vmlifters/lconst.cpp deleted file mode 100644 index 964e3a2..0000000 --- a/src/vmlifters/lconst.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include - -namespace vm::lifters -{ - vm::lifters::lifter_t lconstq = { - // push imm - vm::handler::LCONSTQ, - []( vtil::basic_block *blk, vm::instrs::virt_instr_t *vinstr, vmp2::v3::code_block_t *code_blk ) { - blk->push( vtil::operand( vinstr->operand.imm.u, 64 ) ); - } }; - - vm::lifters::lifter_t lconstdw = { - // push imm - vm::handler::LCONSTDW, - []( vtil::basic_block *blk, vm::instrs::virt_instr_t *vinstr, vmp2::v3::code_block_t *code_blk ) { - blk->push( vtil::operand( vinstr->operand.imm.u, 32 ) ); - } }; - - vm::lifters::lifter_t lconstw = { - // push imm - vm::handler::LCONSTW, - []( vtil::basic_block *blk, vm::instrs::virt_instr_t *vinstr, vmp2::v3::code_block_t *code_blk ) { - blk->push( vtil::operand( vinstr->operand.imm.u, 16 ) ); - } }; - - vm::lifters::lifter_t lconstbzxw = { - // push imm - vm::handler::LCONSTBZXW, - []( vtil::basic_block *blk, vm::instrs::virt_instr_t *vinstr, vmp2::v3::code_block_t *code_blk ) { - blk->push( vtil::operand( vinstr->operand.imm.u, 16 ) ); - } }; - - vm::lifters::lifter_t lconstbsxdw = { - // push imm - vm::handler::LCONSTBSXDW, - []( vtil::basic_block *blk, vm::instrs::virt_instr_t *vinstr, vmp2::v3::code_block_t *code_blk ) { - blk->push( vtil::operand( vinstr->operand.imm.u, 32 ) ); - } }; - - vm::lifters::lifter_t lconstbsxq = { - // push imm - vm::handler::LCONSTBSXQ, - []( vtil::basic_block *blk, vm::instrs::virt_instr_t *vinstr, vmp2::v3::code_block_t *code_blk ) { - blk->push( vtil::operand( vinstr->operand.imm.u, 64 ) ); - } }; - - vm::lifters::lifter_t lconstdwsxq = { - // push imm - vm::handler::LCONSTDWSXQ, - []( vtil::basic_block *blk, vm::instrs::virt_instr_t *vinstr, vmp2::v3::code_block_t *code_blk ) { - blk->push( vtil::operand( vinstr->operand.imm.u, 64 ) ); - } }; - - vm::lifters::lifter_t lconstwsxq = { - // push imm - vm::handler::LCONSTWSXQ, - []( vtil::basic_block *blk, vm::instrs::virt_instr_t *vinstr, vmp2::v3::code_block_t *code_blk ) { - blk->push( vtil::operand( vinstr->operand.imm.u, 64 ) ); - } }; - - vm::lifters::lifter_t lconstwsxdw = { - // push imm - vm::handler::LCONSTWSXDW, - []( vtil::basic_block *blk, vm::instrs::virt_instr_t *vinstr, vmp2::v3::code_block_t *code_blk ) { - blk->push( vtil::operand( vinstr->operand.imm.u, 32 ) ); - } }; -} // namespace vm::lifters \ No newline at end of file diff --git a/src/vmlifters/lflags.cpp b/src/vmlifters/lflags.cpp deleted file mode 100644 index 8ba753a..0000000 --- a/src/vmlifters/lflags.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include - -namespace vm::lifters -{ - vm::lifters::lifter_t lrflags = { - // push flags - vm::handler::LRFLAGS, []( vtil::basic_block *blk, vm::instrs::virt_instr_t *vinstr, - vmp2::v3::code_block_t *code_blk ) { blk->push( vtil::REG_FLAGS ); } }; -} \ No newline at end of file diff --git a/src/vmlifters/lreg.cpp b/src/vmlifters/lreg.cpp deleted file mode 100644 index 2f0fb23..0000000 --- a/src/vmlifters/lreg.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include - -namespace vm::lifters -{ - vm::lifters::lifter_t lregq = { - // push vregX - vm::handler::LREGQ, - []( vtil::basic_block *blk, vm::instrs::virt_instr_t *vinstr, vmp2::v3::code_block_t *code_blk ) { - blk->push( make_virtual_register( vinstr->operand.imm.u, 8 ) ); - } }; - - vm::lifters::lifter_t lregdw = { - // push vregX - vm::handler::LREGDW, - []( vtil::basic_block *blk, vm::instrs::virt_instr_t *vinstr, vmp2::v3::code_block_t *code_blk ) { - blk->push( make_virtual_register( vinstr->operand.imm.u, 4 ) ); - } }; -} // namespace vm::lifters \ No newline at end of file diff --git a/src/vmlifters/lvsp.cpp b/src/vmlifters/lvsp.cpp deleted file mode 100644 index 7943aa9..0000000 --- a/src/vmlifters/lvsp.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include - -namespace vm::lifters -{ - vm::lifters::lifter_t lvsp = { - // vsp = vsp[0] - vm::handler::LVSP, []( vtil::basic_block *blk, vm::instrs::virt_instr_t *vinstr, - vmp2::v3::code_block_t *code_blk ) { blk->pop( vtil::REG_SP ); } }; -} \ No newline at end of file diff --git a/src/vmlifters/nand.cpp b/src/vmlifters/nand.cpp deleted file mode 100644 index bdf4bb8..0000000 --- a/src/vmlifters/nand.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include - -namespace vm::lifters -{ - vm::lifters::lifter_t nandq = { - // pop vregX - // pop vregY - // not vregX - // not vregY - // and vregX, vregY - // push vregX - // pushf - vm::handler::NANDQ, - []( vtil::basic_block *blk, vm::instrs::virt_instr_t *vinstr, vmp2::v3::code_block_t *code_blk ) { - auto [ t1, t2 ] = blk->tmp( 64, 64 ); - blk->pop( t1 ); - blk->pop( t2 ); - - blk->bnot( t1 ); - blk->bnot( t2 ); - - blk->band( t1, t2 ); - blk->push( t1 ); - blk->pushf(); - } }; - - vm::lifters::lifter_t nanddw = { - // pop vregX - // pop vregY - // not vregX - // not vregY - // and vregX, vregY - // push vregX - // pushf - vm::handler::NANDDW, - []( vtil::basic_block *blk, vm::instrs::virt_instr_t *vinstr, vmp2::v3::code_block_t *code_blk ) { - auto [ t1, t2 ] = blk->tmp( 32, 32 ); - blk->pop( t1 ); - blk->pop( t2 ); - - blk->bnot( t1 ); - blk->bnot( t2 ); - - blk->band( t1, t2 ); - blk->push( t1 ); - blk->pushf(); - } }; - - vm::lifters::lifter_t nandw = { - // pop vregX - // pop vregY - // not vregX - // not vregY - // and vregX, vregY - // push vregX - // pushf - vm::handler::NANDW, - []( vtil::basic_block *blk, vm::instrs::virt_instr_t *vinstr, vmp2::v3::code_block_t *code_blk ) { - auto [ t1, t2 ] = blk->tmp( 16, 16 ); - blk->pop( t1 ); - blk->pop( t2 ); - - blk->bnot( t1 ); - blk->bnot( t2 ); - - blk->band( t1, t2 ); - blk->push( t1 ); - blk->pushf(); - } }; -} // namespace vm::lifters \ No newline at end of file diff --git a/src/vmlifters/pushvsp.cpp b/src/vmlifters/pushvsp.cpp deleted file mode 100644 index 1de8465..0000000 --- a/src/vmlifters/pushvsp.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include - -namespace vm::lifters -{ - vm::lifters::lifter_t pushvsp = { - // push vsp - vm::handler::PUSHVSP, []( vtil::basic_block *blk, vm::instrs::virt_instr_t *vinstr, - vmp2::v3::code_block_t *code_blk ) { blk->push( vtil::REG_SP ); } }; -} \ No newline at end of file diff --git a/src/vmlifters/read.cpp b/src/vmlifters/read.cpp deleted file mode 100644 index 6299524..0000000 --- a/src/vmlifters/read.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include - -namespace vm::lifters -{ - vm::lifters::lifter_t readq = { - // pop vregX - // ldd vregX, vregX, 0 - // push vregX - vm::handler::READQ, - []( vtil::basic_block *blk, vm::instrs::virt_instr_t *vinstr, vmp2::v3::code_block_t *code_blk ) { - auto [ t0, t1 ] = blk->tmp( 64, 64 ); - blk->pop( t0 ); - blk->ldd( t1, t0, vtil::make_imm( 0ull ) ); - blk->push( t1 ); - } }; - - vm::lifters::lifter_t readdw = { - // pop vregX - // ldd vregX, vregX, 0 - // push vregX - vm::handler::READDW, - []( vtil::basic_block *blk, vm::instrs::virt_instr_t *vinstr, vmp2::v3::code_block_t *code_blk ) { - auto [ t0, t1 ] = blk->tmp( 64, 32 ); - blk->pop( t0 ); - blk->ldd( t1, t0, vtil::make_imm( 0ull ) ); - blk->push( t1 ); - } }; - - vm::lifters::lifter_t readw = { - // pop vregX - // ldd vregX, vregX, 0 - // push vregX - vm::handler::READW, - []( vtil::basic_block *blk, vm::instrs::virt_instr_t *vinstr, vmp2::v3::code_block_t *code_blk ) { - auto [ t0, t1 ] = blk->tmp( 64, 16 ); - blk->pop( t0 ); - blk->ldd( t1, t0, vtil::make_imm( 0ull ) ); - blk->push( t1 ); - } }; -} // namespace vm::lifters \ No newline at end of file diff --git a/src/vmlifters/shr.cpp b/src/vmlifters/shr.cpp deleted file mode 100644 index f8610ac..0000000 --- a/src/vmlifters/shr.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include - -namespace vm::lifters -{ - vm::lifters::lifter_t shrq = { - // pop vregX - // pop vregY - // shr vregX, vregY - // push vregX - // pushf - vm::handler::SHRQ, - []( vtil::basic_block *blk, vm::instrs::virt_instr_t *vinstr, vmp2::v3::code_block_t *code_blk ) { - auto [ t0, t1 ] = blk->tmp( 64, 8 ); - blk->pop( t0 ); - blk->pop( t1 ); - blk->bshr( t0, t1 ); - blk->push( t0 ); - blk->pushf(); - } }; - - vm::lifters::lifter_t shrw = { - // pop vregX - // pop vregY - // shr vregX, vregY - // push vregX - // pushf - vm::handler::SHRW, - []( vtil::basic_block *blk, vm::instrs::virt_instr_t *vinstr, vmp2::v3::code_block_t *code_blk ) { - auto [ t0, t1 ] = blk->tmp( 16, 8 ); - blk->pop( t0 ); - blk->pop( t1 ); - blk->bshr( t0, t1 ); - blk->push( t0 ); - blk->pushf(); - } }; -} // namespace vm::lifters \ No newline at end of file diff --git a/src/vmlifters/sreg.cpp b/src/vmlifters/sreg.cpp deleted file mode 100644 index 253322f..0000000 --- a/src/vmlifters/sreg.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include - -namespace vm::lifters -{ - vm::lifters::lifter_t sregq = { - // pop vregX - vm::handler::SREGQ, - []( vtil::basic_block *blk, vm::instrs::virt_instr_t *vinstr, vmp2::v3::code_block_t *code_blk ) { - blk->pop( make_virtual_register( vinstr->operand.imm.u, 8 ) ); - } }; - - vm::lifters::lifter_t sregdw = { - // pop vregX - vm::handler::SREGDW, - []( vtil::basic_block *blk, vm::instrs::virt_instr_t *vinstr, vmp2::v3::code_block_t *code_blk ) { - blk->pop( make_virtual_register( vinstr->operand.imm.u, 4 ) ); - } }; - - vm::lifters::lifter_t sregw = { - // pop vregX - vm::handler::SREGW, - []( vtil::basic_block *blk, vm::instrs::virt_instr_t *vinstr, vmp2::v3::code_block_t *code_blk ) { - blk->pop( make_virtual_register( vinstr->operand.imm.u, 2 ) ); - } }; -} // namespace vm::lifters \ No newline at end of file diff --git a/src/vmlifters/vmexit.cpp b/src/vmlifters/vmexit.cpp deleted file mode 100644 index 1fa8a9b..0000000 --- a/src/vmlifters/vmexit.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include - -namespace vm::lifters -{ - vm::lifters::lifter_t vmexit = { - // ret - vm::handler::VMEXIT, - []( vtil::basic_block *blk, vm::instrs::virt_instr_t *vinstr, vmp2::v3::code_block_t *code_blk ) { - blk->vexit( vtil::make_imm( vinstr->trace_data.vsp.qword[ 0x13 ] - vinstr->trace_data.regs.r13 ) ); - } }; -} \ No newline at end of file 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