Merge branch '_xeroxz' into 'master'

added all of the code to append obj files to pe files...

See merge request vmp2/vmdevirt!9
merge-requests/10/merge
_xeroxz 3 years ago
commit 48590259c4

@ -1,10 +1,18 @@
#include <vmprofiler.hpp>
#include <coff/image.hpp>
#include <iostream>
#include <sstream>
#include <string>
#define VM_ENTER_NAME "vmenter_"
#define VM_EXIT_NAME "vmexit_"
#define VM_RTN_NAME "rtn_"
#define FIX_MAKE_ZERO_OFFSET 0x25
#define FIX_MAKE_RELOC_OFFSET 0x30
#define FIX_MAKE_JMP_OFFSET 0x43
namespace devirt
{
namespace util

@ -14,15 +14,17 @@ namespace vm
// sub rsp, num_bytes
auto current_rtn = vmp_rtns.back();
auto rsp_addr = ir_builder->CreateLoad( current_rtn->stack );
rsp_addr->setAlignment( llvm::Align( 1 ) );
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 );
ir_builder->CreateStore( sub_rsp_val, current_rtn->stack )->setAlignment( llvm::Align( 1 ) );
// 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 );
ir_builder->CreateStore( val, resized_new_rsp_addr )->setAlignment( llvm::Align( 1 ) );
}
llvm::Value *devirt_t::pop( std::uint8_t num_bytes )
@ -30,14 +32,20 @@ namespace vm
// mov rax, [rsp]
auto current_rtn = vmp_rtns.back();
auto rsp_addr = ir_builder->CreateLoad( current_rtn->stack );
rsp_addr->setAlignment( llvm::Align( 1 ) );
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 );
pop_val->setAlignment( llvm::Align( 1 ) );
ir_builder->CreateStore( new_rsp_addr, current_rtn->stack )->setAlignment( llvm::Align( 1 ) );
ir_builder->CreateStore( llvm::UndefValue::get( ir_builder->getInt8Ty() ), rsp_addr )
->setAlignment( llvm::Align( 1 ) );
return pop_val;
}
@ -48,9 +56,14 @@ namespace vm
auto cast_ptr = ir_builder->CreatePointerCast(
var, llvm::PointerType::get( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), 0 ) );
return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), cast_ptr );
auto result = ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), cast_ptr );
result->setAlignment( llvm::Align( 1 ) );
return result;
}
return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), var );
auto result = ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), var );
result->setAlignment( llvm::Align( 1 ) );
return result;
}
llvm::Value *devirt_t::load_value( std::uint8_t byte_size, llvm::AllocaInst *var )
@ -60,9 +73,14 @@ namespace vm
auto cast_ptr = ir_builder->CreatePointerCast(
var, llvm::PointerType::get( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), 0 ) );
return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), cast_ptr );
auto result = ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), cast_ptr );
result->setAlignment( llvm::Align( 1 ) );
return result;
}
return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), var );
auto result = ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), var );
result->setAlignment( llvm::Align( 1 ) );
return result;
}
bool devirt_t::compile( std::vector< std::uint8_t > &obj )
@ -170,7 +188,7 @@ namespace vm
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 ) );
return ir_builder->CreateOr( or5, llvm::ConstantInt::get( llvm::IntegerType::get( *llvm_ctx, 64 ), 514 ) );
}
} // namespace vm

@ -57,12 +57,169 @@ namespace devirt
if ( obj.empty() || bin.empty() )
return false;
// TODO: append a new section to the pe file...
// put the entire obj file into this new section...
// fix up the vmenter functions to jmp to their respective devirtualized routines...
//
// move relocation directory to the end of the module and append new relocations...
// export all of the new devirtualized/llvm generated functions...
std::vector< std::uint8_t > map_buff;
auto bin_img = reinterpret_cast< win::image_t<> * >( bin.data() );
// increase the size_image by the size of the obj as the entire obj will be in the .devirt section...
map_buff.resize(
reinterpret_cast< win::image_t<> * >( bin.data() )->get_nt_headers()->optional_header.size_image +=
obj.size() );
// copy over dos headers, pe headers (section headers, optional header etc)...
std::memcpy( map_buff.data(), bin.data(), bin_img->get_nt_headers()->optional_header.size_headers );
// map sections into map_img... also make image offset == virtual offset...
auto map_img = reinterpret_cast< win::image_t<> * >( map_buff.data() );
std::for_each( bin_img->get_nt_headers()->get_sections(),
bin_img->get_nt_headers()->get_sections() + bin_img->get_file_header()->num_sections,
[ & ]( coff::section_header_t &section ) {
if ( !section.virtual_address || !section.ptr_raw_data )
return;
std::memcpy( map_buff.data() + section.virtual_address, bin.data() + section.ptr_raw_data,
section.size_raw_data );
} );
std::for_each( map_img->get_nt_headers()->get_sections(),
map_img->get_nt_headers()->get_sections() + bin_img->get_file_header()->num_sections,
[ & ]( coff::section_header_t &section ) {
section.ptr_raw_data = section.virtual_address;
section.size_raw_data = section.virtual_size;
} );
auto pe_sections = map_img->get_nt_headers()->get_sections();
auto num_sections = map_img->get_file_header()->num_sections;
// append .devirt section to the original binary...
strcpy( pe_sections[ num_sections ].name.short_name, ".devirt" );
pe_sections[ num_sections ].virtual_size = obj.size();
pe_sections[ num_sections ].size_raw_data = obj.size();
pe_sections[ num_sections ].virtual_address = ( pe_sections[ num_sections - 1 ].virtual_address +
pe_sections[ num_sections - 1 ].virtual_size + 0x1000 ) &
~0xFFFull;
pe_sections[ num_sections ].ptr_raw_data = pe_sections[ num_sections ].virtual_address;
coff::section_characteristics_t prots;
prots.flags = 0ull;
prots.mem_execute = true;
prots.mem_read = true;
pe_sections[ num_sections ].characteristics = prots;
++map_img->get_file_header()->num_sections;
std::memcpy( map_buff.data() + pe_sections[ num_sections ].virtual_address, obj.data(), obj.size() );
auto obj_img_addr = map_buff.data() + pe_sections[ num_sections ].virtual_address;
auto obj_img = reinterpret_cast< coff::image_t * >( obj_img_addr );
auto str_table = obj_img->get_strings();
auto symbols = obj_img->get_symbols();
auto obj_sections = obj_img->get_sections();
auto symbol_cnt = obj_img->file_header.num_symbols;
static const auto get_symbol = [ & ]( std::string symbol_name ) -> auto
{
return std::find_if( symbols, symbols + symbol_cnt, [ & ]( coff::symbol_t &symbol ) {
if ( symbol.derived_type != coff::derived_type_id::function )
return false;
return !strcmp( symbol.name.to_string( str_table ).data(), symbol_name.c_str() );
} );
};
std::vector< std::pair< std::uint32_t, std::uint16_t > > new_relocs;
std::for_each( symbols, symbols + symbol_cnt, [ & ]( coff::symbol_t &symbol ) {
if ( symbol.derived_type != coff::derived_type_id::function )
return;
auto symbol_name = symbol.name.to_string( str_table );
if ( strstr( symbol_name.data(), VM_ENTER_NAME ) )
{
// fix 0x1000000000000000 to 0x0000000000000000
// also push back a new relocation for this entry...
auto symbol_addr = reinterpret_cast< std::uintptr_t >( obj_img_addr ) + symbol.value +
obj_sections[ symbol.section_index - 1 ].ptr_raw_data;
*reinterpret_cast< std::uintptr_t * >( symbol_addr + FIX_MAKE_ZERO_OFFSET ) = 0ull;
*reinterpret_cast< std::uintptr_t * >( symbol_addr + FIX_MAKE_RELOC_OFFSET ) = 0ull;
auto page = ( symbol.value + obj_sections[ symbol.section_index - 1 ].ptr_raw_data +
FIX_MAKE_RELOC_OFFSET + pe_sections[ num_sections ].virtual_address ) &
~0xFFFull;
auto offset = ( symbol.value + obj_sections[ symbol.section_index - 1 ].ptr_raw_data +
FIX_MAKE_RELOC_OFFSET + pe_sections[ num_sections ].virtual_address ) &
0xFFFull;
new_relocs.push_back( { page, offset } );
// look up the rtn_xxxxxx function symbol for this vm enter and make it jmp to it...
auto rtn_offset = std::stoull( symbol_name.data() + sizeof( VM_ENTER_NAME ) - 1, nullptr, 16 );
std::stringstream rtn_name;
rtn_name << "rtn_" << std::hex << rtn_offset;
auto rtn_sym = get_symbol( rtn_name.str() );
auto relocs = reinterpret_cast< coff::reloc_t * >(
obj_sections[ rtn_sym->section_index - 1 ].ptr_relocs + obj_img_addr );
auto rtn_rva = rtn_offset - map_img->get_nt_headers()->optional_header.image_base;
std::int32_t devirt_rtn_rva = symbol_addr - reinterpret_cast< std::uintptr_t >( map_buff.data() );
*reinterpret_cast< std::int32_t * >( rtn_rva + map_buff.data() + 1 ) = devirt_rtn_rva - ( rtn_rva + 5 );
*reinterpret_cast< std::uint8_t * >( rtn_rva + map_buff.data() ) = 0xE9;
// apply relocations to the rtn_xxxxx...
for ( auto reloc_idx = 0u; reloc_idx < obj_sections[ rtn_sym->section_index - 1 ].num_relocs;
++reloc_idx )
{
coff::reloc_t &reloc = relocs[ reloc_idx ];
auto vmexit_sym =
get_symbol( std::string( symbols[ reloc.symbol_index ].name.to_string( str_table ) ) );
auto vmexit_offset = vmexit_sym->value + obj_sections[ vmexit_sym->section_index - 1 ].ptr_raw_data;
auto reloc_file_offset =
reloc.virtual_address + obj_sections[ rtn_sym->section_index - 1 ].ptr_raw_data;
std::int32_t rva = vmexit_offset - ( std::int32_t )( reloc_file_offset + 4 );
*reinterpret_cast< std::int32_t * >( obj_img_addr + reloc_file_offset ) = rva;
}
auto rtn_addr = reinterpret_cast< std::uintptr_t >(
obj_img_addr + obj_sections[ rtn_sym->section_index - 1 ].ptr_raw_data + rtn_sym->value );
// create jmp to the rtn_xxxxx....
std::int32_t rva = rtn_addr - ( std::int64_t )( symbol_addr + FIX_MAKE_JMP_OFFSET + 5 );
*reinterpret_cast< std::uint8_t * >( symbol_addr + FIX_MAKE_JMP_OFFSET ) = 0xE9;
*reinterpret_cast< std::int32_t * >( symbol_addr + FIX_MAKE_JMP_OFFSET + 1 ) = rva;
}
} );
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() );
return true;
}
} // namespace devirt

@ -3,50 +3,50 @@
namespace vm
{
lifters_t::lifter_callback_t lifters_t::lconstq =
[ & ]( 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 ) {
rtn->push( 8, llvm::ConstantInt::get( ir_builder->getInt64Ty(), vinstr.operand.imm.u ) );
};
lifters_t::lifter_callback_t lifters_t::lconstdwsxq =
[ & ]( 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 ) {
rtn->push( 8, llvm::ConstantInt::get( ir_builder->getInt64Ty(), vinstr.operand.imm.u ) );
};
lifters_t::lifter_callback_t lifters_t::lconstwsxq =
[ & ]( 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 ) {
rtn->push( 8, llvm::ConstantInt::get( ir_builder->getInt64Ty(), vinstr.operand.imm.u ) );
};
lifters_t::lifter_callback_t lifters_t::lconstbsxq =
[ & ]( 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 ) {
rtn->push( 8, llvm::ConstantInt::get( ir_builder->getInt64Ty(), vinstr.operand.imm.u ) );
};
lifters_t::lifter_callback_t lifters_t::lconstdw =
[ & ]( 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 ) {
rtn->push( 4, llvm::ConstantInt::get( ir_builder->getInt32Ty(), 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 ) {
[ & ]( 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::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 ) {
rtn->push( 4, llvm::ConstantInt::get( ir_builder->getInt32Ty(), vinstr.operand.imm.u ) );
};
lifters_t::lifter_callback_t lifters_t::lconstbzxw =
[ & ]( 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 ) {
rtn->push( 2, llvm::ConstantInt::get( ir_builder->getInt16Ty(), vinstr.operand.imm.u ) );
};
} // namespace vm

@ -17,8 +17,6 @@ namespace vm
auto t1 = rtn->pop( 4 );
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 );
ir_builder->CreateStore( ir_builder->CreateIntCast( t1, ir_builder->getInt64Ty(), false ), vreg );
};
} // namespace vm

@ -8,6 +8,8 @@ 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..." );
parser.add_argument().name( "--out" ).required( true ).description( "output devirtualized binary name..." );
parser.add_argument().name( "--genobj" ).description( "write the generated obj file to disk..." );
parser.add_argument().name( "--bin" ).required( true ).description(
"path to the image in which to apply devirtualized code too...\n" );
@ -77,9 +79,12 @@ int main( int argc, const char *argv[] )
vmp_devirt.compile( compiled_obj );
std::printf( "> compiled all routines... compiled obj size = %d\n", compiled_obj.size() );
std::ofstream( "devirt.o", std::ios::binary )
.write( reinterpret_cast< const char * >( compiled_obj.data() ), compiled_obj.size() );
if ( parser.exists( "genobj" ) )
std::ofstream( parser.get< std::string >( "out" ).append( ".o" ), std::ios::binary )
.write( reinterpret_cast< const char * >( compiled_obj.data() ), compiled_obj.size() );
devirt::append( compiled_obj, bin );
std::ofstream( "devirt.exe", std::ios::binary ).write( reinterpret_cast< const char * >( bin.data() ), bin.size() );
std::ofstream( parser.get< std::string >( "out" ), std::ios::binary )
.write( reinterpret_cast< const char * >( bin.data() ), bin.size() );
}

@ -79,7 +79,7 @@ namespace vm
}
rtn_name.str( "" );
asm_str.append( "mov rcx, rsp; sub rsp, 0xA00; " );
asm_str.append( "mov rcx, rsp; sub rsp, 0xA00; int 3; int 3; int 3; int 3; int 3;" );
rtn_name << "vmenter_" << std::hex << rtn_begin;
auto entry_func = llvm::Function::Create( llvm::FunctionType::get( ir_builder->getVoidTy(), false ),

Loading…
Cancel
Save