diff --git a/CMakeLists.txt b/CMakeLists.txt index 59069e8..373e5f2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,6 +40,7 @@ set(CMKR_TARGET vmdevirt) set(vmdevirt_SOURCES "") list(APPEND vmdevirt_SOURCES + "src/devirt_t.cpp" "src/lifters/add.cpp" "src/lifters/div.cpp" "src/lifters/jmp.cpp" @@ -56,9 +57,10 @@ list(APPEND vmdevirt_SOURCES "src/lifters/sreg.cpp" "src/lifters/vmexit.cpp" "src/main.cpp" - "src/vmp_rtn.cpp" + "src/vmp_rtn_t.cpp" + "include/devirt_t.hpp" "include/vm_lifters.hpp" - "include/vmp_rtn.hpp" + "include/vmp_rtn_t.hpp" ) list(APPEND vmdevirt_SOURCES @@ -86,6 +88,8 @@ target_compile_definitions(vmdevirt PRIVATE target_include_directories(vmdevirt PRIVATE include "dependencies/llvm/llvm/include/" + "dependencies/llvm/llvm/lib/Target/X86/" + "build/dependencies/llvm/llvm/lib/Target/X86" "build/dependencies/llvm/llvm/include/" ) @@ -96,6 +100,12 @@ target_link_libraries(vmdevirt PRIVATE LLVMCodeGen LLVMSupport LLVMLinker + LLVMX86CodeGen + LLVMX86AsmParser + LLVMX86Desc + LLVMX86Disassembler + LLVMX86Info + LLVMAsmParser ) unset(CMKR_TARGET) diff --git a/cmake.toml b/cmake.toml index 1be73bc..41fdb54 100644 --- a/cmake.toml +++ b/cmake.toml @@ -12,6 +12,8 @@ sources = [ include-directories = [ "include", "dependencies/llvm/llvm/include/", + "dependencies/llvm/llvm/lib/Target/X86/", + "build/dependencies/llvm/llvm/lib/Target/X86", "build/dependencies/llvm/llvm/include/", ] link-libraries = [ @@ -20,7 +22,13 @@ link-libraries = [ "LLVMCore", "LLVMCodeGen", "LLVMSupport", - "LLVMLinker" + "LLVMLinker", + "LLVMX86CodeGen", + "LLVMX86AsmParser", + "LLVMX86Desc", + "LLVMX86Disassembler", + "LLVMX86Info", + "LLVMAsmParser" ] compile-definitions = [ "NOMINMAX" diff --git a/dependencies/vmprofiler b/dependencies/vmprofiler index f06bf5f..05c98b1 160000 --- a/dependencies/vmprofiler +++ b/dependencies/vmprofiler @@ -1 +1 @@ -Subproject commit f06bf5f6b72b1d52a6156d6828675c77ceaee7e2 +Subproject commit 05c98b1ef57c3375ffd455221a3be1be6110d4eb diff --git a/include/devirt_t.hpp b/include/devirt_t.hpp new file mode 100644 index 0000000..63bce8f --- /dev/null +++ b/include/devirt_t.hpp @@ -0,0 +1,72 @@ +#pragma once +#include + +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/IRPrintingPasses.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/Mangler.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/Verifier.h" + +#include "llvm/Transforms/InstCombine/InstCombine.h" +#include "llvm/Transforms/Scalar.h" +#include "llvm/Transforms/Scalar/GVN.h" + +#include "X86TargetMachine.h" +#include "llvm/Pass.h" +#include "llvm/Passes/PassBuilder.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" + +namespace llvm +{ + extern "C" void LLVMInitializeX86TargetInfo(); + extern "C" void LLVMInitializeX86Target(); + extern "C" void LLVMInitializeX86TargetMC(); + extern "C" void LLVMInitializeX86AsmParser(); + extern "C" void LLVMInitializeX86AsmPrinter(); +} // namespace llvm + +namespace vm +{ + class devirt_t + { + friend class lifters_t; + + public: + explicit devirt_t( llvm::LLVMContext *llvm_ctx, llvm::Module *llvm_module ); + llvm::Function *lift( std::uintptr_t rtn_begin, std::vector< vm::instrs::code_block_t > vmp2_code_blocks ); + bool compile( std::vector< std::uint8_t > &obj ); + + private: + llvm::LLVMContext *llvm_ctx; + llvm::Module *llvm_module; + std::shared_ptr< llvm::IRBuilder<> > ir_builder; + std::vector< std::shared_ptr< vm::vmp_rtn_t > > vmp_rtns; + + void create_routine( void ); + void push( std::uint8_t byte_size, llvm::Value *input_val ); + llvm::Value *pop( std::uint8_t byte_size ); + + llvm::Value *load_value( std::uint8_t byte_size, llvm::GlobalValue *global ); + llvm::Value *load_value( std::uint8_t byte_size, llvm::AllocaInst *var ); + + llvm::Value *compute_sf( std::uint8_t byte_size, llvm::Value *val ); + llvm::Value *compute_zf( std::uint8_t byte_size, llvm::Value *val ); + llvm::Value *compute_pf( std::uint8_t byte_size, llvm::Value *val ); + llvm::Value *combine_flags( llvm::Value *cf, llvm::Value *pf, llvm::Value *af, llvm::Value *zf, llvm::Value *sf, + llvm::Value *of ); + }; +} // namespace vm \ No newline at end of file diff --git a/include/vm_lifters.hpp b/include/vm_lifters.hpp index 1bbaec2..e9b5717 100644 --- a/include/vm_lifters.hpp +++ b/include/vm_lifters.hpp @@ -1,7 +1,5 @@ #pragma once -#include -#include -#include +#include #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constants.h" @@ -27,7 +25,7 @@ namespace vm } using lifter_callback_t = - std::function< void( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block, + std::function< void( vm::devirt_t *rtn, const vm::instrs::code_block_t &vm_code_block, const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) >; static lifter_callback_t lconstq, lconstdwsxq, lconstwsxq, lconstbzxw, lconstbsxq, lconstwsxdw, lconstdw, @@ -70,11 +68,10 @@ namespace vm { vm::handler::JMP, &jmp }, { vm::handler::VMEXIT, &vmexit } }; - static vm::llvm_value_t *and_flags( vm::vmp_rtn_t *rtn, std::uint8_t byte_size, vm::llvm_value_t *result ); - static vm::llvm_value_t *add_flags( vm::vmp_rtn_t *rtn, std::uint8_t byte_size, vm::llvm_value_t *lhs, - vm::llvm_value_t *rhs ); - static vm::llvm_value_t *shr_flags( vm::vmp_rtn_t *rtn, std::uint8_t byte_size, vm::llvm_value_t *lhs, - vm::llvm_value_t *rhs, vm::llvm_value_t *result ); + static llvm::Value *and_flags( vm::devirt_t *rtn, std::uint8_t byte_size, llvm::Value *result ); + static llvm::Value *add_flags( vm::devirt_t *rtn, std::uint8_t byte_size, llvm::Value *lhs, llvm::Value *rhs ); + static llvm::Value *shr_flags( vm::devirt_t *rtn, std::uint8_t byte_size, llvm::Value *lhs, llvm::Value *rhs, + llvm::Value *result ); public: static lifters_t *get_instance( void ) @@ -83,7 +80,7 @@ namespace vm return &obj; } - bool lift( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block, + bool lift( vm::devirt_t *rtn, const vm::instrs::code_block_t &vm_code_block, const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) { if ( vinstr.mnemonic_t == vm::handler::INVALID || lifters.find( vinstr.mnemonic_t ) == lifters.end() ) diff --git a/include/vmp_rtn.hpp b/include/vmp_rtn.hpp deleted file mode 100644 index c309fc6..0000000 --- a/include/vmp_rtn.hpp +++ /dev/null @@ -1,71 +0,0 @@ -#pragma once -#include - -#include "llvm/IR/BasicBlock.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/IRBuilder.h" -#include "llvm/IR/IRPrintingPasses.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/PassManager.h" -#include "llvm/IR/Type.h" -#include "llvm/IR/Verifier.h" -#include "llvm/Pass.h" -#include "llvm/Support/raw_ostream.h" - -namespace vm -{ - // Obsessive-compulsive disorder is characterized by unreasonable - // thoughts and fears (obsessions) that lead to compulsive behaviors. - using llvm_type_t = llvm::Type; - using llvm_value_t = llvm::Value; - using llvm_module_t = llvm::Module; - using llvm_context_t = llvm::LLVMContext; - using llvm_function_t = llvm::Function; - using llvm_irbuilder_t = llvm::IRBuilder<>; - using llvm_alloca_inst_t = llvm::AllocaInst; - using llvm_basic_block_t = llvm::BasicBlock; - using llvm_global_value_t = llvm::GlobalValue; - - class vmp_rtn_t - { - friend class lifters_t; - - public: - explicit vmp_rtn_t( llvm_context_t *llvm_ctx, llvm_module_t *llvm_module, vm::ctx_t *vm_ctx, - std::uintptr_t rtn_begin, std::vector< vm::instrs::code_block_t > vmp2_code_blocks ); - - llvm_function_t *lift( void ); - - private: - llvm_context_t *llvm_ctx; - llvm_module_t *llvm_module; - llvm_function_t *llvm_fptr; - llvm_alloca_inst_t *flags, *stack; - - vm::ctx_t *vm_ctx; - std::uintptr_t rtn_begin; - std::shared_ptr< llvm_irbuilder_t > ir_builder; - - std::vector< llvm_alloca_inst_t * > virtual_registers; - std::vector< std::pair< std::uintptr_t, llvm_basic_block_t * > > llvm_code_blocks; - std::vector< vm::instrs::code_block_t > vmp2_code_blocks; - - void push( std::uint8_t byte_size, llvm_value_t *input_val ); - llvm::Value *pop( std::uint8_t byte_size ); - - llvm::Value *load_value( std::uint8_t byte_size, llvm_global_value_t *global ); - llvm::Value *load_value( std::uint8_t byte_size, llvm_alloca_inst_t *var ); - - llvm_value_t *compute_sf( std::uint8_t byte_size, llvm_value_t *val ); - llvm_value_t *compute_zf( std::uint8_t byte_size, llvm_value_t *val ); - llvm_value_t *compute_pf( std::uint8_t byte_size, llvm_value_t *val ); - llvm_value_t *combine_flags( llvm_value_t *cf, llvm_value_t *pf, llvm_value_t *af, llvm_value_t *zf, - llvm_value_t *sf, llvm_value_t *of ); - - void create_virtual_registers( void ); - void create_routine( void ); - }; -} // namespace vm \ No newline at end of file diff --git a/include/vmp_rtn_t.hpp b/include/vmp_rtn_t.hpp new file mode 100644 index 0000000..a4aa92d --- /dev/null +++ b/include/vmp_rtn_t.hpp @@ -0,0 +1,41 @@ +#pragma once +#include + +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/IRPrintingPasses.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/Mangler.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/Verifier.h" + +namespace vm +{ + class vmp_rtn_t + { + llvm::Function *llvm_fptr; + llvm::AllocaInst *flags, *stack; + llvm::Module *llvm_module; + + std::uintptr_t rtn_begin; + std::shared_ptr< llvm::IRBuilder<> > ir_builder; + std::vector< llvm::AllocaInst * > virtual_registers; + std::vector< std::pair< std::uintptr_t, llvm::BasicBlock * > > llvm_code_blocks; + std::vector< vm::instrs::code_block_t > vmp2_code_blocks; + void create_virtual_registers( void ); + void create_routine( void ); + + friend class devirt_t; + friend class lifters_t; + + public: + explicit vmp_rtn_t( std::uintptr_t rtn_begin, std::vector< vm::instrs::code_block_t > vmp2_code_blocks, + std::shared_ptr< llvm::IRBuilder<> > &ir_builder, llvm::Module *llvm_module ); + }; +} // namespace vm \ No newline at end of file diff --git a/src/devirt_t.cpp b/src/devirt_t.cpp new file mode 100644 index 0000000..8b2c5d2 --- /dev/null +++ b/src/devirt_t.cpp @@ -0,0 +1,141 @@ +#include +#include + +namespace vm +{ + devirt_t::devirt_t( llvm::LLVMContext *llvm_ctx, llvm::Module *llvm_module ) + : llvm_ctx( llvm_ctx ), llvm_module( llvm_module ) + { + ir_builder = std::make_shared< llvm::IRBuilder<> >( *llvm_ctx ); + } + + void devirt_t::push( std::uint8_t num_bytes, llvm::Value *val ) + { + // sub rsp, num_bytes + auto current_rtn = vmp_rtns.back(); + auto rsp_addr = ir_builder->CreateLoad( current_rtn->stack ); + auto sub_rsp_val = + ir_builder->CreateGEP( ir_builder->getInt8Ty(), rsp_addr, ir_builder->getInt8( 0 - num_bytes ) ); + + ir_builder->CreateStore( sub_rsp_val, current_rtn->stack ); + + // mov [rsp], val + auto resized_new_rsp_addr = ir_builder->CreateBitCast( + sub_rsp_val, llvm::PointerType::get( llvm::IntegerType::get( *llvm_ctx, num_bytes * 8 ), 0ull ) ); + ir_builder->CreateStore( val, resized_new_rsp_addr ); + } + + llvm::Value *devirt_t::pop( std::uint8_t num_bytes ) + { + // mov rax, [rsp] + auto current_rtn = vmp_rtns.back(); + auto rsp_addr = ir_builder->CreateLoad( current_rtn->stack ); + auto new_rsp_addr = + ir_builder->CreateGEP( ir_builder->getInt8Ty(), rsp_addr, ir_builder->getInt8( num_bytes ) ); + + auto resized_new_rsp_addr = ir_builder->CreateBitCast( + rsp_addr, llvm::PointerType::get( llvm::IntegerType::get( *llvm_ctx, num_bytes * 8 ), 0ull ) ); + auto pop_val = ir_builder->CreateLoad( resized_new_rsp_addr ); + ir_builder->CreateStore( new_rsp_addr, current_rtn->stack ); + ir_builder->CreateStore( llvm::UndefValue::get( ir_builder->getInt8Ty() ), rsp_addr ); + return pop_val; + } + + llvm::Value *devirt_t::load_value( std::uint8_t byte_size, llvm::GlobalValue *var ) + { + if ( byte_size * 8 != var->getType()->getPrimitiveSizeInBits() ) + { + auto cast_ptr = ir_builder->CreatePointerCast( + var, llvm::PointerType::get( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), 0 ) ); + + return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), cast_ptr ); + } + return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), var ); + } + + llvm::Value *devirt_t::load_value( std::uint8_t byte_size, llvm::AllocaInst *var ) + { + if ( byte_size * 8 != var->getType()->getPrimitiveSizeInBits() ) + { + auto cast_ptr = ir_builder->CreatePointerCast( + var, llvm::PointerType::get( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), 0 ) ); + + return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), cast_ptr ); + } + return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), var ); + } + + bool devirt_t::compile( std::vector< std::uint8_t > &obj ) + { + return true; + } + + llvm::Function *devirt_t::lift( std::uintptr_t rtn_begin, std::vector< vm::instrs::code_block_t > code_blocks ) + { + vmp_rtns.push_back( std::make_shared< vm::vmp_rtn_t >( rtn_begin, code_blocks, ir_builder, llvm_module ) ); + + auto &vmp_rtn = vmp_rtns.back(); + auto lifters = vm::lifters_t::get_instance(); + + for ( auto idx = 0u; idx < vmp_rtn->vmp2_code_blocks.size(); ++idx ) + { + ir_builder->SetInsertPoint( vmp_rtn->llvm_code_blocks[ idx ].second ); + for ( auto &vinstr : vmp_rtn->vmp2_code_blocks[ idx ].vinstrs ) + { + if ( !lifters->lift( this, vmp_rtn->vmp2_code_blocks[ idx ], vinstr, ir_builder.get() ) ) + { + std::printf( + "> failed to devirtualize virtual instruction with opcode = %d, handler table rva = 0x%x\n", + vinstr.opcode, vinstr.trace_data.regs.r12 - vinstr.trace_data.regs.r13 ); + + return nullptr; + } + } + } + return vmp_rtn->llvm_fptr; + } + + llvm::Value *devirt_t::compute_sf( std::uint8_t byte_size, llvm::Value *val ) + { + auto op_size = llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ); + auto msb = ir_builder->CreateLShr( val, ( byte_size * 8 ) - 1 ); + return ir_builder->CreateZExt( msb, llvm::IntegerType::get( *llvm_ctx, 64 ) ); + } + + llvm::Value *devirt_t::compute_zf( std::uint8_t byte_size, llvm::Value *val ) + { + auto op_size = llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ); + auto is_zero = ir_builder->CreateICmpEQ( val, llvm::ConstantInt::get( op_size, 0 ) ); + return ir_builder->CreateZExt( is_zero, llvm::IntegerType::get( *llvm_ctx, 64 ) ); + } + + llvm::Value *devirt_t::compute_pf( std::uint8_t byte_size, llvm::Value *val ) + { + auto operand_size = llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ); + auto popcount_intrinsic = llvm::Intrinsic::getDeclaration( llvm_module, llvm::Intrinsic::ctpop, + { llvm::IntegerType::get( *llvm_ctx, 64 ) } ); + + auto lower_bits = ir_builder->CreateIntCast( val, llvm::IntegerType::get( *llvm_ctx, 8 ), false ); + auto extended_bits = ir_builder->CreateZExt( lower_bits, llvm::IntegerType::get( *llvm_ctx, 64 ) ); + return ir_builder->CreateCall( popcount_intrinsic, { extended_bits } ); + } + + llvm::Value *devirt_t::combine_flags( llvm::Value *cf, llvm::Value *pf, llvm::Value *af, llvm::Value *zf, + llvm::Value *sf, llvm::Value *of ) + { + auto shifted_pf = ir_builder->CreateShl( pf, 2, "shifted_pf", true, true ); + auto shifted_af = ir_builder->CreateShl( llvm::ConstantInt::get( llvm::IntegerType::get( *llvm_ctx, 64 ), 0 ), + 4, "shifted_af", true, true ); // treat af as zero + + auto shifted_zf = ir_builder->CreateShl( zf, 6, "shifted_zf", true, true ); + auto shifted_sf = ir_builder->CreateShl( sf, 7, "shifted_sf", true, true ); + auto shifted_of = ir_builder->CreateShl( of, 11, "shifted_of", true, true ); + auto or1 = ir_builder->CreateOr( cf, shifted_of ); + auto or2 = ir_builder->CreateOr( or1, shifted_zf ); + auto or3 = ir_builder->CreateOr( or2, shifted_sf ); + auto or4 = ir_builder->CreateOr( or3, shifted_af ); + auto or5 = ir_builder->CreateOr( or4, shifted_pf ); + return ir_builder->CreateXor( or5, llvm::ConstantInt::get( llvm::IntegerType::get( *llvm_ctx, 64 ), 514 ) ); + } + +} // namespace vm \ No newline at end of file diff --git a/src/lifters/add.cpp b/src/lifters/add.cpp index 85903bb..1f298f0 100644 --- a/src/lifters/add.cpp +++ b/src/lifters/add.cpp @@ -2,8 +2,7 @@ namespace vm { - vm::llvm_value_t *lifters_t::add_flags( vm::vmp_rtn_t *rtn, std::uint8_t byte_size, vm::llvm_value_t *lhs, - vm::llvm_value_t *rhs ) + llvm::Value *lifters_t::add_flags( vm::devirt_t *rtn, std::uint8_t byte_size, llvm::Value *lhs, llvm::Value *rhs ) { auto op_size = llvm::IntegerType::get( *rtn->llvm_ctx, byte_size * 8 ); std::vector< llvm::Type * > intrinsic_arg_types; @@ -37,42 +36,45 @@ namespace vm } lifters_t::lifter_callback_t lifters_t::addq = - [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block, + [ & ]( vm::devirt_t *rtn, const vm::instrs::code_block_t &vm_code_block, const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) { auto t1 = rtn->pop( 8 ); auto t2 = rtn->pop( 8 ); auto t3 = ir_builder->CreateAdd( t1, t2 ); rtn->push( 8, t3 ); + auto &vmp_rtn = rtn->vmp_rtns.back(); auto flags = lifters_t::add_flags( rtn, 8, t1, t2 ); - ir_builder->CreateStore( flags, rtn->flags ); - rtn->push( 8, rtn->load_value( 8, rtn->flags ) ); + ir_builder->CreateStore( flags, vmp_rtn->flags ); + rtn->push( 8, rtn->load_value( 8, vmp_rtn->flags ) ); }; lifters_t::lifter_callback_t lifters_t::adddw = - [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block, + [ & ]( vm::devirt_t *rtn, const vm::instrs::code_block_t &vm_code_block, const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) { auto t1 = rtn->pop( 4 ); auto t2 = rtn->pop( 4 ); auto t3 = ir_builder->CreateAdd( t1, t2 ); rtn->push( 4, t3 ); + auto &vmp_rtn = rtn->vmp_rtns.back(); auto flags = lifters_t::add_flags( rtn, 4, t1, t2 ); - ir_builder->CreateStore( flags, rtn->flags ); - rtn->push( 8, rtn->load_value( 8, rtn->flags ) ); + ir_builder->CreateStore( flags, vmp_rtn->flags ); + rtn->push( 8, rtn->load_value( 8, vmp_rtn->flags ) ); }; lifters_t::lifter_callback_t lifters_t::addw = - [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block, + [ & ]( vm::devirt_t *rtn, const vm::instrs::code_block_t &vm_code_block, const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) { auto t1 = rtn->pop( 2 ); auto t2 = rtn->pop( 2 ); auto t3 = ir_builder->CreateAdd( t1, t2 ); rtn->push( 2, t3 ); + auto &vmp_rtn = rtn->vmp_rtns.back(); auto flags = lifters_t::add_flags( rtn, 2, t1, t2 ); - ir_builder->CreateStore( flags, rtn->flags ); - rtn->push( 8, rtn->load_value( 8, rtn->flags ) ); + ir_builder->CreateStore( flags, vmp_rtn->flags ); + rtn->push( 8, rtn->load_value( 8, vmp_rtn->flags ) ); }; } // namespace vm \ No newline at end of file diff --git a/src/lifters/jmp.cpp b/src/lifters/jmp.cpp index 3ed5b33..43464ad 100644 --- a/src/lifters/jmp.cpp +++ b/src/lifters/jmp.cpp @@ -2,54 +2,56 @@ namespace vm { - lifters_t::lifter_callback_t lifters_t::jmp = [ & ]( vm::vmp_rtn_t *rtn, - const vm::instrs::code_block_t &vm_code_block, - const vm::instrs::virt_instr_t &vinstr, - llvm::IRBuilder<> *ir_builder ) { - assert( vm_code_block.jcc.has_jcc, "[!] fatal error in vmemu... virtual block ending with jmp marked as" - " has_jcc = false... debug time!\n" ); - - if ( vm_code_block.jcc.type == vm::instrs::jcc_type::branching ) - { - auto rva = rtn->pop( 8 ); - auto b1 = vm_code_block.jcc.block_addr[ 0 ] & std::numeric_limits< std::uint32_t >::max(); - - auto _const_b1 = llvm::ConstantInt::get( ir_builder->getInt64Ty(), b1 ); - auto cmp = ir_builder->CreateCmp( llvm::CmpInst::ICMP_EQ, rva, _const_b1 ); - - // find the first branch basic block... - auto bb1 = - std::find_if( rtn->llvm_code_blocks.begin(), rtn->llvm_code_blocks.end(), - [ & ]( const std::pair< std::uintptr_t, llvm_basic_block_t * > &block_data ) -> bool { - return block_data.first == vm_code_block.jcc.block_addr[ 0 ]; - } ); - - assert( bb1 != rtn->llvm_code_blocks.end(), - "[!] fatal error... unable to locate basic block for branching...\n" ); - - // find the second branch basic block... - auto bb2 = - std::find_if( rtn->llvm_code_blocks.begin(), rtn->llvm_code_blocks.end(), - [ & ]( const std::pair< std::uintptr_t, llvm_basic_block_t * > &block_data ) -> bool { - return block_data.first == vm_code_block.jcc.block_addr[ 1 ]; - } ); - - assert( bb2 != rtn->llvm_code_blocks.end(), - "[!] fatal error... unable to locate basic block for branching...\n" ); - - ir_builder->CreateCondBr( cmp, bb1->second, bb2->second ); - } - else - { - auto rva = rtn->pop( 8 ); - auto bb_data = - std::find_if( rtn->llvm_code_blocks.begin(), rtn->llvm_code_blocks.end(), - [ & ]( const std::pair< std::uintptr_t, llvm_basic_block_t * > &block_data ) -> bool { - return block_data.first == vm_code_block.jcc.block_addr[ 0 ]; - } ); - - assert( bb_data != rtn->llvm_code_blocks.end(), "[!] fatal error... unable to locate basic block...\n" ); - ir_builder->CreateBr( bb_data->second ); - } - }; + lifters_t::lifter_callback_t lifters_t::jmp = + [ & ]( vm::devirt_t *rtn, const vm::instrs::code_block_t &vm_code_block, const vm::instrs::virt_instr_t &vinstr, + llvm::IRBuilder<> *ir_builder ) { + assert( vm_code_block.jcc.has_jcc, "[!] fatal error in vmemu... virtual block ending with jmp marked as" + " has_jcc = false... debug time!\n" ); + + auto &vmp_rtn = rtn->vmp_rtns.back(); + if ( vm_code_block.jcc.type == vm::instrs::jcc_type::branching ) + { + auto rva = rtn->pop( 8 ); + auto b1 = vm_code_block.jcc.block_addr[ 0 ] & std::numeric_limits< std::uint32_t >::max(); + + auto _const_b1 = llvm::ConstantInt::get( ir_builder->getInt64Ty(), b1 ); + auto cmp = ir_builder->CreateCmp( llvm::CmpInst::ICMP_EQ, rva, _const_b1 ); + + // find the first branch basic block... + auto bb1 = + std::find_if( vmp_rtn->llvm_code_blocks.begin(), vmp_rtn->llvm_code_blocks.end(), + [ & ]( const std::pair< std::uintptr_t, llvm::BasicBlock * > &block_data ) -> bool { + return block_data.first == vm_code_block.jcc.block_addr[ 0 ]; + } ); + + assert( bb1 != vmp_rtn->llvm_code_blocks.end(), + "[!] fatal error... unable to locate basic block for branching...\n" ); + + // find the second branch basic block... + auto bb2 = + std::find_if( vmp_rtn->llvm_code_blocks.begin(), vmp_rtn->llvm_code_blocks.end(), + [ & ]( const std::pair< std::uintptr_t, llvm::BasicBlock * > &block_data ) -> bool { + return block_data.first == vm_code_block.jcc.block_addr[ 1 ]; + } ); + + assert( bb2 != vmp_rtn->llvm_code_blocks.end(), + "[!] fatal error... unable to locate basic block for branching...\n" ); + + ir_builder->CreateCondBr( cmp, bb1->second, bb2->second ); + } + else + { + auto rva = rtn->pop( 8 ); + auto bb_data = + std::find_if( vmp_rtn->llvm_code_blocks.begin(), vmp_rtn->llvm_code_blocks.end(), + [ & ]( const std::pair< std::uintptr_t, llvm::BasicBlock * > &block_data ) -> bool { + return block_data.first == vm_code_block.jcc.block_addr[ 0 ]; + } ); + + assert( bb_data != vmp_rtn->llvm_code_blocks.end(), + "[!] fatal error... unable to locate basic block...\n" ); + + ir_builder->CreateBr( bb_data->second ); + } + }; } \ No newline at end of file diff --git a/src/lifters/lconst.cpp b/src/lifters/lconst.cpp index 0856610..b4a5e1f 100644 --- a/src/lifters/lconst.cpp +++ b/src/lifters/lconst.cpp @@ -3,49 +3,49 @@ namespace vm { lifters_t::lifter_callback_t lifters_t::lconstq = - [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block, + [ & ]( vm::devirt_t *rtn, const vm::instrs::code_block_t &vm_code_block, const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) { rtn->push( 8, llvm::ConstantInt::get( ir_builder->getInt64Ty(), vinstr.operand.imm.u ) ); }; lifters_t::lifter_callback_t lifters_t::lconstdwsxq = - [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block, + [ & ]( vm::devirt_t *rtn, const vm::instrs::code_block_t &vm_code_block, const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) { rtn->push( 8, llvm::ConstantInt::get( ir_builder->getInt64Ty(), vinstr.operand.imm.u ) ); }; lifters_t::lifter_callback_t lifters_t::lconstwsxq = - [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block, + [ & ]( vm::devirt_t *rtn, const vm::instrs::code_block_t &vm_code_block, const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) { rtn->push( 8, llvm::ConstantInt::get( ir_builder->getInt64Ty(), vinstr.operand.imm.u ) ); }; lifters_t::lifter_callback_t lifters_t::lconstbsxq = - [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block, + [ & ]( vm::devirt_t *rtn, const vm::instrs::code_block_t &vm_code_block, const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) { rtn->push( 8, llvm::ConstantInt::get( ir_builder->getInt64Ty(), vinstr.operand.imm.u ) ); }; lifters_t::lifter_callback_t lifters_t::lconstdw = - [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block, + [ & ]( vm::devirt_t *rtn, const vm::instrs::code_block_t &vm_code_block, const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) { rtn->push( 4, llvm::ConstantInt::get( ir_builder->getInt32Ty(), vinstr.operand.imm.u ) ); }; lifters_t::lifter_callback_t lifters_t::lconstwsxdw = - [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block, + [ & ]( vm::devirt_t *rtn, const vm::instrs::code_block_t &vm_code_block, const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) { rtn->push( 4, llvm::ConstantInt::get( ir_builder->getInt32Ty(), vinstr.operand.imm.u ) ); }; lifters_t::lifter_callback_t lifters_t::lconstbsxdw = - [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block, + [ & ]( vm::devirt_t *rtn, const vm::instrs::code_block_t &vm_code_block, const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) { rtn->push( 4, llvm::ConstantInt::get( ir_builder->getInt32Ty(), vinstr.operand.imm.u ) ); }; lifters_t::lifter_callback_t lifters_t::lconstbzxw = - [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block, + [ & ]( vm::devirt_t *rtn, const vm::instrs::code_block_t &vm_code_block, const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) { rtn->push( 2, llvm::ConstantInt::get( ir_builder->getInt16Ty(), vinstr.operand.imm.u ) ); }; diff --git a/src/lifters/lflags.cpp b/src/lifters/lflags.cpp index 576ee8b..deb8bce 100644 --- a/src/lifters/lflags.cpp +++ b/src/lifters/lflags.cpp @@ -3,9 +3,10 @@ namespace vm { lifters_t::lifter_callback_t lifters_t::lflagsq = - [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block, - const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) { + [ & ]( vm::devirt_t *rtn, const vm::instrs::code_block_t &vm_code_block, const vm::instrs::virt_instr_t &vinstr, + llvm::IRBuilder<> *ir_builder ) { + auto &vmp_rtn = rtn->vmp_rtns.back(); auto flags = rtn->pop( 8 ); - ir_builder->CreateStore( flags, rtn->flags ); + ir_builder->CreateStore( flags, vmp_rtn->flags ); }; } \ No newline at end of file diff --git a/src/lifters/lreg.cpp b/src/lifters/lreg.cpp index aac1486..b8bbad3 100644 --- a/src/lifters/lreg.cpp +++ b/src/lifters/lreg.cpp @@ -3,16 +3,18 @@ namespace vm { lifters_t::lifter_callback_t lifters_t::lregq = - [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block, - const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) { - auto vreg = rtn->virtual_registers[ vinstr.operand.imm.u ? vinstr.operand.imm.u / 8 : 0 ]; + [ & ]( vm::devirt_t *rtn, const vm::instrs::code_block_t &vm_code_block, const vm::instrs::virt_instr_t &vinstr, + llvm::IRBuilder<> *ir_builder ) { + auto &vmp_rtn = rtn->vmp_rtns.back(); + auto vreg = vmp_rtn->virtual_registers[ vinstr.operand.imm.u ? vinstr.operand.imm.u / 8 : 0 ]; rtn->push( 8, rtn->load_value( 8, vreg ) ); }; lifters_t::lifter_callback_t lifters_t::lregdw = - [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block, - const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) { - auto vreg = rtn->virtual_registers[ vinstr.operand.imm.u ? vinstr.operand.imm.u / 8 : 0 ]; + [ & ]( vm::devirt_t *rtn, const vm::instrs::code_block_t &vm_code_block, const vm::instrs::virt_instr_t &vinstr, + llvm::IRBuilder<> *ir_builder ) { + auto &vmp_rtn = rtn->vmp_rtns.back(); + auto vreg = vmp_rtn->virtual_registers[ vinstr.operand.imm.u ? vinstr.operand.imm.u / 8 : 0 ]; rtn->push( 4, rtn->load_value( 4, vreg ) ); }; } // namespace vm \ No newline at end of file diff --git a/src/lifters/nand.cpp b/src/lifters/nand.cpp index fd602f2..8ec8fa0 100644 --- a/src/lifters/nand.cpp +++ b/src/lifters/nand.cpp @@ -2,7 +2,7 @@ namespace vm { - vm::llvm_value_t *lifters_t::and_flags( vm::vmp_rtn_t *rtn, std::uint8_t byte_size, vm::llvm_value_t *result ) + llvm::Value *lifters_t::and_flags( vm::devirt_t *rtn, std::uint8_t byte_size, llvm::Value *result ) { auto cf = llvm::ConstantInt::get( llvm::IntegerType::get( *rtn->llvm_ctx, 64 ), 0 ); auto of = llvm::ConstantInt::get( llvm::IntegerType::get( *rtn->llvm_ctx, 64 ), 0 ); @@ -16,7 +16,7 @@ namespace vm } lifters_t::lifter_callback_t lifters_t::nandq = - [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block, + [ & ]( vm::devirt_t *rtn, const vm::instrs::code_block_t &vm_code_block, const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) { auto t1 = rtn->pop( 8 ); auto t2 = rtn->pop( 8 ); @@ -27,13 +27,14 @@ namespace vm auto t3 = ir_builder->CreateAnd( { t1_not, t2_not } ); rtn->push( 8, t3 ); + auto &vmp_rtn = rtn->vmp_rtns.back(); auto flags = and_flags( rtn, 8, t3 ); - ir_builder->CreateStore( flags, rtn->flags ); - rtn->push( 8, rtn->load_value( 8, rtn->flags ) ); + ir_builder->CreateStore( flags, vmp_rtn->flags ); + rtn->push( 8, rtn->load_value( 8, vmp_rtn->flags ) ); }; lifters_t::lifter_callback_t lifters_t::nanddw = - [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block, + [ & ]( vm::devirt_t *rtn, const vm::instrs::code_block_t &vm_code_block, const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) { auto t1 = rtn->pop( 4 ); auto t2 = rtn->pop( 4 ); @@ -44,9 +45,10 @@ namespace vm auto t3 = ir_builder->CreateAnd( { t1_not, t2_not } ); rtn->push( 4, t3 ); + auto &vmp_rtn = rtn->vmp_rtns.back(); auto flags = and_flags( rtn, 4, t3 ); - ir_builder->CreateStore( flags, rtn->flags ); - rtn->push( 8, rtn->load_value( 8, rtn->flags ) ); + ir_builder->CreateStore( flags, vmp_rtn->flags ); + rtn->push( 8, rtn->load_value( 8, vmp_rtn->flags ) ); }; } // namespace vm \ No newline at end of file diff --git a/src/lifters/pushvsp.cpp b/src/lifters/pushvsp.cpp index 38c6f2f..0b91ba8 100644 --- a/src/lifters/pushvsp.cpp +++ b/src/lifters/pushvsp.cpp @@ -3,9 +3,10 @@ namespace vm { lifters_t::lifter_callback_t lifters_t::pushvsp = - [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block, - const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) { - auto stack = ir_builder->CreateLoad( rtn->stack ); + [ & ]( vm::devirt_t *rtn, const vm::instrs::code_block_t &vm_code_block, const vm::instrs::virt_instr_t &vinstr, + llvm::IRBuilder<> *ir_builder ) { + auto &vmp_rtn = rtn->vmp_rtns.back(); + auto stack = ir_builder->CreateLoad( vmp_rtn->stack ); auto stack_ptr = ir_builder->CreatePtrToInt( stack, ir_builder->getInt64Ty() ); rtn->push( 8, stack_ptr ); }; diff --git a/src/lifters/read.cpp b/src/lifters/read.cpp index 011fe81..b92f53d 100644 --- a/src/lifters/read.cpp +++ b/src/lifters/read.cpp @@ -3,7 +3,7 @@ namespace vm { lifters_t::lifter_callback_t lifters_t::readq = - [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block, + [ & ]( vm::devirt_t *rtn, const vm::instrs::code_block_t &vm_code_block, const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) { auto t1 = rtn->pop( 8 ); auto t2 = ir_builder->CreateIntToPtr( t1, llvm::PointerType::get( ir_builder->getInt64Ty(), 0ull ) ); @@ -12,7 +12,7 @@ namespace vm }; lifters_t::lifter_callback_t lifters_t::readdw = - [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block, + [ & ]( vm::devirt_t *rtn, const vm::instrs::code_block_t &vm_code_block, const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) { auto t1 = rtn->pop( 8 ); auto t2 = ir_builder->CreateIntToPtr( t1, llvm::PointerType::get( ir_builder->getInt32Ty(), 0ull ) ); diff --git a/src/lifters/shr.cpp b/src/lifters/shr.cpp index dc11e46..43e5b7a 100644 --- a/src/lifters/shr.cpp +++ b/src/lifters/shr.cpp @@ -3,8 +3,8 @@ namespace vm { // our undefined behavior is that we don't model cases where the shift count is zero... - vm::llvm_value_t *lifters_t::shr_flags( vm::vmp_rtn_t *rtn, std::uint8_t byte_size, vm::llvm_value_t *lhs, - vm::llvm_value_t *rhs, vm::llvm_value_t *result ) + llvm::Value *lifters_t::shr_flags( vm::devirt_t *rtn, std::uint8_t byte_size, llvm::Value *lhs, llvm::Value *rhs, + llvm::Value *result ) { auto op_size = llvm::IntegerType::get( *rtn->llvm_ctx, byte_size * 8 ); auto msb = rtn->ir_builder->CreateLShr( lhs, ( byte_size * 8 ) - 1 ); @@ -21,16 +21,17 @@ namespace vm } lifters_t::lifter_callback_t lifters_t::shrq = - [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block, + [ & ]( vm::devirt_t *rtn, const vm::instrs::code_block_t &vm_code_block, const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) { auto t1 = rtn->pop( 8 ); auto t2 = rtn->pop( 2 ); auto t3 = ir_builder->CreateIntCast( t2, llvm::IntegerType::get( *rtn->llvm_ctx, 64 ), false ); auto t4 = ir_builder->CreateLShr( t1, t3 ); + auto &vmp_rtn = rtn->vmp_rtns.back(); auto flags = lifters_t::shr_flags( rtn, 8, t1, t3, t4 ); - ir_builder->CreateStore( flags, rtn->flags ); + ir_builder->CreateStore( flags, vmp_rtn->flags ); rtn->push( 8, t4 ); - rtn->push( 8, rtn->load_value( 8, rtn->flags ) ); + rtn->push( 8, rtn->load_value( 8, vmp_rtn->flags ) ); }; } // namespace vm \ No newline at end of file diff --git a/src/lifters/sreg.cpp b/src/lifters/sreg.cpp index 6e2ae98..bb656a9 100644 --- a/src/lifters/sreg.cpp +++ b/src/lifters/sreg.cpp @@ -3,18 +3,20 @@ namespace vm { lifters_t::lifter_callback_t lifters_t::sregq = - [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block, - const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) { + [ & ]( vm::devirt_t *rtn, const vm::instrs::code_block_t &vm_code_block, const vm::instrs::virt_instr_t &vinstr, + llvm::IRBuilder<> *ir_builder ) { auto t1 = rtn->pop( 8 ); - auto vreg = rtn->virtual_registers[ vinstr.operand.imm.u ? vinstr.operand.imm.u / 8 : 0 ]; + auto &vmp_rtn = rtn->vmp_rtns.back(); + auto vreg = vmp_rtn->virtual_registers[ vinstr.operand.imm.u ? vinstr.operand.imm.u / 8 : 0 ]; ir_builder->CreateStore( t1, vreg ); }; lifters_t::lifter_callback_t lifters_t::sregdw = - [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block, - const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) { + [ & ]( vm::devirt_t *rtn, const vm::instrs::code_block_t &vm_code_block, const vm::instrs::virt_instr_t &vinstr, + llvm::IRBuilder<> *ir_builder ) { auto t1 = rtn->pop( 4 ); - auto vreg = rtn->virtual_registers[ vinstr.operand.imm.u ? vinstr.operand.imm.u / 8 : 0 ]; + auto &vmp_rtn = rtn->vmp_rtns.back(); + auto vreg = vmp_rtn->virtual_registers[ vinstr.operand.imm.u ? vinstr.operand.imm.u / 8 : 0 ]; auto vregdw = ir_builder->CreatePointerCast( vreg, llvm::PointerType::get( llvm::IntegerType::get( *rtn->llvm_ctx, 32 ), 0 ) ); ir_builder->CreateStore( t1, vregdw ); diff --git a/src/lifters/vmexit.cpp b/src/lifters/vmexit.cpp index ee1bb99..8bc011d 100644 --- a/src/lifters/vmexit.cpp +++ b/src/lifters/vmexit.cpp @@ -3,6 +3,9 @@ namespace vm { lifters_t::lifter_callback_t lifters_t::vmexit = - [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block, - const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) { ir_builder->CreateRetVoid(); }; + [ & ]( vm::devirt_t *rtn, const vm::instrs::code_block_t &vm_code_block, const vm::instrs::virt_instr_t &vinstr, + llvm::IRBuilder<> *ir_builder ) { + auto &vmp_rtn = rtn->vmp_rtns.back(); + ir_builder->CreateRet( ir_builder->CreateLoad( vmp_rtn->stack ) ); + }; } diff --git a/src/main.cpp b/src/main.cpp index 77043ad..0e866be 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,10 +1,59 @@ #include #include -#include -#include +#include #include -using namespace llvm; +/// +/// helper function to serialize vmp2 file data to vm::instr::code_block's... +/// +/// vector of pairs {vm enter offset, vector of code blocks} which gets filled up with +/// serialized data +/// a vector of bytes containing the vmp2 file... +/// returns true if serialization was successful +bool serialize_vmp2( std::vector< std::pair< std::uint32_t, std::vector< vm::instrs::code_block_t > > > &virt_rtns, + std::vector< std::uint8_t > &vmp2file ) +{ + const auto file_header = reinterpret_cast< vmp2::v4::file_header * >( vmp2file.data() ); + + if ( file_header->version != vmp2::version_t::v4 ) + { + std::printf( "[!] invalid vmp2 file version... this build uses v3...\n" ); + return false; + } + + auto first_rtn = reinterpret_cast< vmp2::v4::rtn_t * >( reinterpret_cast< std::uintptr_t >( file_header ) + + file_header->rtn_offset ); + + for ( auto [ rtn_block, rtn_idx ] = std::pair{ first_rtn, 0ull }; rtn_idx < file_header->rtn_count; + ++rtn_idx, rtn_block = reinterpret_cast< vmp2::v4::rtn_t * >( + reinterpret_cast< std::uintptr_t >( rtn_block ) + rtn_block->size ) ) + { + virt_rtns.push_back( { rtn_block->vm_enter_offset, {} } ); + for ( auto [ code_block, block_idx ] = std::pair{ &rtn_block->code_blocks[ 0 ], 0ull }; + block_idx < rtn_block->code_block_count; + ++block_idx, code_block = reinterpret_cast< vmp2::v4::code_block_t * >( + reinterpret_cast< std::uintptr_t >( code_block ) + code_block->next_block_offset ) ) + { + auto block_vinstrs = reinterpret_cast< vm::instrs::virt_instr_t * >( + reinterpret_cast< std::uintptr_t >( code_block ) + sizeof vmp2::v4::code_block_t + + ( code_block->num_block_addrs * 8 ) ); + + vm::instrs::code_block_t _code_block{ code_block->vip_begin }; + _code_block.jcc.has_jcc = code_block->has_jcc; + _code_block.jcc.type = code_block->jcc_type; + + for ( auto idx = 0u; idx < code_block->num_block_addrs; ++idx ) + _code_block.jcc.block_addr.push_back( code_block->branch_addr[ idx ] ); + + for ( auto idx = 0u; idx < code_block->vinstr_count; ++idx ) + _code_block.vinstrs.push_back( block_vinstrs[ idx ] ); + + virt_rtns.back().second.push_back( _code_block ); + } + } + + return true; +} int main( int argc, const char *argv[] ) { @@ -35,47 +84,31 @@ int main( int argc, const char *argv[] ) return -1; } - const auto file_header = reinterpret_cast< vmp2::v3::file_header * >( vmp2file.data() ); + const auto file_header = reinterpret_cast< vmp2::v4::file_header * >( vmp2file.data() ); + std::vector< std::pair< std::uint32_t, std::vector< vm::instrs::code_block_t > > > virt_rtns; - if ( file_header->version != vmp2::version_t::v3 ) + if ( !serialize_vmp2( virt_rtns, vmp2file ) ) { - std::printf( "[!] invalid vmp2 file version... this build uses v3...\n" ); - return -1; - } - - auto first_block = reinterpret_cast< vmp2::v3::code_block_t * >( reinterpret_cast< std::uintptr_t >( file_header ) + - file_header->code_block_offset ); - - std::vector< vm::instrs::code_block_t > vmp_code_blocks; - // convert code blocks back to vm::instrs::code_block_t form... - for ( auto [ code_block, code_block_num ] = std::tuple{ first_block, 0u }; - code_block_num < file_header->code_block_count; - code_block = reinterpret_cast< vmp2::v3::code_block_t * >( reinterpret_cast< std::uintptr_t >( code_block ) + - code_block->next_block_offset ), - ++code_block_num ) - { - vm::instrs::code_block_t _code_block{ code_block->vip_begin, code_block->jcc }; - std::for_each( code_block->vinstr, code_block->vinstr + code_block->vinstr_count, - [ & ]( const vm::instrs::virt_instr_t &vinstr ) { _code_block.vinstrs.push_back( vinstr ); } ); - - vmp_code_blocks.push_back( _code_block ); + std::printf( "> failed to serialize vmp2 file...\n" ); + return false; } - LLVMContext llvm_ctx; - Module llvm_module( "", llvm_ctx ); + llvm::LLVMContext llvm_ctx; + llvm::Module llvm_module( "VMProtect 2 Devirtualization", llvm_ctx ); - vm::ctx_t vm_ctx( reinterpret_cast< std::uintptr_t >( file_header ) + file_header->module_offset, - file_header->image_base, file_header->module_size, file_header->vm_entry_rva ); + std::vector< std::uint8_t > compiled_obj; + vm::devirt_t vmp_rtn( &llvm_ctx, &llvm_module ); - if ( !vm_ctx.init() ) + for ( auto &[ vm_enter_offset, vmp2_code_blocks ] : virt_rtns ) { - std::printf( "> failed to init vm::ctx_t... this can be for many reason... make sure you are using the correct " - "vmemu version for this project...\n" ); - - return false; + if ( !vmp_rtn.lift( vm_enter_offset + file_header->image_base, vmp2_code_blocks ) ) + { + std::printf( "[!] failed to lift rtn_0x%p, please review the console...\n", + vm_enter_offset + file_header->image_base ); + return -1; + } } - vm::vmp_rtn_t vmp_rtn( &llvm_ctx, &llvm_module, &vm_ctx, first_block->vip_begin, vmp_code_blocks ); - auto func = vmp_rtn.lift(); - func->print( llvm::outs(), nullptr ); + vmp_rtn.compile( compiled_obj ); + std::printf( "> compiled obj size = %d\n", compiled_obj.size() ); } \ No newline at end of file diff --git a/src/vmp_rtn.cpp b/src/vmp_rtn.cpp deleted file mode 100644 index a14f127..0000000 --- a/src/vmp_rtn.cpp +++ /dev/null @@ -1,177 +0,0 @@ -#include -#include - -namespace vm -{ - vmp_rtn_t::vmp_rtn_t( llvm_context_t *llvm_ctx, llvm_module_t *llvm_module, vm::ctx_t *vm_ctx, - std::uintptr_t rtn_begin, std::vector< vm::instrs::code_block_t > vmp2_code_blocks ) - : llvm_ctx( llvm_ctx ), llvm_module( llvm_module ), vm_ctx( vm_ctx ), rtn_begin( rtn_begin ), - vmp2_code_blocks( vmp2_code_blocks ) - { - // do not change the ordering of these function calls... - create_routine(); - ir_builder = std::make_shared< llvm_irbuilder_t >( *llvm_ctx ); - ir_builder->SetInsertPoint( llvm_code_blocks[ 0 ].second ); - flags = ir_builder->CreateAlloca( ir_builder->getInt64Ty(), nullptr, "flags" ); - stack = ir_builder->CreateAlloca( llvm::PointerType::get( ir_builder->getInt8Ty(), 0ull ), nullptr, "sp" ); - - ir_builder->CreateStore( llvm_fptr->getArg( 0 ), stack ); - create_virtual_registers(); - } - - void vmp_rtn_t::create_virtual_registers( void ) - { - for ( auto idx = 0u; idx < 24; ++idx ) - // allocate virtual register space... - virtual_registers.push_back( - ir_builder->CreateAlloca( llvm::IntegerType::get( *llvm_ctx, 64 ), nullptr, - ( std::string( "vreg" ) + std::to_string( idx ) ).c_str() ) ); - } - - void vmp_rtn_t::create_routine( void ) - { - // function has no arguments and returns void... maybe change this in the future as i learn - // more and more LLVM... - auto func_ty = llvm::FunctionType::get( llvm::Type::getVoidTy( *llvm_ctx ), - { llvm::PointerType::getInt8PtrTy( *llvm_ctx ) }, false ); - - // convert the rtn_begin address to a hex string and prepend "rtn_" to it... - std::stringstream rtn_name; - rtn_name << "rtn_" << std::hex << rtn_begin; - llvm_fptr = llvm::Function::Create( func_ty, llvm::GlobalValue::LinkageTypes::ExternalLinkage, - rtn_name.str().c_str(), *llvm_module ); - - for ( const auto &vmp2_code_block : vmp2_code_blocks ) - { - // create basic block name... block_xxxxxxxx format... - std::stringstream blk_name; - blk_name << "blk_" << std::hex << vmp2_code_block.vip_begin; - llvm_code_blocks.push_back( { vmp2_code_block.vip_begin, - llvm::BasicBlock::Create( *llvm_ctx, blk_name.str().c_str(), llvm_fptr ) } ); - } - } - - void vmp_rtn_t::push( std::uint8_t num_bytes, llvm_value_t *val ) - { - // sub rsp, num_bytes - auto rsp_addr = ir_builder->CreateLoad( stack ); - auto rsp_i64 = ir_builder->CreatePtrToInt( rsp_addr, ir_builder->getInt64Ty() ); - auto sub_rsp_val = ir_builder->CreateSub( rsp_i64, ir_builder->getInt64( num_bytes ) ); - ir_builder->CreateStore( - ir_builder->CreateIntToPtr( sub_rsp_val, llvm::PointerType::get( ir_builder->getInt8Ty(), 0ull ) ), stack ); - - // mov [rsp], val - rsp_addr = ir_builder->CreateLoad( stack ); - auto rsp_cast_ptr = ir_builder->CreatePointerCast( - rsp_addr, llvm::PointerType::get( llvm::IntegerType::get( *llvm_ctx, num_bytes * 8 ), false ) ); - ir_builder->CreateStore( val, rsp_cast_ptr ); - } - - llvm_value_t *vmp_rtn_t::pop( std::uint8_t num_bytes ) - { - // mov rax, [rsp] - auto rsp_addr = ir_builder->CreateLoad( stack ); - auto rsp_cast_ptr = ir_builder->CreatePointerCast( - rsp_addr, llvm::PointerType::get( llvm::IntegerType::get( *llvm_ctx, num_bytes * 8 ), false ) ); - auto pop_val = ir_builder->CreateLoad( rsp_cast_ptr ); - - // add rsp, num_bytes - auto rsp_i64 = ir_builder->CreatePtrToInt( rsp_addr, ir_builder->getInt64Ty() ); - auto sub_rsp_val = ir_builder->CreateAdd( rsp_i64, ir_builder->getInt64( num_bytes ) ); - auto sub_rsp_val_ptr = - ir_builder->CreateIntToPtr( sub_rsp_val, llvm::PointerType::get( ir_builder->getInt8Ty(), 0ull ) ); - - ir_builder->CreateStore( sub_rsp_val_ptr, stack ); - return pop_val; - } - - llvm_value_t *vmp_rtn_t::load_value( std::uint8_t byte_size, llvm_global_value_t *var ) - { - if ( byte_size * 8 != var->getType()->getPrimitiveSizeInBits() ) - { - auto cast_ptr = ir_builder->CreatePointerCast( - var, llvm::PointerType::get( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), 0 ) ); - - return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), cast_ptr ); - } - return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), var ); - } - - llvm_value_t *vmp_rtn_t::load_value( std::uint8_t byte_size, llvm_alloca_inst_t *var ) - { - if ( byte_size * 8 != var->getType()->getPrimitiveSizeInBits() ) - { - auto cast_ptr = ir_builder->CreatePointerCast( - var, llvm::PointerType::get( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), 0 ) ); - - return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), cast_ptr ); - } - return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), var ); - } - - llvm_function_t *vmp_rtn_t::lift( void ) - { - auto &code_blocks = llvm_fptr->getBasicBlockList(); - auto lifters = vm::lifters_t::get_instance(); - - for ( auto idx = 0u; idx < code_blocks.size(); ++idx ) - { - ir_builder->SetInsertPoint( llvm_code_blocks[ idx ].second ); - for ( auto &vinstr : vmp2_code_blocks[ idx ].vinstrs ) - { - if ( !lifters->lift( this, vmp2_code_blocks[ idx ], vinstr, ir_builder.get() ) ) - { - std::printf( "> failed to devirtualize virtual instruction with opcode = %d\n", vinstr.opcode ); - llvm_module->print( llvm::outs(), nullptr ); - return nullptr; - } - } - } - - return llvm_fptr; - } - - llvm_value_t *vmp_rtn_t::compute_sf( std::uint8_t byte_size, llvm_value_t *val ) - { - auto op_size = llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ); - auto msb = ir_builder->CreateLShr( val, ( byte_size * 8 ) - 1 ); - return ir_builder->CreateZExt( msb, llvm::IntegerType::get( *llvm_ctx, 64 ) ); - } - - llvm_value_t *vmp_rtn_t::compute_zf( std::uint8_t byte_size, llvm_value_t *val ) - { - auto op_size = llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ); - auto is_zero = ir_builder->CreateICmpEQ( val, llvm::ConstantInt::get( op_size, 0 ) ); - return ir_builder->CreateZExt( is_zero, llvm::IntegerType::get( *llvm_ctx, 64 ) ); - } - - llvm_value_t *vmp_rtn_t::compute_pf( std::uint8_t byte_size, llvm_value_t *val ) - { - auto operand_size = llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ); - auto popcount_intrinsic = llvm::Intrinsic::getDeclaration( llvm_module, llvm::Intrinsic::ctpop, - { llvm::IntegerType::get( *llvm_ctx, 64 ) } ); - - auto lower_bits = ir_builder->CreateIntCast( val, llvm::IntegerType::get( *llvm_ctx, 8 ), false ); - auto extended_bits = ir_builder->CreateZExt( lower_bits, llvm::IntegerType::get( *llvm_ctx, 64 ) ); - return ir_builder->CreateCall( popcount_intrinsic, { extended_bits } ); - } - - llvm_value_t *vmp_rtn_t::combine_flags( llvm_value_t *cf, llvm_value_t *pf, llvm_value_t *af, llvm_value_t *zf, - llvm_value_t *sf, llvm_value_t *of ) - { - auto shifted_pf = ir_builder->CreateShl( pf, 2, "shifted_pf", true, true ); - auto shifted_af = ir_builder->CreateShl( llvm::ConstantInt::get( llvm::IntegerType::get( *llvm_ctx, 64 ), 0 ), - 4, "shifted_af", true, true ); // treat af as zero - - auto shifted_zf = ir_builder->CreateShl( zf, 6, "shifted_zf", true, true ); - auto shifted_sf = ir_builder->CreateShl( sf, 7, "shifted_sf", true, true ); - auto shifted_of = ir_builder->CreateShl( of, 11, "shifted_of", true, true ); - auto or1 = ir_builder->CreateOr( cf, shifted_of ); - auto or2 = ir_builder->CreateOr( or1, shifted_zf ); - auto or3 = ir_builder->CreateOr( or2, shifted_sf ); - auto or4 = ir_builder->CreateOr( or3, shifted_af ); - auto or5 = ir_builder->CreateOr( or4, shifted_pf ); - return ir_builder->CreateXor( or5, llvm::ConstantInt::get( llvm::IntegerType::get( *llvm_ctx, 64 ), 514 ) ); - } - -} // namespace vm \ No newline at end of file diff --git a/src/vmp_rtn_t.cpp b/src/vmp_rtn_t.cpp new file mode 100644 index 0000000..35c2180 --- /dev/null +++ b/src/vmp_rtn_t.cpp @@ -0,0 +1,52 @@ +#include + +namespace vm +{ + vmp_rtn_t::vmp_rtn_t( std::uintptr_t rtn_begin, std::vector< vm::instrs::code_block_t > vmp2_code_blocks, + std::shared_ptr< llvm::IRBuilder<> > &ir_builder, llvm::Module *llvm_module ) + : ir_builder( ir_builder ), vmp2_code_blocks( vmp2_code_blocks ), rtn_begin( rtn_begin ), + llvm_module( llvm_module ) + { + create_routine(); + // create virtual registers in the first code block... + ir_builder->SetInsertPoint( llvm_code_blocks[ 0 ].second ); + flags = ir_builder->CreateAlloca( ir_builder->getInt64Ty(), nullptr, "flags" ); + stack = ir_builder->CreateAlloca( llvm::PointerType::get( ir_builder->getInt8Ty(), 0ull ), nullptr, "sp" ); + ir_builder->CreateStore( llvm_fptr->getArg( 0 ), stack ); + create_virtual_registers(); + } + + void vmp_rtn_t::create_virtual_registers( void ) + { + for ( auto idx = 0u; idx < 24; ++idx ) + // allocate virtual register space... + virtual_registers.push_back( + ir_builder->CreateAlloca( llvm::IntegerType::get( ir_builder->getContext(), 64 ), nullptr, + ( std::string( "vreg" ) + std::to_string( idx ) ).c_str() ) ); + } + + void vmp_rtn_t::create_routine( void ) + { + // function has no arguments and returns void... maybe change this in the future as i learn + // more and more LLVM... + auto func_ty = + llvm::FunctionType::get( llvm::PointerType::getInt8PtrTy( ir_builder->getContext() ), + { llvm::PointerType::getInt8PtrTy( ir_builder->getContext() ) }, false ); + + // convert the rtn_begin address to a hex string and prepend "rtn_" to it... + std::stringstream rtn_name; + rtn_name << "rtn_" << std::hex << rtn_begin; + llvm_fptr = llvm::Function::Create( func_ty, llvm::GlobalValue::LinkageTypes::ExternalLinkage, + rtn_name.str().c_str(), *llvm_module ); + + for ( const auto &vmp2_code_block : vmp2_code_blocks ) + { + // create basic block name... block_xxxxxxxx format... + std::stringstream blk_name; + blk_name << "blk_" << std::hex << vmp2_code_block.vip_begin; + llvm_code_blocks.push_back( + { vmp2_code_block.vip_begin, + llvm::BasicBlock::Create( ir_builder->getContext(), blk_name.str().c_str(), llvm_fptr ) } ); + } + } +} // namespace vm \ No newline at end of file