|
|
@ -3,14 +3,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
namespace vm
|
|
|
|
namespace vm
|
|
|
|
{
|
|
|
|
{
|
|
|
|
vmp_rtn_t::vmp_rtn_t( llvm_context_t *llvm_ctx, llvm_module_t *llvm_module, vm::ctx_t *vm_ctx,
|
|
|
|
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 )
|
|
|
|
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 ),
|
|
|
|
: llvm_ctx( llvm_ctx ), llvm_module( llvm_module ), vm_ctx( vm_ctx ), rtn_begin( rtn_begin ),
|
|
|
|
vmp2_code_blocks( vmp2_code_blocks )
|
|
|
|
vmp2_code_blocks( vmp2_code_blocks )
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// do not change the ordering of these function calls...
|
|
|
|
// do not change the ordering of these function calls...
|
|
|
|
create_routine();
|
|
|
|
create_routine();
|
|
|
|
ir_builder = std::make_shared< llvm_irbuilder_t >( *llvm_ctx );
|
|
|
|
ir_builder = std::make_shared< llvm::IRBuilder<> >( *llvm_ctx );
|
|
|
|
ir_builder->SetInsertPoint( llvm_code_blocks[ 0 ].second );
|
|
|
|
ir_builder->SetInsertPoint( llvm_code_blocks[ 0 ].second );
|
|
|
|
flags = ir_builder->CreateAlloca( ir_builder->getInt64Ty(), nullptr, "flags" );
|
|
|
|
flags = ir_builder->CreateAlloca( ir_builder->getInt64Ty(), nullptr, "flags" );
|
|
|
|
stack = ir_builder->CreateAlloca( llvm::PointerType::get( ir_builder->getInt8Ty(), 0ull ), nullptr, "sp" );
|
|
|
|
stack = ir_builder->CreateAlloca( llvm::PointerType::get( ir_builder->getInt8Ty(), 0ull ), nullptr, "sp" );
|
|
|
@ -32,7 +32,7 @@ namespace vm
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// function has no arguments and returns void... maybe change this in the future as i learn
|
|
|
|
// function has no arguments and returns void... maybe change this in the future as i learn
|
|
|
|
// more and more LLVM...
|
|
|
|
// more and more LLVM...
|
|
|
|
auto func_ty = llvm::FunctionType::get( llvm::Type::getVoidTy( *llvm_ctx ),
|
|
|
|
auto func_ty = llvm::FunctionType::get( llvm::PointerType::getInt8PtrTy( *llvm_ctx ),
|
|
|
|
{ llvm::PointerType::getInt8PtrTy( *llvm_ctx ) }, false );
|
|
|
|
{ llvm::PointerType::getInt8PtrTy( *llvm_ctx ) }, false );
|
|
|
|
|
|
|
|
|
|
|
|
// convert the rtn_begin address to a hex string and prepend "rtn_" to it...
|
|
|
|
// convert the rtn_begin address to a hex string and prepend "rtn_" to it...
|
|
|
@ -51,7 +51,7 @@ namespace vm
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void vmp_rtn_t::push( std::uint8_t num_bytes, llvm_value_t *val )
|
|
|
|
void vmp_rtn_t::push( std::uint8_t num_bytes, llvm::Value *val )
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// sub rsp, num_bytes
|
|
|
|
// sub rsp, num_bytes
|
|
|
|
auto rsp_addr = ir_builder->CreateLoad( stack );
|
|
|
|
auto rsp_addr = ir_builder->CreateLoad( stack );
|
|
|
@ -67,7 +67,7 @@ namespace vm
|
|
|
|
ir_builder->CreateStore( val, rsp_cast_ptr );
|
|
|
|
ir_builder->CreateStore( val, rsp_cast_ptr );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
llvm_value_t *vmp_rtn_t::pop( std::uint8_t num_bytes )
|
|
|
|
llvm::Value *vmp_rtn_t::pop( std::uint8_t num_bytes )
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// mov rax, [rsp]
|
|
|
|
// mov rax, [rsp]
|
|
|
|
auto rsp_addr = ir_builder->CreateLoad( stack );
|
|
|
|
auto rsp_addr = ir_builder->CreateLoad( stack );
|
|
|
@ -85,7 +85,7 @@ namespace vm
|
|
|
|
return pop_val;
|
|
|
|
return pop_val;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
llvm_value_t *vmp_rtn_t::load_value( std::uint8_t byte_size, llvm_global_value_t *var )
|
|
|
|
llvm::Value *vmp_rtn_t::load_value( std::uint8_t byte_size, llvm::GlobalValue *var )
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if ( byte_size * 8 != var->getType()->getPrimitiveSizeInBits() )
|
|
|
|
if ( byte_size * 8 != var->getType()->getPrimitiveSizeInBits() )
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -97,7 +97,7 @@ namespace vm
|
|
|
|
return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), var );
|
|
|
|
return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), var );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
llvm_value_t *vmp_rtn_t::load_value( std::uint8_t byte_size, llvm_alloca_inst_t *var )
|
|
|
|
llvm::Value *vmp_rtn_t::load_value( std::uint8_t byte_size, llvm::AllocaInst *var )
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if ( byte_size * 8 != var->getType()->getPrimitiveSizeInBits() )
|
|
|
|
if ( byte_size * 8 != var->getType()->getPrimitiveSizeInBits() )
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -109,7 +109,7 @@ namespace vm
|
|
|
|
return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), var );
|
|
|
|
return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), var );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
llvm_function_t *vmp_rtn_t::lift( void )
|
|
|
|
llvm::Function *vmp_rtn_t::lift( void )
|
|
|
|
{
|
|
|
|
{
|
|
|
|
auto &code_blocks = llvm_fptr->getBasicBlockList();
|
|
|
|
auto &code_blocks = llvm_fptr->getBasicBlockList();
|
|
|
|
auto lifters = vm::lifters_t::get_instance();
|
|
|
|
auto lifters = vm::lifters_t::get_instance();
|
|
|
@ -117,35 +117,46 @@ namespace vm
|
|
|
|
for ( auto idx = 0u; idx < code_blocks.size(); ++idx )
|
|
|
|
for ( auto idx = 0u; idx < code_blocks.size(); ++idx )
|
|
|
|
{
|
|
|
|
{
|
|
|
|
ir_builder->SetInsertPoint( llvm_code_blocks[ idx ].second );
|
|
|
|
ir_builder->SetInsertPoint( llvm_code_blocks[ idx ].second );
|
|
|
|
|
|
|
|
|
|
|
|
for ( auto &vinstr : vmp2_code_blocks[ idx ].vinstrs )
|
|
|
|
for ( auto &vinstr : vmp2_code_blocks[ idx ].vinstrs )
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if ( !lifters->lift( this, vmp2_code_blocks[ idx ], vinstr, ir_builder.get() ) )
|
|
|
|
if ( !lifters->lift( this, vmp2_code_blocks[ idx ], vinstr, ir_builder.get() ) )
|
|
|
|
{
|
|
|
|
{
|
|
|
|
std::printf( "> failed to devirtualize virtual instruction with opcode = %d\n", vinstr.opcode );
|
|
|
|
std::printf(
|
|
|
|
llvm_module->print( llvm::outs(), nullptr );
|
|
|
|
"> 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 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;
|
|
|
|
return llvm_fptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
llvm_value_t *vmp_rtn_t::compute_sf( std::uint8_t byte_size, llvm_value_t *val )
|
|
|
|
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 op_size = llvm::IntegerType::get( *llvm_ctx, byte_size * 8 );
|
|
|
|
auto msb = ir_builder->CreateLShr( val, ( byte_size * 8 ) - 1 );
|
|
|
|
auto msb = ir_builder->CreateLShr( val, ( byte_size * 8 ) - 1 );
|
|
|
|
return ir_builder->CreateZExt( msb, llvm::IntegerType::get( *llvm_ctx, 64 ) );
|
|
|
|
return ir_builder->CreateZExt( msb, llvm::IntegerType::get( *llvm_ctx, 64 ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
llvm_value_t *vmp_rtn_t::compute_zf( std::uint8_t byte_size, llvm_value_t *val )
|
|
|
|
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 op_size = llvm::IntegerType::get( *llvm_ctx, byte_size * 8 );
|
|
|
|
auto is_zero = ir_builder->CreateICmpEQ( val, llvm::ConstantInt::get( op_size, 0 ) );
|
|
|
|
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 ) );
|
|
|
|
return ir_builder->CreateZExt( is_zero, llvm::IntegerType::get( *llvm_ctx, 64 ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
llvm_value_t *vmp_rtn_t::compute_pf( std::uint8_t byte_size, llvm_value_t *val )
|
|
|
|
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 operand_size = llvm::IntegerType::get( *llvm_ctx, byte_size * 8 );
|
|
|
|
auto popcount_intrinsic = llvm::Intrinsic::getDeclaration( llvm_module, llvm::Intrinsic::ctpop,
|
|
|
|
auto popcount_intrinsic = llvm::Intrinsic::getDeclaration( llvm_module, llvm::Intrinsic::ctpop,
|
|
|
@ -156,8 +167,8 @@ namespace vm
|
|
|
|
return ir_builder->CreateCall( popcount_intrinsic, { extended_bits } );
|
|
|
|
return ir_builder->CreateCall( popcount_intrinsic, { extended_bits } );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
llvm_value_t *vmp_rtn_t::combine_flags( llvm_value_t *cf, llvm_value_t *pf, llvm_value_t *af, llvm_value_t *zf,
|
|
|
|
llvm::Value *vmp_rtn_t::combine_flags( llvm::Value *cf, llvm::Value *pf, llvm::Value *af, llvm::Value *zf,
|
|
|
|
llvm_value_t *sf, llvm_value_t *of )
|
|
|
|
llvm::Value *sf, llvm::Value *of )
|
|
|
|
{
|
|
|
|
{
|
|
|
|
auto shifted_pf = ir_builder->CreateShl( pf, 2, "shifted_pf", true, true );
|
|
|
|
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 ),
|
|
|
|
auto shifted_af = ir_builder->CreateShl( llvm::ConstantInt::get( llvm::IntegerType::get( *llvm_ctx, 64 ), 0 ),
|
|
|
|