diff --git a/CMakeLists.txt b/CMakeLists.txt index f0c3847..59069e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,6 +54,7 @@ list(APPEND vmdevirt_SOURCES "src/lifters/shl.cpp" "src/lifters/shr.cpp" "src/lifters/sreg.cpp" + "src/lifters/vmexit.cpp" "src/main.cpp" "src/vmp_rtn.cpp" "include/vm_lifters.hpp" diff --git a/include/vm_lifters.hpp b/include/vm_lifters.hpp index 99361c8..3bc7f01 100644 --- a/include/vm_lifters.hpp +++ b/include/vm_lifters.hpp @@ -41,6 +41,7 @@ namespace vm static lifter_callback_t shrq; static lifter_callback_t jmp; static lifter_callback_t lflagsq; + static lifter_callback_t vmexit; std::map< vm::handler::mnemonic_t, lifter_callback_t * > lifters = { { vm::handler::LCONSTQ, &lconstq }, { vm::handler::LCONSTDW, &lconstdw }, @@ -63,7 +64,8 @@ namespace vm { vm::handler::NANDQ, &nandq }, { vm::handler::NANDDW, &nanddw }, { vm::handler::LFLAGSQ, &lflagsq }, - { vm::handler::JMP, &jmp } }; + { 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, diff --git a/include/vmp_rtn.hpp b/include/vmp_rtn.hpp index c309fc6..abd4328 100644 --- a/include/vmp_rtn.hpp +++ b/include/vmp_rtn.hpp @@ -43,7 +43,7 @@ namespace vm llvm_context_t *llvm_ctx; llvm_module_t *llvm_module; llvm_function_t *llvm_fptr; - llvm_alloca_inst_t *flags, *stack; + llvm_alloca_inst_t *virtual_stack, *stack_ptr, *flags; vm::ctx_t *vm_ctx; std::uintptr_t rtn_begin; @@ -65,6 +65,7 @@ namespace vm 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_stack( void ); void create_virtual_registers( void ); void create_routine( void ); }; diff --git a/src/lifters/pushvsp.cpp b/src/lifters/pushvsp.cpp index 1f459fc..c1b29d2 100644 --- a/src/lifters/pushvsp.cpp +++ b/src/lifters/pushvsp.cpp @@ -5,8 +5,16 @@ 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 sp = rtn->pop( 8 ); - auto sp_ptr = ir_builder->CreateIntToPtr( sp, llvm::PointerType::get( ir_builder->getInt8Ty(), 0ull ) ); - ir_builder->CreateStore( sp_ptr, rtn->stack ); + auto current_spi = + ir_builder->CreateLoad( llvm::IntegerType::get( *rtn->llvm_ctx, 64 ), rtn->stack_ptr, false ); + + auto *i64_zero = llvm::ConstantInt::get( *rtn->llvm_ctx, llvm::APInt( 64, 0 ) ); + llvm_value_t *indices[ 2 ] = { i64_zero, current_spi }; + auto stack_ptr = + ir_builder->CreateInBoundsGEP( rtn->virtual_stack, llvm::ArrayRef< llvm::Value * >( indices, 2 ) ); + + auto stack_ptr_val = ir_builder->CreatePtrToInt( stack_ptr, ir_builder->getInt64Ty() ); + rtn->push( 8, stack_ptr_val ); + }; } \ No newline at end of file diff --git a/src/lifters/sreg.cpp b/src/lifters/sreg.cpp index 6e2ae98..b2d3abf 100644 --- a/src/lifters/sreg.cpp +++ b/src/lifters/sreg.cpp @@ -7,7 +7,7 @@ namespace vm 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 ]; - ir_builder->CreateStore( t1, vreg ); + ir_builder->CreateStore( t1, vreg )->setAlignment( llvm::Align( 1 ) ); }; lifters_t::lifter_callback_t lifters_t::sregdw = @@ -17,6 +17,6 @@ namespace vm auto vreg = 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 ); + ir_builder->CreateStore( t1, vregdw )->setAlignment( llvm::Align( 1 ) ); }; } // namespace vm \ No newline at end of file diff --git a/src/vmp_rtn.cpp b/src/vmp_rtn.cpp index a14f127..0277be6 100644 --- a/src/vmp_rtn.cpp +++ b/src/vmp_rtn.cpp @@ -13,9 +13,10 @@ namespace vm 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_stack(); + // TODO: copy arg1 (array) onto the local stack... + // ir_builder->CreateMemCpy(... create_virtual_registers(); } @@ -32,8 +33,9 @@ namespace vm { // 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 ); + auto func_ty = + llvm::FunctionType::get( llvm::Type::getVoidTy( *llvm_ctx ), + { llvm::ArrayType::get( llvm::IntegerType::get( *llvm_ctx, 64 ), 21 ) }, false ); // convert the rtn_begin address to a hex string and prepend "rtn_" to it... std::stringstream rtn_name; @@ -41,6 +43,7 @@ namespace vm llvm_fptr = llvm::Function::Create( func_ty, llvm::GlobalValue::LinkageTypes::ExternalLinkage, rtn_name.str().c_str(), *llvm_module ); + llvm_fptr->setCallingConv( llvm::CallingConv::X86_FastCall ); for ( const auto &vmp2_code_block : vmp2_code_blocks ) { // create basic block name... block_xxxxxxxx format... @@ -53,36 +56,53 @@ namespace vm 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 ); + auto spi = ir_builder->CreateLoad( ir_builder->getInt64Ty(), stack_ptr, false ); + spi->setAlignment( llvm::Align( 1 ) ); + + auto new_spi = ir_builder->CreateSub( spi, llvm::ConstantInt::get( ir_builder->getInt64Ty(), num_bytes ) ); + ir_builder->CreateStore( new_spi, stack_ptr )->setAlignment( llvm::Align( 1 ) ); + + auto *i64_zero = llvm::ConstantInt::get( *llvm_ctx, llvm::APInt( 64, 0 ) ); + llvm_value_t *indices[ 2 ] = { i64_zero, new_spi }; + auto stack_ptr = ir_builder->CreateInBoundsGEP( virtual_stack, llvm::ArrayRef< llvm_value_t * >( indices, 2 ) ); + + if ( num_bytes > 1 ) + { + auto casted_ptr = ir_builder->CreatePointerCast( + stack_ptr, llvm::PointerType::get( llvm::IntegerType::get( *llvm_ctx, num_bytes * 8 ), 0 ) ); + + ir_builder->CreateStore( val, casted_ptr )->setAlignment( llvm::Align( 1 ) ); + } + else + ir_builder->CreateStore( val, stack_ptr )->setAlignment( llvm::Align( 1 ) ); } 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 *output_value = nullptr; + auto current_spi = ir_builder->CreateLoad( ir_builder->getInt64Ty(), stack_ptr, false ); + current_spi->setAlignment( llvm::Align( 1 ) ); + + llvm_value_t *i64_zero = llvm::ConstantInt::get( *llvm_ctx, llvm::APInt( 64, 0 ) ); + llvm_value_t *indices[ 2 ] = { i64_zero, current_spi }; + auto top_stack = ir_builder->CreateInBoundsGEP( virtual_stack, llvm::ArrayRef< llvm::Value * >( indices, 2 ) ); + + if ( num_bytes > 1 ) + { + auto casted_ptr = ir_builder->CreatePointerCast( + top_stack, llvm::PointerType::get( llvm::IntegerType::get( *llvm_ctx, num_bytes * 8 ), 0 ) ); + + output_value = ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, num_bytes * 8 ), casted_ptr ); + } + else + output_value = ir_builder->CreateLoad( ir_builder->getInt8Ty(), top_stack ); + + static_cast< llvm::LoadInst * >( output_value )->setAlignment( llvm::Align( 1 ) ); + auto new_spi = ir_builder->CreateAdd( + current_spi, llvm::ConstantInt::get( llvm::IntegerType::get( *llvm_ctx, 64 ), num_bytes ) ); + + ir_builder->CreateStore( new_spi, stack_ptr )->setAlignment( llvm::Align( 1 ) ); + return output_value; } llvm_value_t *vmp_rtn_t::load_value( std::uint8_t byte_size, llvm_global_value_t *var ) @@ -92,9 +112,13 @@ namespace vm 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 ); + auto result = ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), cast_ptr ); + result->setAlignment( llvm::Align( 1 ) ); + return result; } - return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), var ); + auto result = ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), var ); + result->setAlignment( llvm::Align( 1 ) ); + return result; } llvm_value_t *vmp_rtn_t::load_value( std::uint8_t byte_size, llvm_alloca_inst_t *var ) @@ -104,9 +128,14 @@ namespace vm 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 ); + auto result = ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), cast_ptr ); + result->setAlignment( llvm::Align( 1 ) ); + return result; } - return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), var ); + + auto result = ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), var ); + result->setAlignment( llvm::Align( 1 ) ); + return result; } llvm_function_t *vmp_rtn_t::lift( void ) @@ -131,6 +160,18 @@ namespace vm return llvm_fptr; } + void vmp_rtn_t::create_virtual_stack( void ) + { + // allocate stack space... + virtual_stack = ir_builder->CreateAlloca( llvm::ArrayType::get( llvm::IntegerType::get( *llvm_ctx, 8 ), 1024 ), + nullptr, "stack" ); + + // allocate stack pointer... + stack_ptr = ir_builder->CreateAlloca( llvm::IntegerType::get( *llvm_ctx, 64 ), nullptr, "sp" ); + ir_builder->CreateStore( llvm::ConstantInt::get( llvm::IntegerType::getInt64Ty( *llvm_ctx ), 1024 ), + stack_ptr ); + } + 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 );