diff --git a/CMakeLists.txt b/CMakeLists.txt index d5561ed..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 diff --git a/include/vmp_rtn.hpp b/include/devirt_t.hpp similarity index 74% rename from include/vmp_rtn.hpp rename to include/devirt_t.hpp index 97a2ee4..63bce8f 100644 --- a/include/vmp_rtn.hpp +++ b/include/devirt_t.hpp @@ -1,5 +1,5 @@ #pragma once -#include +#include #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constants.h" @@ -41,30 +41,22 @@ namespace llvm namespace vm { - class vmp_rtn_t + class devirt_t { friend class lifters_t; public: - explicit vmp_rtn_t( llvm::LLVMContext *llvm_ctx, llvm::Module *llvm_module, vm::ctx_t *vm_ctx, - std::uintptr_t rtn_begin, std::vector< vm::instrs::code_block_t > vmp2_code_blocks ); - - llvm::Function *lift( void ); + 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; - llvm::Function *llvm_fptr; - llvm::AllocaInst *flags, *stack; - - vm::ctx_t *vm_ctx; - std::uintptr_t rtn_begin; std::shared_ptr< llvm::IRBuilder<> > ir_builder; + std::vector< std::shared_ptr< vm::vmp_rtn_t > > vmp_rtns; - 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_routine( void ); void push( std::uint8_t byte_size, llvm::Value *input_val ); llvm::Value *pop( std::uint8_t byte_size ); @@ -76,8 +68,5 @@ namespace vm 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 ); - - void create_virtual_registers( void ); - void create_routine( void ); }; } // namespace vm \ No newline at end of file diff --git a/include/vm_lifters.hpp b/include/vm_lifters.hpp index 950e519..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,9 +68,9 @@ namespace vm { vm::handler::JMP, &jmp }, { vm::handler::VMEXIT, &vmexit } }; - static llvm::Value *and_flags( vm::vmp_rtn_t *rtn, std::uint8_t byte_size, llvm::Value *result ); - static llvm::Value *add_flags( vm::vmp_rtn_t *rtn, std::uint8_t byte_size, llvm::Value *lhs, llvm::Value *rhs ); - static llvm::Value *shr_flags( vm::vmp_rtn_t *rtn, std::uint8_t byte_size, llvm::Value *lhs, llvm::Value *rhs, + 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: @@ -82,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_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 4c25648..1f298f0 100644 --- a/src/lifters/add.cpp +++ b/src/lifters/add.cpp @@ -2,7 +2,7 @@ namespace vm { - llvm::Value *lifters_t::add_flags( vm::vmp_rtn_t *rtn, std::uint8_t byte_size, llvm::Value *lhs, llvm::Value *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; @@ -36,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 5ccfe32..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::BasicBlock * > &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::BasicBlock * > &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::BasicBlock * > &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 d4af883..8ec8fa0 100644 --- a/src/lifters/nand.cpp +++ b/src/lifters/nand.cpp @@ -2,7 +2,7 @@ namespace vm { - llvm::Value *lifters_t::and_flags( vm::vmp_rtn_t *rtn, std::uint8_t byte_size, llvm::Value *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 4ffae00..43e5b7a 100644 --- a/src/lifters/shr.cpp +++ b/src/lifters/shr.cpp @@ -3,7 +3,7 @@ namespace vm { // our undefined behavior is that we don't model cases where the shift count is zero... - llvm::Value *lifters_t::shr_flags( vm::vmp_rtn_t *rtn, std::uint8_t byte_size, llvm::Value *lhs, llvm::Value *rhs, + 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 ); @@ -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 f7265e5..8bc011d 100644 --- a/src/lifters/vmexit.cpp +++ b/src/lifters/vmexit.cpp @@ -3,7 +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->CreateRet( 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(); + ir_builder->CreateRet( ir_builder->CreateLoad( vmp_rtn->stack ) ); + }; } diff --git a/src/main.cpp b/src/main.cpp index b3e2716..0e866be 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,52 +1,29 @@ #include #include -#include -#include +#include #include -using namespace llvm; - -int main( int argc, const char *argv[] ) +/// +/// 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 ) { - argparse::argument_parser_t parser( "vmdevirt", "virtual instruction pseudo code generator" ); - parser.add_argument().name( "--vmp2file" ).required( true ).description( "path to .vmp2 file..." ); - - parser.enable_help(); - auto err = parser.parse( argc, argv ); - - if ( err ) - { - std::cout << err << std::endl; - return -1; - } - - if ( parser.exists( "help" ) ) - { - parser.print_help(); - return 0; - } - - std::vector< std::uint8_t > vmp2file; - const auto umtils = xtils::um_t::get_instance(); - - if ( !umtils->open_binary_file( parser.get< std::string >( "vmp2file" ), vmp2file ) ) - { - std::printf( "[!] failed to open vmp2 file...\n" ); - return -1; - } - 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 -1; + return false; } auto first_rtn = reinterpret_cast< vmp2::v4::rtn_t * >( reinterpret_cast< std::uintptr_t >( file_header ) + file_header->rtn_offset ); - std::vector< std::pair< std::uint32_t, std::vector< vm::instrs::code_block_t > > > virt_rtns; 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 ) ) @@ -66,10 +43,7 @@ int main( int argc, const char *argv[] ) _code_block.jcc.type = code_block->jcc_type; for ( auto idx = 0u; idx < code_block->num_block_addrs; ++idx ) - { - std::printf( "> branch addr = 0x%p\n", code_block->branch_addr[ 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 ] ); @@ -78,48 +52,63 @@ int main( int argc, const char *argv[] ) } } - LLVMContext llvm_ctx; - Module llvm_module( "", llvm_ctx ); + return true; +} - 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 ); +int main( int argc, const char *argv[] ) +{ + argparse::argument_parser_t parser( "vmdevirt", "virtual instruction pseudo code generator" ); + parser.add_argument().name( "--vmp2file" ).required( true ).description( "path to .vmp2 file..." ); - if ( !vm_ctx.init() ) + parser.enable_help(); + auto err = parser.parse( argc, argv ); + + if ( err ) { - 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" ); + std::cout << err << std::endl; + return -1; + } - return false; + if ( parser.exists( "help" ) ) + { + parser.print_help(); + return 0; } - vm::vmp_rtn_t vmp_rtn( &llvm_ctx, &llvm_module, &vm_ctx, virt_rtns[ 0 ].second[ 0 ].vip_begin, - virt_rtns[ 0 ].second ); + std::vector< std::uint8_t > vmp2file; + const auto umtils = xtils::um_t::get_instance(); - auto func = vmp_rtn.lift(); - llvm_module.print( llvm::outs(), nullptr ); + if ( !umtils->open_binary_file( parser.get< std::string >( "vmp2file" ), vmp2file ) ) + { + std::printf( "[!] failed to open vmp2 file...\n" ); + return -1; + } - llvm::LLVMInitializeX86TargetInfo(); - llvm::LLVMInitializeX86Target(); - llvm::LLVMInitializeX86TargetMC(); - llvm::LLVMInitializeX86AsmParser(); - llvm::LLVMInitializeX86AsmPrinter(); + 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; - TargetOptions opt; - llvm::SmallVector< char, 128 > buff; - llvm::raw_svector_ostream dest( buff ); - legacy::PassManager pass; + if ( !serialize_vmp2( virt_rtns, vmp2file ) ) + { + std::printf( "> failed to serialize vmp2 file...\n" ); + return false; + } - auto target_triple = sys::getDefaultTargetTriple(); - llvm_module.setTargetTriple( target_triple ); + llvm::LLVMContext llvm_ctx; + llvm::Module llvm_module( "VMProtect 2 Devirtualization", llvm_ctx ); - std::string error; - auto Target = TargetRegistry::lookupTarget( target_triple, error ); + std::vector< std::uint8_t > compiled_obj; + vm::devirt_t vmp_rtn( &llvm_ctx, &llvm_module ); - auto reloc_model = Optional< Reloc::Model >(); - auto target_machine = Target->createTargetMachine( target_triple, "generic", "", opt, reloc_model ); - llvm_module.setDataLayout( target_machine->createDataLayout() ); - target_machine->addPassesToEmitFile( pass, dest, nullptr, CGFT_ObjectFile ); - pass.run( llvm_module ); + for ( auto &[ vm_enter_offset, vmp2_code_blocks ] : virt_rtns ) + { + 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; + } + } - std::printf( "> obj size = %d\n", buff.size() ); + 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 92d6a50..0000000 --- a/src/vmp_rtn.cpp +++ /dev/null @@ -1,182 +0,0 @@ -#include -#include - -namespace vm -{ - vmp_rtn_t::vmp_rtn_t( llvm::LLVMContext *llvm_ctx, llvm::Module *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<> >( *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::PointerType::getInt8PtrTy( *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 *val ) - { - // sub rsp, num_bytes - auto rsp_addr = ir_builder->CreateLoad( stack, "rsp_addr" ); - auto sub_rsp_val = ir_builder->CreateGEP( ir_builder->getInt8Ty(), rsp_addr, - ir_builder->getInt8( 0 - num_bytes ), "sub_rsp_val" ); - ir_builder->CreateStore( sub_rsp_val, 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 *vmp_rtn_t::pop( std::uint8_t num_bytes ) - { - // mov rax, [rsp] - auto rsp_addr = ir_builder->CreateLoad( stack, "rsp_addr" ); - auto new_rsp_addr = ir_builder->CreateGEP( ir_builder->getInt8Ty(), rsp_addr, ir_builder->getInt8( num_bytes ), - "new_rsp_addr" ); - 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, stack ); - ir_builder->CreateStore( llvm::UndefValue::get( ir_builder->getInt8Ty() ), rsp_addr ); - return pop_val; - } - - llvm::Value *vmp_rtn_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 *vmp_rtn_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 ); - } - - llvm::Function *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, handler table rva = 0x%x\n", - vinstr.opcode, vinstr.trace_data.regs.r12 - vinstr.trace_data.regs.r13 ); - - return nullptr; - } - } - } - - // TODO: update this list of optimizations to add more... - llvm::legacy::FunctionPassManager fpm( llvm_module ); - fpm.add( llvm::createInstructionCombiningPass() ); - fpm.add( llvm::createReassociatePass() ); - fpm.add( llvm::createGVNPass() ); - fpm.add( llvm::createCFGSimplificationPass() ); - fpm.doInitialization(); - fpm.run( *llvm_fptr ); - return llvm_fptr; - } - - llvm::Value *vmp_rtn_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 *vmp_rtn_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 *vmp_rtn_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 *vmp_rtn_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/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