From 8053fca586bf65ecea406c89b9591ffad27e3fc3 Mon Sep 17 00:00:00 2001 From: _xeroxz Date: Sat, 7 Aug 2021 01:42:17 -0700 Subject: [PATCH] added some more lifters... need to fix alignment... need to add RFLAGS alloca register and also code to update its bits.... getting there! --- CMakeLists.txt | 6 +- cmake.toml | 1 - dependencies/vmprofiler | 2 +- include/vm_lifters.hpp | 11 +- include/vmp_rtn.hpp | 14 ++- src/lifters/add.cpp | 17 +++ src/lifters/lconst.cpp | 10 +- src/lifters/lreg.cpp | 10 ++ src/lifters/pushvsp.cpp | 20 ++++ src/lifters/read.cpp | 0 src/lifters/sreg.cpp | 14 +-- src/main.cpp | 15 ++- src/vmp_rtn.cpp | 227 ++++++++++++++++++++++++++++++++-------- 13 files changed, 278 insertions(+), 69 deletions(-) create mode 100644 src/lifters/add.cpp create mode 100644 src/lifters/pushvsp.cpp create mode 100644 src/lifters/read.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c0445e..e1af35b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,14 +40,14 @@ set(CMKR_TARGET vmdevirt) set(vmdevirt_SOURCES "") list(APPEND vmdevirt_SOURCES + "src/lifters/add.cpp" "src/lifters/lconst.cpp" "src/lifters/lreg.cpp" + "src/lifters/pushvsp.cpp" + "src/lifters/read.cpp" "src/lifters/sreg.cpp" "src/main.cpp" "src/vmp_rtn.cpp" - "src/lifters/lconst.cpp" - "src/lifters/lreg.cpp" - "src/lifters/sreg.cpp" "include/vm_lifters.hpp" "include/vmp_rtn.hpp" ) diff --git a/cmake.toml b/cmake.toml index 24efd64..1be73bc 100644 --- a/cmake.toml +++ b/cmake.toml @@ -7,7 +7,6 @@ type = "executable" sources = [ "src/**.cpp", - "src/lifters/**.cpp", "include/**.hpp", ] include-directories = [ diff --git a/dependencies/vmprofiler b/dependencies/vmprofiler index ef9e9c1..16aeb2d 160000 --- a/dependencies/vmprofiler +++ b/dependencies/vmprofiler @@ -1 +1 @@ -Subproject commit ef9e9c1cb2f69abfc5ea070db71ef57b4316bb87 +Subproject commit 16aeb2d6d48c4822b89497ad660911eb0f5e54bd diff --git a/include/vm_lifters.hpp b/include/vm_lifters.hpp index 0e8827b..e2d4bb7 100644 --- a/include/vm_lifters.hpp +++ b/include/vm_lifters.hpp @@ -23,10 +23,17 @@ namespace vmp2::lifters const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) >; extern lifter_callback_t lconstq; + extern lifter_callback_t lconstdwsxq; + + extern lifter_callback_t pushvsp; + extern lifter_callback_t addq; extern lifter_callback_t sregq; + extern lifter_callback_t lregq; - inline std::map< vm::handler::mnemonic_t, lifter_callback_t * > lifters = { { vm::handler::LCONSTQ, &lconstq }, - { vm::handler::SREGQ, &sregq } }; + inline std::map< vm::handler::mnemonic_t, lifter_callback_t * > lifters = { + { vm::handler::LCONSTQ, &lconstq }, { vm::handler::LCONSTDWSXQ, &lconstdwsxq }, + { vm::handler::ADDQ, &addq }, { vm::handler::PUSHVSP, &pushvsp }, + { vm::handler::SREGQ, &sregq }, { vm::handler::LREGQ, &lregq } }; inline bool lift( 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 ) diff --git a/include/vmp_rtn.hpp b/include/vmp_rtn.hpp index 9ce80db..40fdd00 100644 --- a/include/vmp_rtn.hpp +++ b/include/vmp_rtn.hpp @@ -20,26 +20,34 @@ namespace vm class vmp_rtn_t { public: - explicit vmp_rtn_t( llvm::LLVMContext *llvm_ctx, llvm::Module *llvm_module, std::uintptr_t rtn_begin, - std::vector< vm::instrs::code_block_t > vmp2_code_blocks ); + 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 ); llvm::LLVMContext *llvm_ctx; + vm::ctx_t *vm_ctx; llvm::Module *llvm_module; std::uintptr_t rtn_begin; llvm::Function *llvm_fptr; std::shared_ptr< llvm::IRBuilder<> > ir_builder; llvm::AllocaInst *virtual_stack, *stack_ptr; - std::map< ZydisRegister, llvm::Constant * > native_registers; + std::map< ZydisRegister, llvm::GlobalVariable * > native_registers; std::vector< llvm::AllocaInst * > virtual_registers; std::vector< llvm::BasicBlock * > llvm_code_blocks; std::vector< vm::instrs::code_block_t > vmp2_code_blocks; + void push( std::uint8_t byte_size, llvm::Value *input_val ); + llvm::Value *pop( std::uint8_t byte_size ); + llvm::Value *peek( std::uint8_t byte_size, std::uint8_t byte_offset = 0u ); + llvm::Value *load_value( std::uint8_t byte_size, llvm::GlobalValue *global ); + llvm::Value *load_value( std::uint8_t byte_size, llvm::AllocaInst *var ); + private: void create_native_registers( void ); void create_virtual_registers( void ); void create_routine( void ); void create_virtual_stack( void ); + void lift_vm_entry( void ); }; } // namespace vm \ No newline at end of file diff --git a/src/lifters/add.cpp b/src/lifters/add.cpp new file mode 100644 index 0000000..e8e668d --- /dev/null +++ b/src/lifters/add.cpp @@ -0,0 +1,17 @@ +#include + +namespace vmp2::lifters +{ + lifter_callback_t addq = [ & ]( 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 t1 = rtn->pop( 8 ); + auto t2 = rtn->pop( 8 ); + auto t3 = ir_builder->CreateAdd( t1, t2 ); + + rtn->push( 8, t1 ); + rtn->push( 8, t3 ); + + // TODO: compute and update RFLAGS... + rtn->push( 8, rtn->load_value( 8, rtn->native_registers[ ZYDIS_REGISTER_RFLAGS ] ) ); + }; +} \ No newline at end of file diff --git a/src/lifters/lconst.cpp b/src/lifters/lconst.cpp index 638960b..0de0f38 100644 --- a/src/lifters/lconst.cpp +++ b/src/lifters/lconst.cpp @@ -3,8 +3,12 @@ namespace vmp2::lifters { lifter_callback_t lconstq = [ & ]( 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 push_val = llvm::ConstantInt::get( llvm::IntegerType::getInt64Ty( *rtn->llvm_ctx ), vinstr.operand.imm.u ); + const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) { + rtn->push( 8, llvm::ConstantInt::get( ir_builder->getInt64Ty(), vinstr.operand.imm.u ) ); + }; + lifter_callback_t lconstdwsxq = [ & ]( 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 ) { + rtn->push( 8, llvm::ConstantInt::get( ir_builder->getInt64Ty(), vinstr.operand.imm.u ) ); }; -} \ No newline at end of file +} // namespace vmp2::lifters \ No newline at end of file diff --git a/src/lifters/lreg.cpp b/src/lifters/lreg.cpp index e69de29..c1097b3 100644 --- a/src/lifters/lreg.cpp +++ b/src/lifters/lreg.cpp @@ -0,0 +1,10 @@ +#include + +namespace vmp2::lifters +{ + lifter_callback_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 ]; + rtn->push( 8, rtn->load_value( 8, vreg ) ); + }; +} \ No newline at end of file diff --git a/src/lifters/pushvsp.cpp b/src/lifters/pushvsp.cpp new file mode 100644 index 0000000..a815d08 --- /dev/null +++ b/src/lifters/pushvsp.cpp @@ -0,0 +1,20 @@ +#include + +namespace vmp2::lifters +{ + lifter_callback_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 ) { + // Load the current stack index into a temporary variable + auto current_stack_index = + ir_builder->CreateLoad( llvm::IntegerType::get( *rtn->llvm_ctx, 64 ), rtn->stack_ptr, false ); + + // Get a pointer to the top byte of the stack + llvm::Value *i64_zero = llvm::ConstantInt::get( *rtn->llvm_ctx, llvm::APInt( 64, 0 ) ); + llvm::Value *indices[ 2 ] = { i64_zero, current_stack_index }; + 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/read.cpp b/src/lifters/read.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/lifters/sreg.cpp b/src/lifters/sreg.cpp index 3b899b9..52322b4 100644 --- a/src/lifters/sreg.cpp +++ b/src/lifters/sreg.cpp @@ -7,16 +7,8 @@ namespace vmp2::lifters // %vregX = %1 lifter_callback_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 ) { - auto old_sp = - ir_builder->CreateLoad( llvm::IntegerType::get( *rtn->llvm_ctx, 64 ), rtn->stack_ptr, false, "old_sp" ); - - auto new_sp = ir_builder->CreateSub( - old_sp, llvm::ConstantInt::get( llvm::IntegerType::get( *rtn->llvm_ctx, 64 ), 8 ), "new_sp" ); - - ir_builder->CreateStore( new_sp, rtn->stack_ptr ); - - auto top_stack = - ir_builder->CreateGEP( llvm::ArrayType::get( llvm::IntegerType::get( *rtn->llvm_ctx, 8 ), 1024 ), - rtn->virtual_stack, new_sp, "top_stack" ); + 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 ); }; } // namespace vmp2::lifters \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 66d17f1..e0652fe 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -62,8 +62,19 @@ int main( int argc, const char *argv[] ) } LLVMContext llvm_ctx; - Module llvm_module( "VMProtect 2 Static Devirtualizer", llvm_ctx ); + Module llvm_module( "", llvm_ctx ); - vm::vmp_rtn_t vmp_rtn( &llvm_ctx, &llvm_module, first_block->vip_begin, vmp_code_blocks ); + 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 ); + + if ( !vm_ctx.init() ) + { + 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; + } + + vm::vmp_rtn_t vmp_rtn( &llvm_ctx, &llvm_module, &vm_ctx, first_block->vip_begin, vmp_code_blocks ); vmp_rtn.lift(); } \ No newline at end of file diff --git a/src/vmp_rtn.cpp b/src/vmp_rtn.cpp index f567661..dd1606b 100644 --- a/src/vmp_rtn.cpp +++ b/src/vmp_rtn.cpp @@ -3,13 +3,11 @@ namespace vm { - vmp_rtn_t::vmp_rtn_t( llvm::LLVMContext *llvm_ctx, llvm::Module *llvm_module, std::uintptr_t rtn_begin, - std::vector< vm::instrs::code_block_t > vmp2_code_blocks ) - : llvm_ctx( llvm_ctx ), llvm_module( llvm_module ), rtn_begin( rtn_begin ), vmp2_code_blocks( vmp2_code_blocks ) + 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 ) { - // create native registers... - create_native_registers(); - // create llvm::Function and llvm::BasicBlock's... create_routine(); @@ -17,65 +15,102 @@ namespace vm ir_builder = std::make_shared< llvm::IRBuilder<> >( *llvm_ctx ); ir_builder->SetInsertPoint( llvm_code_blocks[ 0 ] ); + // create native registers... + create_native_registers(); + // create stack and stack pointer... create_virtual_stack(); + // lift vm enter pushes to llvm ir... + lift_vm_entry(); + // create virtual registers... create_virtual_registers(); } + void vmp_rtn_t::lift_vm_entry( void ) + { + for ( const auto &instr : vm_ctx->vm_entry ) + { + if ( instr.instr.mnemonic == ZYDIS_MNEMONIC_PUSH ) + { + // push [xxxxx] we know this is zero and the next push is the image base... + if ( instr.instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY ) + { + push( 8, llvm::ConstantInt::get( ir_builder->getInt64Ty(), 0ull ) ); + push( 8, llvm::ConstantInt::get( ir_builder->getInt64Ty(), vm_ctx->image_base ) ); + break; // dont make these if statements a switch case because we need to use this break... + } + else if ( instr.instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_IMMEDIATE ) + { + push( 8, llvm::ConstantInt::get( ir_builder->getInt64Ty(), instr.instr.operands[ 0 ].imm.value.u, + false ) ); + } + else if ( instr.instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER ) + { + push( 8, load_value( 8, native_registers[ instr.instr.operands[ 0 ].reg.value ] ) ); + } + } + else if ( instr.instr.mnemonic == ZYDIS_MNEMONIC_PUSHFQ ) + { + // just push 0 as the value itself wont matter... + push( 8, load_value( 8, native_registers[ ZYDIS_REGISTER_RFLAGS ] ) ); + } + } + } + void vmp_rtn_t::create_native_registers( void ) { - native_registers[ ZYDIS_REGISTER_RAX ] = - llvm_module->getOrInsertGlobal( "rax", llvm::IntegerType::get( *llvm_ctx, 64 ) ); + llvm_module->getOrInsertGlobal( "rax", ir_builder->getInt64Ty() ); + native_registers[ ZYDIS_REGISTER_RAX ] = llvm_module->getGlobalVariable( "rax" ); - native_registers[ ZYDIS_REGISTER_RBX ] = - llvm_module->getOrInsertGlobal( "rbx", llvm::IntegerType::get( *llvm_ctx, 64 ) ); + llvm_module->getOrInsertGlobal( "rbx", ir_builder->getInt64Ty() ); + native_registers[ ZYDIS_REGISTER_RBX ] = llvm_module->getGlobalVariable( "rbx" ); - native_registers[ ZYDIS_REGISTER_RCX ] = - llvm_module->getOrInsertGlobal( "rcx", llvm::IntegerType::get( *llvm_ctx, 64 ) ); + llvm_module->getOrInsertGlobal( "rcx", ir_builder->getInt64Ty() ); + native_registers[ ZYDIS_REGISTER_RCX ] = llvm_module->getGlobalVariable( "rcx" ); - native_registers[ ZYDIS_REGISTER_RDX ] = - llvm_module->getOrInsertGlobal( "rdx", llvm::IntegerType::get( *llvm_ctx, 64 ) ); + llvm_module->getOrInsertGlobal( "rdx", ir_builder->getInt64Ty() ); + native_registers[ ZYDIS_REGISTER_RDX ] = llvm_module->getGlobalVariable( "rdx" ); - native_registers[ ZYDIS_REGISTER_RSI ] = - llvm_module->getOrInsertGlobal( "rsi", llvm::IntegerType::get( *llvm_ctx, 64 ) ); + llvm_module->getOrInsertGlobal( "rsi", ir_builder->getInt64Ty() ); + native_registers[ ZYDIS_REGISTER_RSI ] = llvm_module->getGlobalVariable( "rsi" ); - native_registers[ ZYDIS_REGISTER_RDI ] = - llvm_module->getOrInsertGlobal( "rdi", llvm::IntegerType::get( *llvm_ctx, 64 ) ); + llvm_module->getOrInsertGlobal( "rdi", ir_builder->getInt64Ty() ); + native_registers[ ZYDIS_REGISTER_RDI ] = llvm_module->getGlobalVariable( "rdi" ); - native_registers[ ZYDIS_REGISTER_RBP ] = - llvm_module->getOrInsertGlobal( "rbp", llvm::IntegerType::get( *llvm_ctx, 64 ) ); + llvm_module->getOrInsertGlobal( "rbp", ir_builder->getInt64Ty() ); + native_registers[ ZYDIS_REGISTER_RBP ] = llvm_module->getGlobalVariable( "rbp" ); - native_registers[ ZYDIS_REGISTER_RSP ] = - llvm_module->getOrInsertGlobal( "rsp", llvm::IntegerType::get( *llvm_ctx, 64 ) ); + llvm_module->getOrInsertGlobal( "rsp", ir_builder->getInt64Ty() ); + native_registers[ ZYDIS_REGISTER_RSP ] = llvm_module->getGlobalVariable( "rsp" ); - native_registers[ ZYDIS_REGISTER_R8 ] = - llvm_module->getOrInsertGlobal( "r8", llvm::IntegerType::get( *llvm_ctx, 64 ) ); + llvm_module->getOrInsertGlobal( "r8", ir_builder->getInt64Ty() ); + native_registers[ ZYDIS_REGISTER_R8 ] = llvm_module->getGlobalVariable( "r8" ); - native_registers[ ZYDIS_REGISTER_R9 ] = - llvm_module->getOrInsertGlobal( "r9", llvm::IntegerType::get( *llvm_ctx, 64 ) ); + llvm_module->getOrInsertGlobal( "r9", ir_builder->getInt64Ty() ); + native_registers[ ZYDIS_REGISTER_R9 ] = llvm_module->getGlobalVariable( "r9" ); - native_registers[ ZYDIS_REGISTER_R10 ] = - llvm_module->getOrInsertGlobal( "r10", llvm::IntegerType::get( *llvm_ctx, 64 ) ); + llvm_module->getOrInsertGlobal( "r10", ir_builder->getInt64Ty() ); + native_registers[ ZYDIS_REGISTER_R10 ] = llvm_module->getGlobalVariable( "r10" ); - native_registers[ ZYDIS_REGISTER_R11 ] = - llvm_module->getOrInsertGlobal( "r11", llvm::IntegerType::get( *llvm_ctx, 64 ) ); + llvm_module->getOrInsertGlobal( "r11", ir_builder->getInt64Ty() ); + native_registers[ ZYDIS_REGISTER_R11 ] = llvm_module->getGlobalVariable( "r11" ); - native_registers[ ZYDIS_REGISTER_R12 ] = - llvm_module->getOrInsertGlobal( "r12", llvm::IntegerType::get( *llvm_ctx, 64 ) ); + llvm_module->getOrInsertGlobal( "r12", ir_builder->getInt64Ty() ); + native_registers[ ZYDIS_REGISTER_R12 ] = llvm_module->getGlobalVariable( "r12" ); - native_registers[ ZYDIS_REGISTER_R13 ] = - llvm_module->getOrInsertGlobal( "r13", llvm::IntegerType::get( *llvm_ctx, 64 ) ); + llvm_module->getOrInsertGlobal( "r13", ir_builder->getInt64Ty() ); + native_registers[ ZYDIS_REGISTER_R13 ] = llvm_module->getGlobalVariable( "r13" ); - native_registers[ ZYDIS_REGISTER_R14 ] = - llvm_module->getOrInsertGlobal( "r14", llvm::IntegerType::get( *llvm_ctx, 64 ) ); + llvm_module->getOrInsertGlobal( "r14", ir_builder->getInt64Ty() ); + native_registers[ ZYDIS_REGISTER_R14 ] = llvm_module->getGlobalVariable( "r14" ); - native_registers[ ZYDIS_REGISTER_R15 ] = - llvm_module->getOrInsertGlobal( "r15", llvm::IntegerType::get( *llvm_ctx, 64 ) ); + llvm_module->getOrInsertGlobal( "r15", ir_builder->getInt64Ty() ); + native_registers[ ZYDIS_REGISTER_R15 ] = llvm_module->getGlobalVariable( "r15" ); - native_registers[ ZYDIS_REGISTER_RFLAGS ] = - llvm_module->getOrInsertGlobal( "rflags", llvm::IntegerType::get( *llvm_ctx, 64 ) ); + llvm_module->getOrInsertGlobal( "rflags", ir_builder->getInt64Ty() ); + native_registers[ ZYDIS_REGISTER_RFLAGS ] = llvm_module->getGlobalVariable( "rflags" ); } void vmp_rtn_t::create_virtual_registers( void ) @@ -109,6 +144,114 @@ namespace vm } } + void vmp_rtn_t::push( std::uint8_t byte_size, llvm::Value *input_value ) + { + // Load the current stack index into a temporary variable + auto current_stack_index = ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, 64 ), stack_ptr, false ); + + // Subtract the input value size from the current stack index + auto new_stack_index = ir_builder->CreateSub( + current_stack_index, llvm::ConstantInt::get( llvm::IntegerType::get( *llvm_ctx, 64 ), byte_size ) ); + + // Store the newly calculated stack index into VSP + ir_builder->CreateStore( new_stack_index, stack_ptr ); + + // Get a pointer to the top byte of the stack + llvm::Value *i64_zero = llvm::ConstantInt::get( *llvm_ctx, llvm::APInt( 64, 0 ) ); + llvm::Value *indices[ 2 ] = { i64_zero, new_stack_index }; + auto stack_ptr = ir_builder->CreateInBoundsGEP( virtual_stack, llvm::ArrayRef< llvm::Value * >( indices, 2 ) ); + + // Store the input value at the calculated stack address + if ( byte_size == 1 ) + { + ir_builder->CreateStore( input_value, stack_ptr ); + } + else + { + // Cast the pointer so the stack item width matches the width of the input value + auto casted_ptr = ir_builder->CreatePointerCast( + stack_ptr, llvm::PointerType::get( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), 0 ) ); + + ir_builder->CreateStore( input_value, casted_ptr ); + } + } + + llvm::Value *vmp_rtn_t::pop( std::uint8_t byte_size ) + { + // Load the current stack index into a temporary variable + auto current_stack_index = ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, 64 ), stack_ptr, false ); + + // Get a pointer to the top byte of the stack + llvm::Value *i64_zero = llvm::ConstantInt::get( *llvm_ctx, llvm::APInt( 64, 0 ) ); + llvm::Value *indices[ 2 ] = { i64_zero, current_stack_index }; + auto stack_ptr = ir_builder->CreateInBoundsGEP( virtual_stack, llvm::ArrayRef< llvm::Value * >( indices, 2 ) ); + + // Read the value at the top of the stack + llvm::Value *output_value = nullptr; + + if ( byte_size == 1 ) + { + output_value = ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, 8 ), stack_ptr ); + } + else + { + // Cast the current stack pointer so the stack item width matches the width of the output value + auto casted_ptr = ir_builder->CreatePointerCast( + stack_ptr, llvm::PointerType::get( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), 0 ) ); + + output_value = ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), casted_ptr ); + } + + // Subtract the input value size from the current stack index + auto new_stack_index = ir_builder->CreateAdd( + current_stack_index, llvm::ConstantInt::get( llvm::IntegerType::get( *llvm_ctx, 64 ), byte_size ) ); + + // Store the newly calculated stack index into VSP + ir_builder->CreateStore( new_stack_index, this->stack_ptr ); + return output_value; + } + + llvm::Value *vmp_rtn_t::peek( std::uint8_t byte_size, std::uint8_t byte_offset ) + { + // Load the current stack index into a temporary variable + auto current_stack_index = ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, 64 ), stack_ptr, false ); + + if ( byte_offset ) + { + auto t1 = ir_builder->CreateAdd( + current_stack_index, llvm::ConstantInt::get( llvm::IntegerType::get( *llvm_ctx, 64 ), byte_offset ) ); + + current_stack_index = ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, 64 ), t1, false ); + } + + // Get a pointer to the top byte of the stack + byte_offset (if any) + llvm::Value *i64_zero = llvm::ConstantInt::get( *llvm_ctx, llvm::APInt( 64, 0 ) ); + llvm::Value *indices[ 2 ] = { i64_zero, current_stack_index }; + auto stack_ptr = ir_builder->CreateInBoundsGEP( virtual_stack, llvm::ArrayRef< llvm::Value * >( indices, 2 ) ); + + if ( byte_size != 1 ) + { + auto casted_ptr = ir_builder->CreatePointerCast( + stack_ptr, llvm::PointerType::get( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), 0 ) ); + + return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), casted_ptr ); + } + else + { + return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), stack_ptr ); + } + } + + llvm::Value *vmp_rtn_t::load_value( std::uint8_t byte_size, llvm::GlobalValue *global ) + { + return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), global ); + } + + llvm::Value *vmp_rtn_t::load_value( std::uint8_t byte_size, llvm::AllocaInst *var ) + { + return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), var ); + } + void vmp_rtn_t::create_virtual_stack( void ) { // allocate stack space... @@ -117,7 +260,6 @@ namespace vm // 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 ); } @@ -131,8 +273,7 @@ namespace vm { if ( !vmp2::lifters::lift( this, vmp2_code_blocks[ idx ], vinstr, ir_builder.get() ) ) { - std::printf( "> failed to devirtualize virtual instruction with vm handler index = %d\n", - vinstr.opcode ); + std::printf( "> failed to devirtualize virtual instruction with opcode = %d\n", vinstr.opcode ); llvm_module->print( llvm::outs(), nullptr ); return nullptr;