Compare commits
60 Commits
Author | SHA1 | Date |
---|---|---|
IDontCode | 7fa5bb91a6 | 2 years ago |
_xeroxz | ecccbf4172 | 3 years ago |
_xeroxz | eefb1b5480 | 3 years ago |
_xeroxz | 18e0fceeed | 3 years ago |
_xeroxz | 732fe16864 | 3 years ago |
_xeroxz | 26e2524379 | 3 years ago |
_xeroxz | 09a59453c2 | 3 years ago |
_xeroxz | fd6ddce1d6 | 3 years ago |
_xeroxz | 18392717e4 | 3 years ago |
_xeroxz | 2d6c911ab4 | 3 years ago |
_xeroxz | 1f2d10353b | 3 years ago |
_xeroxz | 680edc4faf | 3 years ago |
_xeroxz | 64e4838d6d | 3 years ago |
_xeroxz | a8fef83c95 | 3 years ago |
_xeroxz | 8a5bf9e8ab | 3 years ago |
_xeroxz | 5775d5ae65 | 3 years ago |
_xeroxz | aaf0e9defe | 3 years ago |
_xeroxz | b82072e2ed | 3 years ago |
_xeroxz | d2da38cad1 | 3 years ago |
_xeroxz | 014c1a08cd | 3 years ago |
_xeroxz | 65ae6ebe02 | 3 years ago |
_xeroxz | ea078d9847 | 3 years ago |
_xeroxz | 93402767a9 | 3 years ago |
_xeroxz | 4fe8c63f49 | 3 years ago |
_xeroxz | ebbe93f278 | 3 years ago |
_xeroxz | 661bc3bc16 | 3 years ago |
_xeroxz | a2b532cfff | 3 years ago |
_xeroxz | c84c28ffd0 | 3 years ago |
_xeroxz | cfb244c93c | 3 years ago |
_xeroxz | 48590259c4 | 3 years ago |
_xeroxz | 4d7bf0d94c | 3 years ago |
_xeroxz | 92bd54c368 | 3 years ago |
_xeroxz | 8217c63389 | 3 years ago |
_xeroxz | 28f44ed761 | 3 years ago |
_xeroxz | 11b6bce49b | 3 years ago |
_xeroxz | d94ff6126d | 3 years ago |
_xeroxz | 53f22b26bb | 3 years ago |
_xeroxz | 547d1a78d6 | 3 years ago |
_xeroxz | 1c6fd327b1 | 3 years ago |
_xeroxz | 29804c5015 | 3 years ago |
_xeroxz | 33ba405a21 | 3 years ago |
_xeroxz | 4b0e53fbe1 | 3 years ago |
_xeroxz | 1128607429 | 3 years ago |
_xeroxz | 5223011f4b | 3 years ago |
_xeroxz | fbce0ffd59 | 3 years ago |
_xeroxz | 77ae31b1b6 | 3 years ago |
_xeroxz | 9ff8014de8 | 3 years ago |
_xeroxz | 3a4529819c | 3 years ago |
_xeroxz | 07bae2e551 | 3 years ago |
_xeroxz | cca5b1191a | 3 years ago |
_xeroxz | fe089bf203 | 3 years ago |
_xeroxz | e45edafb81 | 3 years ago |
_xeroxz | 30c9c96173 | 3 years ago |
_xeroxz | a84ffc3e67 | 3 years ago |
_xeroxz | 3755f866ba | 3 years ago |
_xeroxz | 2a24bfc125 | 3 years ago |
_xeroxz | 97aab6d44f | 3 years ago |
_xeroxz | 856fa1815d | 3 years ago |
_xeroxz | e846560010 | 3 years ago |
_xeroxz | 332f9e4d2e | 3 years ago |
@ -1,3 +1,39 @@
|
||||
# vmdevirt
|
||||
# VMDevirt - VMProtect Static Devirtualization
|
||||
|
||||
VMProtect 2 Static Devirtualization
|
||||
VMDevirt is a project which uses LLVM to lift `vmprofiles` to LLVM IR. This lifting aims to be semantically accurate so that the generated native instructions can be executed as normal. This project only supports x86_64 PE binaries.
|
||||
|
||||
|
||||
Currently there is no project to generate IL for vmp3 virtual routines, however when that code has been willed into existence this project will be used to compile the IL back to native. The lifters/vmprofiles for vmp2 and vmp3 are pretty much the same.
|
||||
|
||||
# Compiling
|
||||
|
||||
<div align="center">
|
||||
<img src="https://media1.giphy.com/media/FovFeej5SQQh94uyyK/giphy.gif"/>
|
||||
<br>
|
||||
<i>LLVM takes forever to build and a few GB's of cache space in tmp...</i>
|
||||
</div>
|
||||
|
||||
### Requirements
|
||||
|
||||
* CMake version 3 and above
|
||||
* Visual Studios 2019 (Fully updated!)
|
||||
* 16gb+ of RAM
|
||||
* 10gb of free disk space
|
||||
|
||||
### Steps
|
||||
|
||||
Clone the entire repo recursively:
|
||||
|
||||
`git clone --recursive https://githacks.org/vmp2/vmdevirt.git`
|
||||
|
||||
Open a console inside of `vmdevirt` folder and execute the following CMake command:
|
||||
|
||||
`cmake -B build`
|
||||
|
||||
# Usage - Generating Native
|
||||
|
||||
In order to use this project you must first generate a `vmp2` file using `VMEmu`. This file contains the IL form of every single virtual instruction of every single virtual code block of every single virtualized routine that you generate from.
|
||||
|
||||
In order for VMEmu to work, all virtual instructions in the given virtual routine(s) must be defined. Please refer to the doxygen of `vmprofiler` to learn how to declare a vmprofile.
|
||||
|
||||
Once a `vmp2` file is generated you can then provide it to `vmdevirt` along with the virtualized binary. `vmdevirt` will lift all of the IL and compile it back to native, then append it to the virtualized binary and patch all jmp's into the virtualized routines to go into the devirtualized code.
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 16aeb2d6d48c4822b89497ad660911eb0f5e54bd
|
||||
Subproject commit 1b6875d18825529907289bc87990fed5d99e7f96
|
@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
#include <vmp_rtn_t.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"
|
||||
|
||||
#include "llvm/Transforms/InstCombine/InstCombine.h"
|
||||
#include "llvm/Transforms/Scalar.h"
|
||||
#include "llvm/Transforms/Scalar/GVN.h"
|
||||
#include "llvm/Transforms/Utils.h"
|
||||
|
||||
#include "X86TargetMachine.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Passes/OptimizationLevel.h"
|
||||
#include "llvm/Passes/PassBuilder.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
#include "llvm/Support/TargetRegistry.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Target/TargetOptions.h"
|
||||
|
||||
namespace llvm
|
||||
{
|
||||
extern "C" void LLVMInitializeX86TargetInfo();
|
||||
extern "C" void LLVMInitializeX86Target();
|
||||
extern "C" void LLVMInitializeX86TargetMC();
|
||||
extern "C" void LLVMInitializeX86AsmParser();
|
||||
extern "C" void LLVMInitializeX86AsmPrinter();
|
||||
} // namespace llvm
|
||||
|
||||
namespace vm
|
||||
{
|
||||
class devirt_t
|
||||
{
|
||||
friend class lifters_t;
|
||||
|
||||
public:
|
||||
explicit devirt_t( llvm::LLVMContext *llvm_ctx, llvm::Module *llvm_module, vmp2::v4::file_header * vmp2_file );
|
||||
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;
|
||||
vmp2::v4::file_header *vmp2_file;
|
||||
std::shared_ptr< llvm::IRBuilder<> > ir_builder;
|
||||
std::vector< std::shared_ptr< vm::vmp_rtn_t > > vmp_rtns;
|
||||
|
||||
void push( std::uint8_t byte_size, llvm::Value *input_val );
|
||||
llvm::Value *pop( std::uint8_t byte_size );
|
||||
|
||||
llvm::Value *load_value( std::uint8_t byte_size, llvm::GlobalValue *global );
|
||||
llvm::Value *load_value( std::uint8_t byte_size, llvm::AllocaInst *var );
|
||||
|
||||
llvm::Value *sf( std::uint8_t byte_size, llvm::Value *val );
|
||||
llvm::Value *zf( std::uint8_t byte_size, llvm::Value *val );
|
||||
llvm::Value *pf( std::uint8_t byte_size, llvm::Value *val );
|
||||
llvm::Value *flags( llvm::Value *cf, llvm::Value *pf, llvm::Value *af, llvm::Value *zf, llvm::Value *sf,
|
||||
llvm::Value *of );
|
||||
};
|
||||
} // namespace vm
|
@ -0,0 +1,39 @@
|
||||
#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
|
||||
{
|
||||
/// <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 );
|
||||
} // namespace util
|
||||
|
||||
/// <summary>
|
||||
/// append devirtualized functions to the original binary... patches vm enter jmps to devirtualized code...
|
||||
/// </summary>
|
||||
/// <param name="obj">compiled obj file... generated by llvm...</param>
|
||||
/// <param name="bin">original binary in a vector... this binary gets patched...</param>
|
||||
/// <returns>returns true if new .devirt section has been appended and all linking was successful...</returns>
|
||||
bool append( std::vector< std::uint8_t > &obj, std::vector< std::uint8_t > &bin );
|
||||
} // namespace devirt
|
@ -1,53 +0,0 @@
|
||||
#pragma once
|
||||
#include <vmprofiler.hpp>
|
||||
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/IR/Constants.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/Module.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/IR/Type.h"
|
||||
#include "llvm/IR/Verifier.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
namespace vm
|
||||
{
|
||||
class vmp_rtn_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 );
|
||||
llvm::LLVMContext *llvm_ctx;
|
||||
vm::ctx_t *vm_ctx;
|
||||
llvm::Module *llvm_module;
|
||||
std::uintptr_t rtn_begin;
|
||||
llvm::Function *llvm_fptr;
|
||||
std::shared_ptr< llvm::IRBuilder<> > ir_builder;
|
||||
llvm::AllocaInst *virtual_stack, *stack_ptr;
|
||||
|
||||
std::map< ZydisRegister, llvm::GlobalVariable * > native_registers;
|
||||
std::vector< llvm::AllocaInst * > virtual_registers;
|
||||
std::vector< llvm::BasicBlock * > llvm_code_blocks;
|
||||
std::vector< vm::instrs::code_block_t > vmp2_code_blocks;
|
||||
|
||||
void push( std::uint8_t byte_size, llvm::Value *input_val );
|
||||
llvm::Value *pop( std::uint8_t byte_size );
|
||||
llvm::Value *peek( std::uint8_t byte_size, std::uint8_t byte_offset = 0u );
|
||||
llvm::Value *load_value( std::uint8_t byte_size, llvm::GlobalValue *global );
|
||||
llvm::Value *load_value( std::uint8_t byte_size, llvm::AllocaInst *var );
|
||||
|
||||
private:
|
||||
void create_native_registers( void );
|
||||
void create_virtual_registers( void );
|
||||
void create_routine( void );
|
||||
void create_virtual_stack( void );
|
||||
void lift_vm_entry( void );
|
||||
};
|
||||
} // namespace vm
|
@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
#include <vmprofiler.hpp>
|
||||
|
||||
#include "llvm/IR/InlineAsm.h"
|
||||
#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;
|
||||
vmp2::v4::file_header *vmp2_file;
|
||||
|
||||
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,
|
||||
vmp2::v4::file_header *vmp2_file );
|
||||
};
|
||||
} // namespace vm
|
@ -0,0 +1,196 @@
|
||||
#include <devirt_t.hpp>
|
||||
#include <vm_lifters.hpp>
|
||||
|
||||
namespace vm
|
||||
{
|
||||
devirt_t::devirt_t( llvm::LLVMContext *llvm_ctx, llvm::Module *llvm_module, vmp2::v4::file_header *vmp2_file )
|
||||
: llvm_ctx( llvm_ctx ), llvm_module( llvm_module ), vmp2_file( vmp2_file )
|
||||
{
|
||||
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 );
|
||||
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 )->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 )->setAlignment( llvm::Align( 1 ) );
|
||||
}
|
||||
|
||||
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 );
|
||||
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 );
|
||||
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;
|
||||
}
|
||||
|
||||
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 ) );
|
||||
|
||||
auto result = ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), cast_ptr );
|
||||
result->setAlignment( llvm::Align( 1 ) );
|
||||
return result;
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
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 ) );
|
||||
|
||||
auto result = ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), cast_ptr );
|
||||
result->setAlignment( llvm::Align( 1 ) );
|
||||
return result;
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
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 );
|
||||
llvm::legacy::PassManager pass;
|
||||
std::string error;
|
||||
|
||||
auto target_triple = llvm::sys::getDefaultTargetTriple();
|
||||
llvm_module->setTargetTriple( target_triple );
|
||||
|
||||
auto target = llvm::TargetRegistry::lookupTarget( target_triple, error );
|
||||
auto reloc_model = llvm::Optional< llvm::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, llvm::CGFT_ObjectFile );
|
||||
auto result = pass.run( *llvm_module );
|
||||
obj.insert( obj.begin(), buff.begin(), buff.end() );
|
||||
return result;
|
||||
}
|
||||
|
||||
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, vmp2_file ) );
|
||||
|
||||
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 );
|
||||
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() ) )
|
||||
{
|
||||
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::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::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::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::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->CreateOr( or5, llvm::ConstantInt::get( llvm::IntegerType::get( *llvm_ctx, 64 ), 514 ) );
|
||||
}
|
||||
|
||||
} // namespace vm
|
@ -0,0 +1,201 @@
|
||||
#include <devirt_utils.hpp>
|
||||
|
||||
namespace devirt
|
||||
{
|
||||
namespace util
|
||||
{
|
||||
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 )
|
||||
{
|
||||
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 v4...\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
auto first_rtn = reinterpret_cast< vmp2::v4::rtn_t * >( reinterpret_cast< std::uintptr_t >( file_header ) +
|
||||
file_header->rtn_offset );
|
||||
|
||||
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 ) )
|
||||
{
|
||||
virt_rtns.push_back( { rtn_block->vm_enter_offset, {} } );
|
||||
for ( auto [ code_block, block_idx ] = std::pair{ &rtn_block->code_blocks[ 0 ], 0ull };
|
||||
block_idx < rtn_block->code_block_count;
|
||||
++block_idx, code_block = reinterpret_cast< vmp2::v4::code_block_t * >(
|
||||
reinterpret_cast< std::uintptr_t >( code_block ) +
|
||||
code_block->next_block_offset ) )
|
||||
{
|
||||
auto block_vinstrs = reinterpret_cast< vm::instrs::virt_instr_t * >(
|
||||
reinterpret_cast< std::uintptr_t >( code_block ) + sizeof vmp2::v4::code_block_t +
|
||||
( code_block->num_block_addrs * 8 ) );
|
||||
|
||||
vm::instrs::code_block_t _code_block{ code_block->vip_begin };
|
||||
_code_block.jcc.has_jcc = code_block->has_jcc;
|
||||
_code_block.jcc.type = code_block->jcc_type;
|
||||
|
||||
for ( auto idx = 0u; idx < code_block->num_block_addrs; ++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 ] );
|
||||
|
||||
virt_rtns.back().second.push_back( _code_block );
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace util
|
||||
|
||||
bool append( std::vector< std::uint8_t > &obj, std::vector< std::uint8_t > &bin )
|
||||
{
|
||||
if ( obj.empty() || bin.empty() )
|
||||
return false;
|
||||
|
||||
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 §ion ) {
|
||||
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 §ion ) {
|
||||
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;
|
||||
}
|
||||
} );
|
||||
|
||||
// replace bin vector with map_buff vector...
|
||||
bin.clear();
|
||||
bin.insert( bin.begin(), map_buff.begin(), map_buff.end() );
|
||||
return true;
|
||||
}
|
||||
} // namespace devirt
|
@ -1,17 +1,98 @@
|
||||
#include <vm_lifters.hpp>
|
||||
|
||||
namespace vmp2::lifters
|
||||
namespace vm
|
||||
{
|
||||
lifter_callback_t addq = [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block,
|
||||
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) {
|
||||
auto t1 = rtn->pop( 8 );
|
||||
auto t2 = rtn->pop( 8 );
|
||||
auto t3 = ir_builder->CreateAdd( t1, t2 );
|
||||
|
||||
rtn->push( 8, t1 );
|
||||
rtn->push( 8, t3 );
|
||||
|
||||
// TODO: compute and update RFLAGS...
|
||||
rtn->push( 8, rtn->load_value( 8, rtn->native_registers[ ZYDIS_REGISTER_RFLAGS ] ) );
|
||||
};
|
||||
}
|
||||
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;
|
||||
intrinsic_arg_types.push_back( op_size );
|
||||
intrinsic_arg_types.push_back( op_size );
|
||||
|
||||
auto sadd_with_overflow = llvm::Intrinsic::getDeclaration(
|
||||
rtn->llvm_module, llvm::Intrinsic::sadd_with_overflow, intrinsic_arg_types );
|
||||
auto uadd_with_overflow = llvm::Intrinsic::getDeclaration(
|
||||
rtn->llvm_module, llvm::Intrinsic::uadd_with_overflow, intrinsic_arg_types );
|
||||
|
||||
auto u_add = rtn->ir_builder->CreateCall( uadd_with_overflow, { lhs, rhs } );
|
||||
auto u_sum = rtn->ir_builder->CreateExtractValue( u_add, { 0 } );
|
||||
auto u_of_bit = rtn->ir_builder->CreateExtractValue( u_add, { 1 } );
|
||||
auto cf = rtn->ir_builder->CreateZExt( u_of_bit, llvm::IntegerType::get( *rtn->llvm_ctx, 64 ) );
|
||||
|
||||
auto s_add = rtn->ir_builder->CreateCall( sadd_with_overflow, { lhs, rhs } );
|
||||
auto s_sum = rtn->ir_builder->CreateExtractValue( s_add, { 0 } );
|
||||
auto s_of_bit = rtn->ir_builder->CreateExtractValue( s_add, { 1 } );
|
||||
auto of = rtn->ir_builder->CreateZExt( s_of_bit, llvm::IntegerType::get( *rtn->llvm_ctx, 64 ) );
|
||||
|
||||
auto sf = rtn->sf( byte_size, u_sum );
|
||||
auto zf = rtn->zf( byte_size, u_sum );
|
||||
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 );
|
||||
|
||||
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 ) {
|
||||
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, vmp_rtn->flags );
|
||||
rtn->push( 8, rtn->load_value( 8, vmp_rtn->flags ) );
|
||||
};
|
||||
|
||||
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 ) {
|
||||
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, vmp_rtn->flags );
|
||||
rtn->push( 8, rtn->load_value( 8, vmp_rtn->flags ) );
|
||||
};
|
||||
|
||||
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 ) {
|
||||
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, vmp_rtn->flags );
|
||||
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
|
@ -0,0 +1,72 @@
|
||||
#include <vm_lifters.hpp>
|
||||
|
||||
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 ) {
|
||||
if ( !vm_code_block.jcc.has_jcc )
|
||||
{
|
||||
ir_builder->CreateRetVoid();
|
||||
return;
|
||||
}
|
||||
|
||||
auto &vmp_rtn = rtn->vmp_rtns.back();
|
||||
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();
|
||||
|
||||
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 );
|
||||
break;
|
||||
}
|
||||
case vm::instrs::jcc_type::absolute:
|
||||
{
|
||||
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 );
|
||||
break;
|
||||
}
|
||||
case vm::instrs::jcc_type::switch_case:
|
||||
{
|
||||
// TODO: add switch case support here...
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
} // namespace vm
|
@ -1,14 +1,58 @@
|
||||
#include <vm_lifters.hpp>
|
||||
|
||||
namespace vmp2::lifters
|
||||
namespace vm
|
||||
{
|
||||
lifter_callback_t lconstq = [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block,
|
||||
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) {
|
||||
rtn->push( 8, llvm::ConstantInt::get( ir_builder->getInt64Ty(), vinstr.operand.imm.u ) );
|
||||
};
|
||||
|
||||
lifter_callback_t lconstdwsxq = [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block,
|
||||
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) {
|
||||
rtn->push( 8, llvm::ConstantInt::get( ir_builder->getInt64Ty(), vinstr.operand.imm.u ) );
|
||||
};
|
||||
} // namespace vmp2::lifters
|
||||
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 ) {
|
||||
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 ) {
|
||||
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 ) {
|
||||
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 ) {
|
||||
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 ) {
|
||||
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 ) {
|
||||
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 ) {
|
||||
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 ) {
|
||||
rtn->push( 2, llvm::ConstantInt::get( ir_builder->getInt16Ty(), vinstr.operand.imm.u ) );
|
||||
};
|
||||
} // namespace vm
|
@ -0,0 +1,12 @@
|
||||
#include <vm_lifters.hpp>
|
||||
|
||||
namespace vm
|
||||
{
|
||||
lifters_t::lifter_callback_t lifters_t::lflagsq =
|
||||
[ & ]( 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, vmp_rtn->flags );
|
||||
};
|
||||
}
|
@ -1,10 +1,20 @@
|
||||
#include <vm_lifters.hpp>
|
||||
|
||||
namespace vmp2::lifters
|
||||
namespace vm
|
||||
{
|
||||
lifter_callback_t lregq = [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block,
|
||||
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) {
|
||||
auto vreg = rtn->virtual_registers[ vinstr.operand.imm.u ? vinstr.operand.imm.u / 8 : 0 ];
|
||||
rtn->push( 8, rtn->load_value( 8, vreg ) );
|
||||
};
|
||||
}
|
||||
lifters_t::lifter_callback_t lifters_t::lregq =
|
||||
[ & ]( 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::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
|
@ -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 ) );
|
||||
};
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
#include <vm_lifters.hpp>
|
||||
|
||||
namespace vm
|
||||
{
|
||||
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 );
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
lifters_t::lifter_callback_t lifters_t::nandq =
|
||||
[ & ]( 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 t1_not = ir_builder->CreateNot( t1 );
|
||||
auto t2_not = ir_builder->CreateNot( t2 );
|
||||
|
||||
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, vmp_rtn->flags );
|
||||
rtn->push( 8, rtn->load_value( 8, vmp_rtn->flags ) );
|
||||
};
|
||||
|
||||
lifters_t::lifter_callback_t lifters_t::nanddw =
|
||||
[ & ]( 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 t1_not = ir_builder->CreateNot( t1 );
|
||||
auto t2_not = ir_builder->CreateNot( t2 );
|
||||
|
||||
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, vmp_rtn->flags );
|
||||
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 ) {
|
||||
auto t1 = rtn->pop( 2 );
|
||||
auto t2 = rtn->pop( 2 );
|
||||
|
||||
auto t1_b = ir_builder->CreateIntCast( t1, ir_builder->getInt8Ty(), false );
|
||||
auto t2_b = ir_builder->CreateIntCast( t2, ir_builder->getInt8Ty(), false );
|
||||
|
||||
auto t1_not = ir_builder->CreateNot( t1_b );
|
||||
auto t2_not = ir_builder->CreateNot( t2_b );
|
||||
|
||||
auto t3 = ir_builder->CreateAnd( { t1_not, t2_not } );
|
||||
auto t3_w = ir_builder->CreateIntCast( t3, ir_builder->getInt16Ty(), false );
|
||||
|
||||
rtn->push( 2, t3_w );
|
||||
auto &vmp_rtn = rtn->vmp_rtns.back();
|
||||
auto flags = and_flags( rtn, 1, t3 );
|
||||
ir_builder->CreateStore( flags, vmp_rtn->flags );
|
||||
rtn->push( 8, rtn->load_value( 8, vmp_rtn->flags ) );
|
||||
};
|
||||
|
||||
} // namespace vm
|
@ -0,0 +1,16 @@
|
||||
#include <vm_lifters.hpp>
|
||||
|
||||
namespace vm
|
||||
{
|
||||
lifters_t::lifter_callback_t lifters_t::popvsp =
|
||||
[ & ]( 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_ptr = ir_builder->CreatePointerCast(
|
||||
stack, llvm::PointerType::get( llvm::PointerType::get( ir_builder->getInt8Ty(), 0ull ), 0ull ) );
|
||||
|
||||
auto stack_ptr = ir_builder->CreateLoad( stack_ptr_ptr );
|
||||
ir_builder->CreateStore( stack_ptr, vmp_rtn->stack );
|
||||
};
|
||||
}
|
@ -1,20 +1,22 @@
|
||||
#include <vm_lifters.hpp>
|
||||
|
||||
namespace vmp2::lifters
|
||||
namespace vm
|
||||
{
|
||||
lifter_callback_t pushvsp = [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block,
|
||||
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) {
|
||||
// Load the current stack index into a temporary variable
|
||||
auto current_stack_index =
|
||||
ir_builder->CreateLoad( llvm::IntegerType::get( *rtn->llvm_ctx, 64 ), rtn->stack_ptr, false );
|
||||
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();
|
||||
auto stack = ir_builder->CreateLoad( vmp_rtn->stack );
|
||||
auto stack_ptr = ir_builder->CreatePtrToInt( stack, ir_builder->getInt64Ty() );
|
||||
rtn->push( 8, stack_ptr );
|
||||
};
|
||||
|
||||
// Get a pointer to the top byte of the stack
|
||||
llvm::Value *i64_zero = llvm::ConstantInt::get( *rtn->llvm_ctx, llvm::APInt( 64, 0 ) );
|
||||
llvm::Value *indices[ 2 ] = { i64_zero, current_stack_index };
|
||||
auto stack_ptr =
|
||||
ir_builder->CreateInBoundsGEP( rtn->virtual_stack, llvm::ArrayRef< llvm::Value * >( indices, 2 ) );
|
||||
|
||||
auto stack_ptr_val = ir_builder->CreatePtrToInt( stack_ptr, ir_builder->getInt64Ty() );
|
||||
rtn->push( 8, stack_ptr_val );
|
||||
};
|
||||
}
|
||||
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 );
|
||||
};
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
#include <vm_lifters.hpp>
|
||||
|
||||
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 ) {
|
||||
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 );
|
||||
rtn->push( 8, t3 );
|
||||
};
|
||||
|
||||
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 ) {
|
||||
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
|
@ -0,0 +1,80 @@
|
||||
#include <vm_lifters.hpp>
|
||||
|
||||
namespace vm
|
||||
{
|
||||
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 );
|
||||
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 );
|
||||
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 );
|
||||
}
|
||||
|
||||
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 ) {
|
||||
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, vmp_rtn->flags );
|
||||
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
|
@ -1,14 +1,44 @@
|
||||
#include <vm_lifters.hpp>
|
||||
|
||||
namespace vmp2::lifters
|
||||
namespace vm
|
||||
{
|
||||
// %t1 = %stack[%sp]
|
||||
// add %sp, 8
|
||||
// %vregX = %1
|
||||
lifter_callback_t sregq = [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block,
|
||||
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) {
|
||||
auto t1 = rtn->pop( 8 );
|
||||
auto vreg = rtn->virtual_registers[ vinstr.operand.imm.u ? vinstr.operand.imm.u / 8 : 0 ];
|
||||
ir_builder->CreateStore( t1, vreg );
|
||||
};
|
||||
} // namespace vmp2::lifters
|
||||
lifters_t::lifter_callback_t lifters_t::sregq =
|
||||
[ & ]( 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 &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::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 &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->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 ) {
|
||||
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->getInt8Ty(), false ),
|
||||
ir_builder->CreatePointerCast( vreg, llvm::PointerType::get( ir_builder->getInt8Ty(), 0ull ) ) );
|
||||
};
|
||||
} // namespace vm
|
@ -0,0 +1,61 @@
|
||||
#include <vm_lifters.hpp>
|
||||
|
||||
namespace vm
|
||||
{
|
||||
lifters_t::lifter_callback_t lifters_t::vmexit = [ & ]( vm::devirt_t *rtn,
|
||||
const vm::instrs::code_block_t &vm_code_block,
|
||||
const vm::instrs::virt_instr_t &vinstr,
|
||||
llvm::IRBuilder<> *ir_builder ) {
|
||||
std::stringstream rtn_name;
|
||||
llvm::Function *exit_func = nullptr;
|
||||
rtn_name << "vmexit_" << std::hex << vinstr.trace_data.vm_handler_rva + rtn->vmp2_file->image_base;
|
||||
|
||||
if ( !( exit_func = rtn->llvm_module->getFunction( rtn_name.str() ) ) )
|
||||
{
|
||||
auto vmexit_func_type = llvm::FunctionType::get(
|
||||
ir_builder->getVoidTy(), llvm::PointerType::getInt8PtrTy( ir_builder->getContext() ) );
|
||||
|
||||
exit_func = llvm::Function::Create( vmexit_func_type, llvm::GlobalValue::LinkageTypes::ExternalLinkage,
|
||||
rtn_name.str().c_str(), *rtn->llvm_module );
|
||||
|
||||
auto entry_block = llvm::BasicBlock::Create( ir_builder->getContext(), "", exit_func );
|
||||
auto vmexit_handler_addr = reinterpret_cast< std::uintptr_t >( rtn->vmp2_file ) +
|
||||
rtn->vmp2_file->module_offset + vinstr.trace_data.vm_handler_rva;
|
||||
|
||||
zydis_routine_t vmexit_handler;
|
||||
vm::util::flatten( vmexit_handler, vmexit_handler_addr );
|
||||
vm::util::deobfuscate( vmexit_handler );
|
||||
|
||||
std::string asm_str( "mov rsp, rcx; " );
|
||||
ZydisFormatter formatter;
|
||||
ZydisFormatterInit( &formatter, ZYDIS_FORMATTER_STYLE_INTEL );
|
||||
|
||||
for ( const auto &instr_data : vmexit_handler )
|
||||
{
|
||||
if ( instr_data.instr.mnemonic == ZYDIS_MNEMONIC_POP ||
|
||||
instr_data.instr.mnemonic == ZYDIS_MNEMONIC_POPFQ )
|
||||
{
|
||||
char buffer[ 256 ];
|
||||
ZydisFormatterFormatInstruction( &formatter, &instr_data.instr, buffer, sizeof( buffer ), 0ull );
|
||||
asm_str.append( buffer ).append( "; " );
|
||||
}
|
||||
}
|
||||
|
||||
asm_str.append( "ret" );
|
||||
auto ib = ir_builder->GetInsertBlock();
|
||||
ir_builder->SetInsertPoint( entry_block );
|
||||
|
||||
auto exit_stub = llvm::InlineAsm::get( llvm::FunctionType::get( ir_builder->getVoidTy(), false ), asm_str,
|
||||
"", false, false, llvm::InlineAsm::AD_Intel );
|
||||
|
||||
ir_builder->CreateCall( exit_stub );
|
||||
ir_builder->CreateRetVoid();
|
||||
ir_builder->SetInsertPoint( ib );
|
||||
}
|
||||
|
||||
auto &vmp_rtn = rtn->vmp_rtns.back();
|
||||
auto stack_ptr = ir_builder->CreateLoad( vmp_rtn->stack );
|
||||
ir_builder->CreateCall( exit_func, stack_ptr );
|
||||
ir_builder->CreateRet( stack_ptr );
|
||||
};
|
||||
} // namespace vm
|
@ -0,0 +1,41 @@
|
||||
#include <vm_lifters.hpp>
|
||||
|
||||
namespace vm
|
||||
{
|
||||
lifters_t::lifter_callback_t lifters_t::writeq =
|
||||
[ & ]( 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->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 } );
|
||||
};
|
||||
}
|
@ -1,285 +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 )
|
||||
{
|
||||
// create llvm::Function and llvm::BasicBlock's...
|
||||
create_routine();
|
||||
|
||||
// set the insert point to the first code block...
|
||||
ir_builder = std::make_shared< llvm::IRBuilder<> >( *llvm_ctx );
|
||||
ir_builder->SetInsertPoint( llvm_code_blocks[ 0 ] );
|
||||
|
||||
// create native registers...
|
||||
create_native_registers();
|
||||
|
||||
// create stack and stack pointer...
|
||||
create_virtual_stack();
|
||||
|
||||
// lift vm enter pushes to llvm ir...
|
||||
lift_vm_entry();
|
||||
|
||||
// create virtual registers...
|
||||
create_virtual_registers();
|
||||
}
|
||||
|
||||
void vmp_rtn_t::lift_vm_entry( void )
|
||||
{
|
||||
for ( const auto &instr : vm_ctx->vm_entry )
|
||||
{
|
||||
if ( instr.instr.mnemonic == ZYDIS_MNEMONIC_PUSH )
|
||||
{
|
||||
// push [xxxxx] we know this is zero and the next push is the image base...
|
||||
if ( instr.instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY )
|
||||
{
|
||||
push( 8, llvm::ConstantInt::get( ir_builder->getInt64Ty(), 0ull ) );
|
||||
push( 8, llvm::ConstantInt::get( ir_builder->getInt64Ty(), vm_ctx->image_base ) );
|
||||
break; // dont make these if statements a switch case because we need to use this break...
|
||||
}
|
||||
else if ( instr.instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_IMMEDIATE )
|
||||
{
|
||||
push( 8, llvm::ConstantInt::get( ir_builder->getInt64Ty(), instr.instr.operands[ 0 ].imm.value.u,
|
||||
false ) );
|
||||
}
|
||||
else if ( instr.instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER )
|
||||
{
|
||||
push( 8, load_value( 8, native_registers[ instr.instr.operands[ 0 ].reg.value ] ) );
|
||||
}
|
||||
}
|
||||
else if ( instr.instr.mnemonic == ZYDIS_MNEMONIC_PUSHFQ )
|
||||
{
|
||||
// just push 0 as the value itself wont matter...
|
||||
push( 8, load_value( 8, native_registers[ ZYDIS_REGISTER_RFLAGS ] ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void vmp_rtn_t::create_native_registers( void )
|
||||
{
|
||||
llvm_module->getOrInsertGlobal( "rax", ir_builder->getInt64Ty() );
|
||||
native_registers[ ZYDIS_REGISTER_RAX ] = llvm_module->getGlobalVariable( "rax" );
|
||||
|
||||
llvm_module->getOrInsertGlobal( "rbx", ir_builder->getInt64Ty() );
|
||||
native_registers[ ZYDIS_REGISTER_RBX ] = llvm_module->getGlobalVariable( "rbx" );
|
||||
|
||||
llvm_module->getOrInsertGlobal( "rcx", ir_builder->getInt64Ty() );
|
||||
native_registers[ ZYDIS_REGISTER_RCX ] = llvm_module->getGlobalVariable( "rcx" );
|
||||
|
||||
llvm_module->getOrInsertGlobal( "rdx", ir_builder->getInt64Ty() );
|
||||
native_registers[ ZYDIS_REGISTER_RDX ] = llvm_module->getGlobalVariable( "rdx" );
|
||||
|
||||
llvm_module->getOrInsertGlobal( "rsi", ir_builder->getInt64Ty() );
|
||||
native_registers[ ZYDIS_REGISTER_RSI ] = llvm_module->getGlobalVariable( "rsi" );
|
||||
|
||||
llvm_module->getOrInsertGlobal( "rdi", ir_builder->getInt64Ty() );
|
||||
native_registers[ ZYDIS_REGISTER_RDI ] = llvm_module->getGlobalVariable( "rdi" );
|
||||
|
||||
llvm_module->getOrInsertGlobal( "rbp", ir_builder->getInt64Ty() );
|
||||
native_registers[ ZYDIS_REGISTER_RBP ] = llvm_module->getGlobalVariable( "rbp" );
|
||||
|
||||
llvm_module->getOrInsertGlobal( "rsp", ir_builder->getInt64Ty() );
|
||||
native_registers[ ZYDIS_REGISTER_RSP ] = llvm_module->getGlobalVariable( "rsp" );
|
||||
|
||||
llvm_module->getOrInsertGlobal( "r8", ir_builder->getInt64Ty() );
|
||||
native_registers[ ZYDIS_REGISTER_R8 ] = llvm_module->getGlobalVariable( "r8" );
|
||||
|
||||
llvm_module->getOrInsertGlobal( "r9", ir_builder->getInt64Ty() );
|
||||
native_registers[ ZYDIS_REGISTER_R9 ] = llvm_module->getGlobalVariable( "r9" );
|
||||
|
||||
llvm_module->getOrInsertGlobal( "r10", ir_builder->getInt64Ty() );
|
||||
native_registers[ ZYDIS_REGISTER_R10 ] = llvm_module->getGlobalVariable( "r10" );
|
||||
|
||||
llvm_module->getOrInsertGlobal( "r11", ir_builder->getInt64Ty() );
|
||||
native_registers[ ZYDIS_REGISTER_R11 ] = llvm_module->getGlobalVariable( "r11" );
|
||||
|
||||
llvm_module->getOrInsertGlobal( "r12", ir_builder->getInt64Ty() );
|
||||
native_registers[ ZYDIS_REGISTER_R12 ] = llvm_module->getGlobalVariable( "r12" );
|
||||
|
||||
llvm_module->getOrInsertGlobal( "r13", ir_builder->getInt64Ty() );
|
||||
native_registers[ ZYDIS_REGISTER_R13 ] = llvm_module->getGlobalVariable( "r13" );
|
||||
|
||||
llvm_module->getOrInsertGlobal( "r14", ir_builder->getInt64Ty() );
|
||||
native_registers[ ZYDIS_REGISTER_R14 ] = llvm_module->getGlobalVariable( "r14" );
|
||||
|
||||
llvm_module->getOrInsertGlobal( "r15", ir_builder->getInt64Ty() );
|
||||
native_registers[ ZYDIS_REGISTER_R15 ] = llvm_module->getGlobalVariable( "r15" );
|
||||
|
||||
llvm_module->getOrInsertGlobal( "rflags", ir_builder->getInt64Ty() );
|
||||
native_registers[ ZYDIS_REGISTER_RFLAGS ] = llvm_module->getGlobalVariable( "rflags" );
|
||||
}
|
||||
|
||||
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::Type::getVoidTy( *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( llvm::BasicBlock::Create( *llvm_ctx, blk_name.str().c_str(), llvm_fptr ) );
|
||||
}
|
||||
}
|
||||
|
||||
void vmp_rtn_t::push( std::uint8_t byte_size, llvm::Value *input_value )
|
||||
{
|
||||
// Load the current stack index into a temporary variable
|
||||
auto current_stack_index = ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, 64 ), stack_ptr, false );
|
||||
|
||||
// Subtract the input value size from the current stack index
|
||||
auto new_stack_index = ir_builder->CreateSub(
|
||||
current_stack_index, llvm::ConstantInt::get( llvm::IntegerType::get( *llvm_ctx, 64 ), byte_size ) );
|
||||
|
||||
// Store the newly calculated stack index into VSP
|
||||
ir_builder->CreateStore( new_stack_index, stack_ptr );
|
||||
|
||||
// Get a pointer to the top byte of the stack
|
||||
llvm::Value *i64_zero = llvm::ConstantInt::get( *llvm_ctx, llvm::APInt( 64, 0 ) );
|
||||
llvm::Value *indices[ 2 ] = { i64_zero, new_stack_index };
|
||||
auto stack_ptr = ir_builder->CreateInBoundsGEP( virtual_stack, llvm::ArrayRef< llvm::Value * >( indices, 2 ) );
|
||||
|
||||
// Store the input value at the calculated stack address
|
||||
if ( byte_size == 1 )
|
||||
{
|
||||
ir_builder->CreateStore( input_value, stack_ptr );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Cast the pointer so the stack item width matches the width of the input value
|
||||
auto casted_ptr = ir_builder->CreatePointerCast(
|
||||
stack_ptr, llvm::PointerType::get( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), 0 ) );
|
||||
|
||||
ir_builder->CreateStore( input_value, casted_ptr );
|
||||
}
|
||||
}
|
||||
|
||||
llvm::Value *vmp_rtn_t::pop( std::uint8_t byte_size )
|
||||
{
|
||||
// Load the current stack index into a temporary variable
|
||||
auto current_stack_index = ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, 64 ), stack_ptr, false );
|
||||
|
||||
// Get a pointer to the top byte of the stack
|
||||
llvm::Value *i64_zero = llvm::ConstantInt::get( *llvm_ctx, llvm::APInt( 64, 0 ) );
|
||||
llvm::Value *indices[ 2 ] = { i64_zero, current_stack_index };
|
||||
auto stack_ptr = ir_builder->CreateInBoundsGEP( virtual_stack, llvm::ArrayRef< llvm::Value * >( indices, 2 ) );
|
||||
|
||||
// Read the value at the top of the stack
|
||||
llvm::Value *output_value = nullptr;
|
||||
|
||||
if ( byte_size == 1 )
|
||||
{
|
||||
output_value = ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, 8 ), stack_ptr );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Cast the current stack pointer so the stack item width matches the width of the output value
|
||||
auto casted_ptr = ir_builder->CreatePointerCast(
|
||||
stack_ptr, llvm::PointerType::get( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), 0 ) );
|
||||
|
||||
output_value = ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), casted_ptr );
|
||||
}
|
||||
|
||||
// Subtract the input value size from the current stack index
|
||||
auto new_stack_index = ir_builder->CreateAdd(
|
||||
current_stack_index, llvm::ConstantInt::get( llvm::IntegerType::get( *llvm_ctx, 64 ), byte_size ) );
|
||||
|
||||
// Store the newly calculated stack index into VSP
|
||||
ir_builder->CreateStore( new_stack_index, this->stack_ptr );
|
||||
return output_value;
|
||||
}
|
||||
|
||||
llvm::Value *vmp_rtn_t::peek( std::uint8_t byte_size, std::uint8_t byte_offset )
|
||||
{
|
||||
// Load the current stack index into a temporary variable
|
||||
auto current_stack_index = ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, 64 ), stack_ptr, false );
|
||||
|
||||
if ( byte_offset )
|
||||
{
|
||||
auto t1 = ir_builder->CreateAdd(
|
||||
current_stack_index, llvm::ConstantInt::get( llvm::IntegerType::get( *llvm_ctx, 64 ), byte_offset ) );
|
||||
|
||||
current_stack_index = ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, 64 ), t1, false );
|
||||
}
|
||||
|
||||
// Get a pointer to the top byte of the stack + byte_offset (if any)
|
||||
llvm::Value *i64_zero = llvm::ConstantInt::get( *llvm_ctx, llvm::APInt( 64, 0 ) );
|
||||
llvm::Value *indices[ 2 ] = { i64_zero, current_stack_index };
|
||||
auto stack_ptr = ir_builder->CreateInBoundsGEP( virtual_stack, llvm::ArrayRef< llvm::Value * >( indices, 2 ) );
|
||||
|
||||
if ( byte_size != 1 )
|
||||
{
|
||||
auto casted_ptr = ir_builder->CreatePointerCast(
|
||||
stack_ptr, llvm::PointerType::get( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), 0 ) );
|
||||
|
||||
return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), casted_ptr );
|
||||
}
|
||||
else
|
||||
{
|
||||
return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), stack_ptr );
|
||||
}
|
||||
}
|
||||
|
||||
llvm::Value *vmp_rtn_t::load_value( std::uint8_t byte_size, llvm::GlobalValue *global )
|
||||
{
|
||||
return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), global );
|
||||
}
|
||||
|
||||
llvm::Value *vmp_rtn_t::load_value( std::uint8_t byte_size, llvm::AllocaInst *var )
|
||||
{
|
||||
return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), var );
|
||||
}
|
||||
|
||||
void vmp_rtn_t::create_virtual_stack( void )
|
||||
{
|
||||
// allocate stack space...
|
||||
virtual_stack = ir_builder->CreateAlloca( llvm::ArrayType::get( llvm::IntegerType::get( *llvm_ctx, 8 ), 1024 ),
|
||||
nullptr, "stack" );
|
||||
|
||||
// allocate stack pointer...
|
||||
stack_ptr = ir_builder->CreateAlloca( llvm::IntegerType::get( *llvm_ctx, 64 ), nullptr, "sp" );
|
||||
ir_builder->CreateStore( llvm::ConstantInt::get( llvm::IntegerType::getInt64Ty( *llvm_ctx ), 1024 ),
|
||||
stack_ptr );
|
||||
}
|
||||
|
||||
llvm::Function *vmp_rtn_t::lift( void )
|
||||
{
|
||||
auto &code_blocks = llvm_fptr->getBasicBlockList();
|
||||
for ( auto idx = 0u; idx < code_blocks.size(); ++idx )
|
||||
{
|
||||
for ( auto &vinstr : vmp2_code_blocks[ idx ].vinstrs )
|
||||
{
|
||||
if ( !vmp2::lifters::lift( this, vmp2_code_blocks[ idx ], vinstr, ir_builder.get() ) )
|
||||
{
|
||||
std::printf( "> failed to devirtualize virtual instruction with opcode = %d\n", vinstr.opcode );
|
||||
|
||||
llvm_module->print( llvm::outs(), nullptr );
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return llvm_fptr;
|
||||
}
|
||||
} // namespace vm
|
@ -0,0 +1,98 @@
|
||||
#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,
|
||||
vmp2::v4::file_header *vmp2_file )
|
||||
: ir_builder( ir_builder ), vmp2_code_blocks( vmp2_code_blocks ), rtn_begin( rtn_begin ),
|
||||
llvm_module( llvm_module ), vmp2_file( vmp2_file )
|
||||
{
|
||||
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 )
|
||||
{
|
||||
auto func_ty =
|
||||
llvm::FunctionType::get( llvm::PointerType::getInt8PtrTy( ir_builder->getContext() ),
|
||||
{ llvm::PointerType::getInt8PtrTy( ir_builder->getContext() ) }, false );
|
||||
|
||||
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 ) } );
|
||||
}
|
||||
|
||||
zydis_routine_t vm_enter;
|
||||
auto vm_enter_addr = reinterpret_cast< std::uintptr_t >( vmp2_file ) + vmp2_file->module_offset +
|
||||
( rtn_begin - vmp2_file->image_base );
|
||||
|
||||
vm::util::flatten( vm_enter, vm_enter_addr );
|
||||
vm::util::deobfuscate( vm_enter );
|
||||
|
||||
std::string asm_str;
|
||||
ZydisFormatter formatter;
|
||||
ZydisFormatterInit( &formatter, ZYDIS_FORMATTER_STYLE_INTEL );
|
||||
|
||||
for ( const auto &instr_data : vm_enter )
|
||||
{
|
||||
if ( instr_data.instr.mnemonic == ZYDIS_MNEMONIC_PUSH )
|
||||
{
|
||||
if ( instr_data.instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY )
|
||||
{
|
||||
asm_str.append( "mov rax, 0x1000000000000000; push rax; mov rax, 0x1000000000000000; push rax; " );
|
||||
break;
|
||||
}
|
||||
|
||||
char buffer[ 256 ];
|
||||
ZydisFormatterFormatInstruction( &formatter, &instr_data.instr, buffer, sizeof( buffer ), 0ull );
|
||||
asm_str.append( buffer ).append( "; " );
|
||||
}
|
||||
else if ( instr_data.instr.mnemonic == ZYDIS_MNEMONIC_PUSHFQ )
|
||||
{
|
||||
asm_str.append( "pushfq; " );
|
||||
}
|
||||
}
|
||||
|
||||
rtn_name.str( "" );
|
||||
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 ),
|
||||
llvm::GlobalValue::LinkageTypes::ExternalLinkage,
|
||||
rtn_name.str().c_str(), *llvm_module );
|
||||
|
||||
auto entry_block = llvm::BasicBlock::Create( ir_builder->getContext(), "", entry_func );
|
||||
ir_builder->SetInsertPoint( entry_block );
|
||||
|
||||
auto entry_stub = llvm::InlineAsm::get( llvm::FunctionType::get( ir_builder->getVoidTy(), false ), asm_str, "",
|
||||
false, false, llvm::InlineAsm::AD_Intel );
|
||||
|
||||
ir_builder->CreateCall( entry_stub );
|
||||
ir_builder->CreateRetVoid();
|
||||
}
|
||||
} // namespace vm
|
Loading…
Reference in new issue