Merge branch '_xeroxz' into 'master'

_xeroxz into master

See merge request vmp2/vmdevirt!12
master v0.1
_xeroxz 3 years ago
commit 680edc4faf

@ -44,6 +44,8 @@ list(APPEND vmdevirt_SOURCES
"src/devirt_utils.cpp"
"src/lifters/add.cpp"
"src/lifters/div.cpp"
"src/lifters/idiv.cpp"
"src/lifters/imul.cpp"
"src/lifters/jmp.cpp"
"src/lifters/lconst.cpp"
"src/lifters/lflags.cpp"
@ -52,13 +54,20 @@ list(APPEND vmdevirt_SOURCES
"src/lifters/nand.cpp"
"src/lifters/popvsp.cpp"
"src/lifters/pushvsp.cpp"
"src/lifters/rdtsc.cpp"
"src/lifters/read.cpp"
"src/lifters/readcr3.cpp"
"src/lifters/readcr8.cpp"
"src/lifters/readgs.cpp"
"src/lifters/sflags.cpp"
"src/lifters/shl.cpp"
"src/lifters/shld.cpp"
"src/lifters/shr.cpp"
"src/lifters/shrd.cpp"
"src/lifters/sreg.cpp"
"src/lifters/vmexit.cpp"
"src/lifters/write.cpp"
"src/lifters/writecr3.cpp"
"src/main.cpp"
"src/vmp_rtn_t.cpp"
"include/devirt_t.hpp"

@ -1 +1 @@
Subproject commit 7b1f815a73096ac33f41133b63d991019622de49
Subproject commit 1b6875d18825529907289bc87990fed5d99e7f96

@ -29,48 +29,91 @@ namespace vm
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) >;
static lifter_callback_t lconstq, lconstdwsxq, lconstwsxq, lconstbzxw, lconstbsxq, lconstwsxdw, lconstdw,
lconstbsxdw;
lconstw, lconstbsxdw;
static lifter_callback_t addq, adddw, addw;
static lifter_callback_t sregq, sregdw, sregb;
static lifter_callback_t addq, adddw, addw, addb;
static lifter_callback_t sregq, sregdw, sregw, sregb;
static lifter_callback_t lregq, lregdw;
static lifter_callback_t pushvsp;
static lifter_callback_t imulq, imuldw;
static lifter_callback_t mulq, muldw;
static lifter_callback_t pushvspq, pushvspdw;
static lifter_callback_t popvsp;
static lifter_callback_t writeq;
static lifter_callback_t readq, readdw;
static lifter_callback_t nandq, nanddw, nandb;
static lifter_callback_t shrq;
static lifter_callback_t writeq, writedw, writew, writeb;
static lifter_callback_t readq, readdw, readw, readb;
static lifter_callback_t nandq, nanddw, nandw, nandb;
static lifter_callback_t shrq, shrdw, shrw, shrb;
static lifter_callback_t shlq, shldw, shlb;
static lifter_callback_t shldq, shlddw;
static lifter_callback_t shrdq, shrddw;
static lifter_callback_t jmp;
static lifter_callback_t lflagsq;
static lifter_callback_t vmexit;
static lifter_callback_t readcr8;
static lifter_callback_t readcr3;
static lifter_callback_t writecr3;
static lifter_callback_t rdtsc;
static lifter_callback_t readgsq;
static lifter_callback_t divq, divdw;
static lifter_callback_t idivdw;
std::map< vm::handler::mnemonic_t, lifter_callback_t * > lifters = { { vm::handler::LCONSTQ, &lconstq },
{ vm::handler::LCONSTDW, &lconstdw },
{ vm::handler::LCONSTW, &lconstw },
{ vm::handler::LCONSTDWSXQ, &lconstdwsxq },
{ vm::handler::LCONSTWSXQ, &lconstwsxq },
{ vm::handler::LCONSTBZXW, &lconstbzxw },
{ vm::handler::LCONSTBSXQ, &lconstbsxq },
{ vm::handler::LCONSTWSXDW, &lconstwsxdw },
{ vm::handler::LCONSTBSXDW, &lconstbsxdw },
{ vm::handler::DIVQ, &divq },
{ vm::handler::DIVDW, &divdw },
{ vm::handler::IDIVDW, &idivdw },
{ vm::handler::ADDQ, &addq },
{ vm::handler::ADDDW, &adddw },
{ vm::handler::ADDW, &addw },
{ vm::handler::ADDB, &addb },
{ vm::handler::SHRQ, &shrq },
{ vm::handler::PUSHVSP, &pushvsp },
{ vm::handler::POPVSP, &popvsp },
{ vm::handler::SHRDW, &shrdw },
{ vm::handler::SHRW, &shrw },
{ vm::handler::SHRB, &shrb },
{ vm::handler::SHLQ, &shlq },
{ vm::handler::SHLDW, &shldw },
{ vm::handler::SHLB, &shlb },
{ vm::handler::SHLDQ, &shldq },
{ vm::handler::SHLDDW, &shlddw },
{ vm::handler::SHRDQ, &shrdq },
{ vm::handler::SHRDDW, &shrddw },
{ vm::handler::IMULQ, &imulq },
{ vm::handler::IMULDW, &imuldw },
{ vm::handler::MULQ, &mulq },
{ vm::handler::MULDW, &muldw },
{ vm::handler::PUSHVSPQ, &pushvspq },
{ vm::handler::PUSHVSPDW, &pushvspdw },
{ vm::handler::POPVSPQ, &popvsp },
{ vm::handler::SREGQ, &sregq },
{ vm::handler::SREGDW, &sregdw },
{ vm::handler::SREGW, &sregw },
{ vm::handler::SREGB, &sregb },
{ vm::handler::LREGQ, &lregq },
{ vm::handler::LREGDW, &lregdw },
{ vm::handler::READQ, &readq },
{ vm::handler::READDW, &readdw },
{ vm::handler::READW, &readw },
{ vm::handler::READB, &readb },
{ vm::handler::WRITEQ, &writeq },
{ vm::handler::WRITEDW, &writedw },
{ vm::handler::WRITEW, &writew },
{ vm::handler::WRITEB, &writeb },
{ vm::handler::NANDQ, &nandq },
{ vm::handler::NANDDW, &nanddw },
{ vm::handler::NANDW, &nandw },
{ vm::handler::NANDB, &nandb },
{ vm::handler::LFLAGSQ, &lflagsq },
{ vm::handler::READCR8, &readcr8 },
{ vm::handler::READCR3, &readcr3 },
{ vm::handler::WRITECR3, &writecr3 },
{ vm::handler::RDTSC, &rdtsc },
{ vm::handler::READGSQ, &readgsq },
{ vm::handler::JMP, &jmp },
{ vm::handler::VMEXIT, &vmexit } };

@ -85,6 +85,19 @@ namespace vm
bool devirt_t::compile( std::vector< std::uint8_t > &obj )
{
llvm::legacy::FunctionPassManager pass_mgr( llvm_module );
pass_mgr.add( llvm::createPromoteMemoryToRegisterPass() );
pass_mgr.add( llvm::createNewGVNPass() );
pass_mgr.add( llvm::createReassociatePass() );
pass_mgr.add( llvm::createDeadCodeEliminationPass() );
pass_mgr.add( llvm::createInstructionCombiningPass() );
for ( auto vmp_rtn : vmp_rtns )
{
pass_mgr.run( *vmp_rtn->llvm_fptr );
std::printf( "> opt rtn_0x%p\n", vmp_rtn->rtn_begin );
}
llvm::TargetOptions opt;
llvm::SmallVector< char, 128 > buff;
llvm::raw_svector_ostream dest( buff );
@ -116,6 +129,12 @@ namespace vm
for ( auto idx = 0u; idx < vmp_rtn->vmp2_code_blocks.size(); ++idx )
{
ir_builder->SetInsertPoint( vmp_rtn->llvm_code_blocks[ idx ].second );
if ( vmp_rtn->vmp2_code_blocks[ idx ].vinstrs.size() < 35 )
{
ir_builder->CreateRetVoid();
continue;
}
for ( auto &vinstr : vmp_rtn->vmp2_code_blocks[ idx ].vinstrs )
{
if ( !lifters->lift( this, vmp_rtn->vmp2_code_blocks[ idx ], vinstr, ir_builder.get() ) )

@ -193,30 +193,6 @@ namespace devirt
}
} );
auto resize_cnt = new_relocs.size() * ( sizeof( win::reloc_entry_t ) + sizeof( win::reloc_block_t ) );
map_buff.resize( map_img->get_nt_headers()->optional_header.size_image += resize_cnt );
map_img = reinterpret_cast< win::image_t<> * >( map_buff.data() );
auto basereloc_dir = map_img->get_directory( win::directory_id::directory_entry_basereloc );
auto reloc_dir = reinterpret_cast< win::reloc_directory_t * >( basereloc_dir->rva + map_buff.data() );
basereloc_dir->size += resize_cnt;
for ( const auto &[ reloc_rva, reloc_offset ] : new_relocs )
{
win::reloc_block_t *reloc_block = &reloc_dir->first_block;
while ( reloc_block->base_rva && reloc_block->size_block )
reloc_block = reloc_block->next();
reloc_block->base_rva = reloc_rva;
reloc_block->size_block = sizeof( win::reloc_entry_t ) + sizeof uint64_t;
reloc_block->next()->base_rva = 0ull;
reloc_block->next()->size_block = 0ull;
reloc_block->entries[ 0 ].type = win::reloc_type_id::rel_based_dir64;
reloc_block->entries[ 0 ].offset = reloc_offset;
}
// replace bin vector with map_buff vector...
bin.clear();
bin.insert( bin.begin(), map_buff.begin(), map_buff.end() );

@ -29,15 +29,15 @@ namespace vm
auto pf = llvm::ConstantInt::get( llvm::IntegerType::get( *rtn->llvm_ctx, 64 ),
0 ); // TODO make clean PF bit computation...
auto flags_calc = rtn->flags(
cf, pf, llvm::ConstantInt::get( llvm::IntegerType::get( *rtn->llvm_ctx, 64 ), 0 ), zf, sf, of );
auto flags_calc =
rtn->flags( cf, pf, llvm::ConstantInt::get( llvm::IntegerType::get( *rtn->llvm_ctx, 64 ), 0 ), zf, sf, of );
return flags_calc;
}
lifters_t::lifter_callback_t lifters_t::addq =
[ & ]( vm::devirt_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 t2 = rtn->pop( 8 );
auto t3 = ir_builder->CreateAdd( t1, t2 );
@ -50,8 +50,8 @@ namespace vm
};
lifters_t::lifter_callback_t lifters_t::adddw =
[ & ]( vm::devirt_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 t2 = rtn->pop( 4 );
auto t3 = ir_builder->CreateAdd( t1, t2 );
@ -64,8 +64,8 @@ namespace vm
};
lifters_t::lifter_callback_t lifters_t::addw =
[ & ]( vm::devirt_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( 2 );
auto t2 = rtn->pop( 2 );
auto t3 = ir_builder->CreateAdd( t1, t2 );
@ -77,4 +77,22 @@ namespace vm
rtn->push( 8, rtn->load_value( 8, vmp_rtn->flags ) );
};
lifters_t::lifter_callback_t lifters_t::addb =
[ & ]( 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->CreateIntCast( t1, ir_builder->getInt8Ty(), false );
auto t4 = ir_builder->CreateIntCast( t2, ir_builder->getInt8Ty(), false );
auto t5 = ir_builder->CreateAdd( t3, t4 );
rtn->push( 2, ir_builder->CreateIntCast( t5, ir_builder->getInt16Ty(), false ) );
auto &vmp_rtn = rtn->vmp_rtns.back();
auto flags = lifters_t::add_flags( rtn, 1, t3, t4 );
ir_builder->CreateStore( flags, vmp_rtn->flags );
rtn->push( 8, rtn->load_value( 8, vmp_rtn->flags ) );
};
} // namespace vm

@ -0,0 +1,34 @@
#include <vm_lifters.hpp>
namespace vm
{
lifters_t::lifter_callback_t lifters_t::divq =
[ & ]( 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 = rtn->pop( 8 );
ir_builder->CreateUDiv( t2, t3 );
rtn->push( 8, t1 );
rtn->push( 8, t2 );
auto &vmp_rtn = rtn->vmp_rtns.back();
// TODO: compute flags...
rtn->push( 8, rtn->load_value( 8, vmp_rtn->flags ) );
};
lifters_t::lifter_callback_t lifters_t::divdw =
[ & ]( 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 = rtn->pop( 4 );
ir_builder->CreateUDiv( t2, t3 );
rtn->push( 4, t1 );
rtn->push( 4, t2 );
auto &vmp_rtn = rtn->vmp_rtns.back();
// TODO: compute flags...
rtn->push( 8, rtn->load_value( 8, vmp_rtn->flags ) );
};
} // namespace vm

@ -0,0 +1,20 @@
#include <vm_lifters.hpp>
namespace vm
{
lifters_t::lifter_callback_t lifters_t::idivdw =
[ & ]( 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 );
// TODO: this is wrong...
ir_builder->CreateUDiv( t1, t2 );
rtn->push( 4, t1 );
rtn->push( 4, t2 );
auto &vmp_rtn = rtn->vmp_rtns.back();
// TODO: compute flags...
rtn->push( 8, rtn->load_value( 8, vmp_rtn->flags ) );
};
}

@ -0,0 +1,45 @@
#include <vm_lifters.hpp>
// https://lists.llvm.org/pipermail/llvm-dev/2014-July/074685.html
// credit to James Courtier-Dutton for asking this question in 2014...
namespace vm
{
lifters_t::lifter_callback_t lifters_t::imulq =
[ & ]( 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 );
// TODO: this is wrong... still need to do some more research into this...
auto t3 = ir_builder->CreateMul( t1, t2 );
auto t4 = ir_builder->CreateAShr( t3, llvm::APInt( 64, 32 ) );
auto t5 = ir_builder->CreateAnd( t3, 0xFFFFFFFF00000000 );
rtn->push( 8, t4 );
rtn->push( 8, t5 );
// TODO: compute flags for IMULQ
auto &vmp_rtn = rtn->vmp_rtns.back();
rtn->push( 8, rtn->load_value( 8, vmp_rtn->flags ) );
};
lifters_t::lifter_callback_t lifters_t::imuldw =
[ & ]( 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->CreateIntCast( t1, ir_builder->getInt64Ty(), false );
auto t4 = ir_builder->CreateIntCast( t2, ir_builder->getInt64Ty(), false );
auto t5 = ir_builder->CreateMul( t3, t4 );
auto t6 = ir_builder->CreateAShr( t5, llvm::APInt( 64, 32 ) );
auto t7 = ir_builder->CreateAnd( t5, 0xFFFFFFFF00000000 );
rtn->push( 8, t6 );
rtn->push( 8, t7 );
// TODO: compute flags for IMULQ
auto &vmp_rtn = rtn->vmp_rtns.back();
rtn->push( 8, rtn->load_value( 8, vmp_rtn->flags ) );
};
} // namespace vm

@ -5,11 +5,16 @@ namespace vm
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" );
if ( !vm_code_block.jcc.has_jcc )
{
ir_builder->CreateRetVoid();
return;
}
auto &vmp_rtn = rtn->vmp_rtns.back();
if ( vm_code_block.jcc.type == vm::instrs::jcc_type::branching )
switch ( vm_code_block.jcc.type )
{
case 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();
@ -38,8 +43,9 @@ namespace vm
"[!] fatal error... unable to locate basic block for branching...\n" );
ir_builder->CreateCondBr( cmp, bb1->second, bb2->second );
break;
}
else
case vm::instrs::jcc_type::absolute:
{
auto rva = rtn->pop( 8 );
auto bb_data =
@ -52,6 +58,15 @@ namespace vm
"[!] fatal error... unable to locate basic block...\n" );
ir_builder->CreateBr( bb_data->second );
break;
}
case vm::instrs::jcc_type::switch_case:
{
// TODO: add switch case support here...
break;
}
default:
break;
}
};
}
} // namespace vm

@ -32,6 +32,12 @@ namespace vm
rtn->push( 4, llvm::ConstantInt::get( ir_builder->getInt32Ty(), vinstr.operand.imm.u ) );
};
lifters_t::lifter_callback_t lifters_t::lconstw =
[ & ]( 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 ) );
};
lifters_t::lifter_callback_t lifters_t::lconstwsxdw =
[ & ]( vm::devirt_t *rtn, const vm::instrs::code_block_t &vm_code_block, const vm::instrs::virt_instr_t &vinstr,
llvm::IRBuilder<> *ir_builder ) {

@ -0,0 +1,40 @@
#include <vm_lifters.hpp>
namespace vm
{
lifters_t::lifter_callback_t lifters_t::mulq =
[ & ]( 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 );
// TODO: this is wrong... still need to do some more research into this...
auto t3 = ir_builder->CreateMul( t1, t2 );
auto t4 = ir_builder->CreateAShr( t3, llvm::APInt( 64, 32 ) );
auto t5 = ir_builder->CreateAnd( t3, 0xFFFFFFFF00000000 );
rtn->push( 8, t4 );
rtn->push( 8, t5 );
// TODO: compute flags for IMULQ
auto &vmp_rtn = rtn->vmp_rtns.back();
rtn->push( 8, rtn->load_value( 8, vmp_rtn->flags ) );
};
lifters_t::lifter_callback_t lifters_t::muldw =
[ & ]( 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 );
// TODO: this is wrong... still need to do some more research into this...
auto t3 = ir_builder->CreateMul( t1, t2 );
auto t4 = ir_builder->CreateAShr( t3, llvm::APInt( 32, 16 ) );
auto t5 = ir_builder->CreateAnd( t3, 0xFFFF0000 );
rtn->push( 4, t4 );
rtn->push( 4, t5 );
// TODO: compute flags for IMULQ
auto &vmp_rtn = rtn->vmp_rtns.back();
rtn->push( 8, rtn->load_value( 8, vmp_rtn->flags ) );
};
}

@ -51,6 +51,24 @@ namespace vm
rtn->push( 8, rtn->load_value( 8, vmp_rtn->flags ) );
};
lifters_t::lifter_callback_t lifters_t::nandw =
[ & ]( 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 t1_not = ir_builder->CreateNot( t1 );
auto t2_not = ir_builder->CreateNot( t2 );
auto t3 = ir_builder->CreateAnd( { t1_not, t2_not } );
rtn->push( 2, t3 );
auto &vmp_rtn = rtn->vmp_rtns.back();
auto flags = and_flags( rtn, 2, t3 );
ir_builder->CreateStore( flags, vmp_rtn->flags );
rtn->push( 8, rtn->load_value( 8, vmp_rtn->flags ) );
};
lifters_t::lifter_callback_t lifters_t::nandb =
[ & ]( vm::devirt_t *rtn, const vm::instrs::code_block_t &vm_code_block, const vm::instrs::virt_instr_t &vinstr,
llvm::IRBuilder<> *ir_builder ) {

@ -2,7 +2,7 @@
namespace vm
{
lifters_t::lifter_callback_t lifters_t::pushvsp =
lifters_t::lifter_callback_t lifters_t::pushvspq =
[ & ]( 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();
@ -10,4 +10,13 @@ namespace vm
auto stack_ptr = ir_builder->CreatePtrToInt( stack, ir_builder->getInt64Ty() );
rtn->push( 8, stack_ptr );
};
}
lifters_t::lifter_callback_t lifters_t::pushvspdw =
[ & ]( 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->getInt32Ty() );
rtn->push( 4, stack_ptr );
};
} // namespace vm

@ -0,0 +1,28 @@
#include <vm_lifters.hpp>
namespace vm
{
lifters_t::lifter_callback_t lifters_t::rdtsc =
[ & ]( vm::devirt_t *rtn, const vm::instrs::code_block_t &vm_code_block, const vm::instrs::virt_instr_t &vinstr,
llvm::IRBuilder<> *ir_builder ) {
llvm::Function *rdtsc_intrin = nullptr;
if ( !( rdtsc_intrin = rtn->llvm_module->getFunction( "rdtsc" ) ) )
{
rdtsc_intrin = llvm::Function::Create( llvm::FunctionType::get( ir_builder->getVoidTy(), false ),
llvm::GlobalValue::LinkageTypes::ExternalLinkage, "rdtsc",
*rtn->llvm_module );
auto entry_block = llvm::BasicBlock::Create( ir_builder->getContext(), "", rdtsc_intrin );
auto ib = ir_builder->GetInsertBlock();
ir_builder->SetInsertPoint( entry_block );
// TODO: put RDTSC code here...
ir_builder->CreateRetVoid();
ir_builder->SetInsertPoint( ib );
}
auto &vmp_rtn = rtn->vmp_rtns.back();
ir_builder->CreateCall( rdtsc_intrin );
};
}

@ -3,8 +3,8 @@
namespace vm
{
lifters_t::lifter_callback_t lifters_t::readq =
[ & ]( vm::devirt_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 t2 = ir_builder->CreateIntToPtr( t1, llvm::PointerType::get( ir_builder->getInt64Ty(), 0ull ) );
auto t3 = ir_builder->CreateLoad( ir_builder->getInt64Ty(), t2 );
@ -12,11 +12,30 @@ namespace vm
};
lifters_t::lifter_callback_t lifters_t::readdw =
[ & ]( vm::devirt_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 t2 = ir_builder->CreateIntToPtr( t1, llvm::PointerType::get( ir_builder->getInt32Ty(), 0ull ) );
auto t3 = ir_builder->CreateLoad( ir_builder->getInt32Ty(), t2 );
rtn->push( 4, t3 );
};
lifters_t::lifter_callback_t lifters_t::readw =
[ & ]( 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->getInt16Ty(), 0ull ) );
auto t3 = ir_builder->CreateLoad( ir_builder->getInt16Ty(), t2 );
rtn->push( 2, t3 );
};
lifters_t::lifter_callback_t lifters_t::readb =
[ & ]( 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->getInt8Ty(), 0ull ) );
auto t3 = ir_builder->CreateLoad( ir_builder->getInt8Ty(), t2 );
auto t4 = ir_builder->CreateIntCast( t3, ir_builder->getInt16Ty(), false );
rtn->push( 2, t4 );
};
} // namespace vm

@ -0,0 +1,30 @@
#include <vm_lifters.hpp>
namespace vm
{
lifters_t::lifter_callback_t lifters_t::readcr3 =
[ & ]( vm::devirt_t *rtn, const vm::instrs::code_block_t &vm_code_block, const vm::instrs::virt_instr_t &vinstr,
llvm::IRBuilder<> *ir_builder ) {
llvm::Function *readcr3_intrin = nullptr;
if ( !( readcr3_intrin = rtn->llvm_module->getFunction( "readcr3" ) ) )
{
readcr3_intrin = llvm::Function::Create( llvm::FunctionType::get( ir_builder->getInt64Ty(), false ),
llvm::GlobalValue::LinkageTypes::ExternalLinkage, "readcr3",
*rtn->llvm_module );
auto entry_block = llvm::BasicBlock::Create( ir_builder->getContext(), "", readcr3_intrin );
auto ib = ir_builder->GetInsertBlock();
ir_builder->SetInsertPoint( entry_block );
std::string asm_str( "mov rax, cr3; ret" );
auto intrin = llvm::InlineAsm::get( llvm::FunctionType::get( ir_builder->getVoidTy(), false ), asm_str,
"", false, false, llvm::InlineAsm::AD_Intel );
ir_builder->CreateCall( intrin );
ir_builder->CreateRet( llvm::ConstantInt::get( *rtn->llvm_ctx, llvm::APInt( 64, 0 ) ) );
ir_builder->SetInsertPoint( ib );
}
auto t1 = ir_builder->CreateCall( readcr3_intrin );
rtn->push( 8, t1 );
};
}

@ -0,0 +1,30 @@
#include <vm_lifters.hpp>
namespace vm
{
lifters_t::lifter_callback_t lifters_t::readcr8 =
[ & ]( vm::devirt_t *rtn, const vm::instrs::code_block_t &vm_code_block, const vm::instrs::virt_instr_t &vinstr,
llvm::IRBuilder<> *ir_builder ) {
llvm::Function *readcr8_intrin = nullptr;
if ( !( readcr8_intrin = rtn->llvm_module->getFunction( "readcr8" ) ) )
{
readcr8_intrin = llvm::Function::Create( llvm::FunctionType::get( ir_builder->getInt64Ty(), false ),
llvm::GlobalValue::LinkageTypes::ExternalLinkage, "readcr8",
*rtn->llvm_module );
auto entry_block = llvm::BasicBlock::Create( ir_builder->getContext(), "", readcr8_intrin );
auto ib = ir_builder->GetInsertBlock();
ir_builder->SetInsertPoint( entry_block );
std::string asm_str( "mov rax, cr8; ret" );
auto intrin = llvm::InlineAsm::get( llvm::FunctionType::get( ir_builder->getVoidTy(), false ), asm_str,
"", false, false, llvm::InlineAsm::AD_Intel );
ir_builder->CreateCall( intrin );
ir_builder->CreateRet( llvm::ConstantInt::get( *rtn->llvm_ctx, llvm::APInt( 64, 0 ) ) );
ir_builder->SetInsertPoint( ib );
}
auto t1 = ir_builder->CreateCall( readcr8_intrin );
rtn->push( 8, t1 );
};
}

@ -0,0 +1,32 @@
#include <vm_lifters.hpp>
namespace vm
{
lifters_t::lifter_callback_t lifters_t::readgsq =
[ & ]( vm::devirt_t *rtn, const vm::instrs::code_block_t &vm_code_block, const vm::instrs::virt_instr_t &vinstr,
llvm::IRBuilder<> *ir_builder ) {
llvm::Function *readgs_intrin = nullptr;
if ( !( readgs_intrin = rtn->llvm_module->getFunction( "readgs" ) ) )
{
readgs_intrin = llvm::Function::Create(
llvm::FunctionType::get( ir_builder->getInt64Ty(), { ir_builder->getInt64Ty() }, false ),
llvm::GlobalValue::LinkageTypes::ExternalLinkage, "readgs", *rtn->llvm_module );
auto entry_block = llvm::BasicBlock::Create( ir_builder->getContext(), "", readgs_intrin );
auto ib = ir_builder->GetInsertBlock();
ir_builder->SetInsertPoint( entry_block );
std::string asm_str( "mov rax, gs:[rcx]; ret" );
auto intrin = llvm::InlineAsm::get( llvm::FunctionType::get( ir_builder->getVoidTy(), false ), asm_str,
"", false, false, llvm::InlineAsm::AD_Intel );
ir_builder->CreateCall( intrin );
ir_builder->CreateRet( llvm::ConstantInt::get( *rtn->llvm_ctx, llvm::APInt( 64, 0 ) ) );
ir_builder->SetInsertPoint( ib );
}
auto t1 = rtn->pop( 8 );
auto t2 = ir_builder->CreateCall( readgs_intrin, { t1 } );
rtn->push( 8, t2 );
};
} // namespace vm

@ -0,0 +1,50 @@
#include <vm_lifters.hpp>
namespace vm
{
lifters_t::lifter_callback_t lifters_t::shlq =
[ & ]( 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->CreateShl( t1, t3 );
auto &vmp_rtn = rtn->vmp_rtns.back();
// TODO: update rflags...
rtn->push( 8, t4 );
rtn->push( 8, rtn->load_value( 8, vmp_rtn->flags ) );
};
lifters_t::lifter_callback_t lifters_t::shldw =
[ & ]( 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( 2 );
auto t3 = ir_builder->CreateIntCast( t2, llvm::IntegerType::get( *rtn->llvm_ctx, 32 ), false );
auto t4 = ir_builder->CreateShl( t1, t3 );
auto &vmp_rtn = rtn->vmp_rtns.back();
// TODO: update rflags...
rtn->push( 4, t4 );
rtn->push( 8, rtn->load_value( 8, vmp_rtn->flags ) );
};
lifters_t::lifter_callback_t lifters_t::shlb =
[ & ]( 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->CreateIntCast( t1, ir_builder->getInt8Ty(), false );
auto t4 = ir_builder->CreateIntCast( t2, ir_builder->getInt8Ty(), false );
auto t5 = ir_builder->CreateShl( t3, t4 );
auto &vmp_rtn = rtn->vmp_rtns.back();
// TODO: update rflags...
rtn->push( 2, ir_builder->CreateIntCast( t5, ir_builder->getInt16Ty(), false ) );
rtn->push( 8, rtn->load_value( 8, vmp_rtn->flags ) );
};
} // namespace vm

@ -0,0 +1,38 @@
#include <vm_lifters.hpp>
namespace vm
{
lifters_t::lifter_callback_t lifters_t::shldq =
[ & ]( 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 = rtn->pop( 2 );
// TODO: this is wrong - replace with more logic!
auto t4 = ir_builder->CreateShl( t1, ir_builder->CreateIntCast( t3, ir_builder->getInt64Ty(), false ) );
rtn->push( 8, t4 );
auto &vmp_rtn = rtn->vmp_rtns.back();
// TODO: update rflags...
rtn->push( 8, rtn->load_value( 8, vmp_rtn->flags ) );
};
lifters_t::lifter_callback_t lifters_t::shlddw =
[ & ]( 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 = rtn->pop( 2 );
// TODO: this is wrong - replace with more logic!
auto t4 = ir_builder->CreateShl( t1, ir_builder->CreateIntCast( t3, ir_builder->getInt32Ty(), false ) );
rtn->push( 4, t4 );
auto &vmp_rtn = rtn->vmp_rtns.back();
// TODO: update rflags...
rtn->push( 8, rtn->load_value( 8, vmp_rtn->flags ) );
};
} // namespace vm

@ -2,7 +2,6 @@
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::devirt_t *rtn, std::uint8_t byte_size, llvm::Value *lhs, llvm::Value *rhs,
llvm::Value *result )
{
@ -10,19 +9,18 @@ namespace vm
auto msb = rtn->ir_builder->CreateLShr( lhs, ( byte_size * 8 ) - 1 );
auto cf = rtn->ir_builder->CreateZExt( msb, llvm::IntegerType::get( *rtn->llvm_ctx, 64 ) );
auto of =
rtn->sf( byte_size, lhs ); // we reuse the compute_sf helper since the flag expression is the same
auto of = rtn->sf( byte_size, lhs );
auto sf = rtn->sf( byte_size, result );
auto zf = rtn->zf( byte_size, result );
auto pf = llvm::ConstantInt::get( llvm::IntegerType::get( *rtn->llvm_ctx, 64 ), 0 );
return rtn->flags( cf, pf, llvm::ConstantInt::get( llvm::IntegerType::get( *rtn->llvm_ctx, 64 ), 0 ),
zf, sf, of );
return rtn->flags( cf, pf, llvm::ConstantInt::get( llvm::IntegerType::get( *rtn->llvm_ctx, 64 ), 0 ), zf, sf,
of );
}
lifters_t::lifter_callback_t lifters_t::shrq =
[ & ]( vm::devirt_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 t2 = rtn->pop( 2 );
auto t3 = ir_builder->CreateIntCast( t2, llvm::IntegerType::get( *rtn->llvm_ctx, 64 ), false );
@ -34,4 +32,49 @@ namespace vm
rtn->push( 8, t4 );
rtn->push( 8, rtn->load_value( 8, vmp_rtn->flags ) );
};
lifters_t::lifter_callback_t lifters_t::shrdw =
[ & ]( 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( 2 );
auto t3 = ir_builder->CreateIntCast( t2, llvm::IntegerType::get( *rtn->llvm_ctx, 32 ), false );
auto t4 = ir_builder->CreateLShr( t1, t3 );
auto &vmp_rtn = rtn->vmp_rtns.back();
auto flags = lifters_t::shr_flags( rtn, 4, t1, t3, t4 );
ir_builder->CreateStore( flags, vmp_rtn->flags );
rtn->push( 4, t4 );
rtn->push( 8, rtn->load_value( 8, vmp_rtn->flags ) );
};
lifters_t::lifter_callback_t lifters_t::shrw =
[ & ]( 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->CreateLShr( t1, t2 );
auto &vmp_rtn = rtn->vmp_rtns.back();
auto flags = lifters_t::shr_flags( rtn, 2, t1, t2, t3 );
ir_builder->CreateStore( flags, vmp_rtn->flags );
rtn->push( 2, t3 );
rtn->push( 8, rtn->load_value( 8, vmp_rtn->flags ) );
};
lifters_t::lifter_callback_t lifters_t::shrb =
[ & ]( 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->CreateIntCast( t1, ir_builder->getInt8Ty(), false );
auto t4 = ir_builder->CreateIntCast( t2, ir_builder->getInt8Ty(), false );
auto t5 = ir_builder->CreateLShr( t3, t4 );
auto &vmp_rtn = rtn->vmp_rtns.back();
auto flags = lifters_t::shr_flags( rtn, 1, t3, t4, t5 );
ir_builder->CreateStore( flags, vmp_rtn->flags );
rtn->push( 2, ir_builder->CreateIntCast( t5, ir_builder->getInt16Ty(), false ) );
rtn->push( 8, rtn->load_value( 8, vmp_rtn->flags ) );
};
} // namespace vm

@ -0,0 +1,38 @@
#include <vm_lifters.hpp>
namespace vm
{
lifters_t::lifter_callback_t lifters_t::shrdq =
[ & ]( 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 = rtn->pop( 2 );
// TODO: this is wrong - replace with more logic!
auto t4 = ir_builder->CreateLShr( t1, ir_builder->CreateIntCast( t3, ir_builder->getInt64Ty(), false ) );
rtn->push( 8, t4 );
auto &vmp_rtn = rtn->vmp_rtns.back();
// TODO: update rflags...
rtn->push( 8, rtn->load_value( 8, vmp_rtn->flags ) );
};
lifters_t::lifter_callback_t lifters_t::shrddw =
[ & ]( 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 = rtn->pop( 2 );
// TODO: this is wrong - replace with more logic!
auto t4 = ir_builder->CreateLShr( t1, ir_builder->CreateIntCast( t3, ir_builder->getInt32Ty(), false ) );
rtn->push( 4, t4 );
auto &vmp_rtn = rtn->vmp_rtns.back();
// TODO: update rflags...
rtn->push( 8, rtn->load_value( 8, vmp_rtn->flags ) );
};
} // namespace vm

@ -20,6 +20,17 @@ namespace vm
ir_builder->CreateStore( ir_builder->CreateIntCast( t1, ir_builder->getInt64Ty(), false ), vreg );
};
lifters_t::lifter_callback_t lifters_t::sregw =
[ & ]( 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 &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(
ir_builder->CreateIntCast( t1, ir_builder->getInt16Ty(), false ),
ir_builder->CreatePointerCast( vreg, llvm::PointerType::get( ir_builder->getInt16Ty(), 0ull ) ) );
};
lifters_t::lifter_callback_t lifters_t::sregb =
[ & ]( vm::devirt_t *rtn, const vm::instrs::code_block_t &vm_code_block, const vm::instrs::virt_instr_t &vinstr,
llvm::IRBuilder<> *ir_builder ) {

@ -10,4 +10,32 @@ namespace vm
auto t3 = ir_builder->CreateIntToPtr( t1, llvm::PointerType::get( ir_builder->getInt64Ty(), 0ull ) );
ir_builder->CreateStore( t2, t3 );
};
lifters_t::lifter_callback_t lifters_t::writedw =
[ & ]( 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( 4 );
auto t3 = ir_builder->CreateIntToPtr( t1, llvm::PointerType::get( ir_builder->getInt32Ty(), 0ull ) );
ir_builder->CreateStore( t2, t3 );
};
lifters_t::lifter_callback_t lifters_t::writew =
[ & ]( 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->CreateIntToPtr( t1, llvm::PointerType::get( ir_builder->getInt16Ty(), 0ull ) );
ir_builder->CreateStore( t2, t3 );
};
lifters_t::lifter_callback_t lifters_t::writeb =
[ & ]( 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->CreateIntToPtr( t1, llvm::PointerType::get( ir_builder->getInt8Ty(), 0ull ) );
auto t4 = ir_builder->CreateIntCast( t2, ir_builder->getInt8Ty(), false );
ir_builder->CreateStore( t4, t3 );
};
} // namespace vm

@ -0,0 +1,31 @@
#include <vm_lifters.hpp>
namespace vm
{
lifters_t::lifter_callback_t lifters_t::writecr3 =
[ & ]( vm::devirt_t *rtn, const vm::instrs::code_block_t &vm_code_block, const vm::instrs::virt_instr_t &vinstr,
llvm::IRBuilder<> *ir_builder ) {
llvm::Function *writecr3_intrin = nullptr;
if ( !( writecr3_intrin = rtn->llvm_module->getFunction( "writecr3" ) ) )
{
writecr3_intrin = llvm::Function::Create(
llvm::FunctionType::get( ir_builder->getVoidTy(), { ir_builder->getInt64Ty() }, false ),
llvm::GlobalValue::LinkageTypes::ExternalLinkage, "writecr3", *rtn->llvm_module );
auto entry_block = llvm::BasicBlock::Create( ir_builder->getContext(), "", writecr3_intrin );
auto ib = ir_builder->GetInsertBlock();
ir_builder->SetInsertPoint( entry_block );
std::string asm_str( "mov cr3, rcx; ret" );
auto intrin = llvm::InlineAsm::get(
llvm::FunctionType::get( ir_builder->getVoidTy(), false ), asm_str,
"", false, false, llvm::InlineAsm::AD_Intel );
ir_builder->CreateCall( intrin );
ir_builder->CreateRetVoid();
ir_builder->SetInsertPoint( ib );
}
auto t1 = rtn->pop( 8 );
ir_builder->CreateCall( writecr3_intrin, { t1 } );
};
}

@ -60,6 +60,9 @@ int main( int argc, const char *argv[] )
for ( auto &[ vm_enter_offset, vmp2_code_blocks ] : virt_rtns )
{
if ( vmp2_code_blocks.empty() )
continue;
if ( !vmp_devirt.lift( vm_enter_offset + file_header->image_base, vmp2_code_blocks ) )
{
std::printf( "[!] failed to lift rtn_0x%p, please review the console...\n",
@ -67,6 +70,8 @@ int main( int argc, const char *argv[] )
return -1;
}
std::printf( "> lifted rtn_0x%p\n", vm_enter_offset + file_header->image_base );
}
llvm::LLVMInitializeX86TargetInfo();

Loading…
Cancel
Save