EAST BOUND AND DOWN

merge-requests/6/head
_xeroxz 3 years ago
parent 29804c5015
commit 1c6fd327b1

@ -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

@ -1,5 +1,5 @@
#pragma once
#include <vmprofiler.hpp>
#include <vmp_rtn_t.hpp>
#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

@ -1,7 +1,5 @@
#pragma once
#include <functional>
#include <vmp_rtn.hpp>
#include <vmprofiler.hpp>
#include <devirt_t.hpp>
#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() )

@ -0,0 +1,41 @@
#pragma once
#include <vmprofiler.hpp>
#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

@ -0,0 +1,141 @@
#include <devirt_t.hpp>
#include <vm_lifters.hpp>
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

@ -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

@ -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 );
}
};
}

@ -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 ) );
};

@ -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 );
};
}

@ -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

@ -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

@ -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 );
};

@ -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 ) );

@ -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

@ -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 );

@ -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 ) );
};
}

@ -1,52 +1,29 @@
#include <Windows.h>
#include <cli-parser.hpp>
#include <vmp_rtn.hpp>
#include <vmprofiler.hpp>
#include <devirt_t.hpp>
#include <xtils.hpp>
using namespace llvm;
int main( int argc, const char *argv[] )
/// <summary>
/// helper function to serialize vmp2 file data to vm::instr::code_block's...
/// </summary>
/// <param name="virt_rtns">vector of pairs {vm enter offset, vector of code blocks} which gets filled up with
/// serialized data</param>
/// <param name="vmp2file">a vector of bytes containing the vmp2 file...</param>
/// <returns>returns true if serialization was successful</returns>
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() );
}

@ -1,182 +0,0 @@
#include <vm_lifters.hpp>
#include <vmp_rtn.hpp>
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

@ -0,0 +1,52 @@
#include <vmp_rtn_t.hpp>
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
Loading…
Cancel
Save