Merge branch 'dev' into 'master'

applied clang-format

See merge request vmp2/vmemu!2
merge-requests/3/merge
_xeroxz 4 years ago
commit 21624dd312

@ -2,281 +2,258 @@
namespace vm namespace vm
{ {
emu_t::emu_t(std::uint32_t vm_entry_rva, emu_t::emu_t( std::uint32_t vm_entry_rva, std::uintptr_t image_base, std::uintptr_t module_base )
std::uintptr_t image_base, std::uintptr_t module_base) : module_base( module_base ), image_base( image_base ), vm_entry_rva( vm_entry_rva ),
: vm_handler_table( nullptr ), uc( nullptr ), trace_entries( nullptr )
module_base(module_base), {
image_base(image_base), }
vm_entry_rva(vm_entry_rva),
vm_handler_table(nullptr), bool emu_t::init()
uc(nullptr), {
trace_entries(nullptr) // vmprofiler init stuff...
{} if ( !vm::util::flatten( vm_entry, vm_entry_rva + module_base ) )
{
bool emu_t::init() std::printf( "[!] failed to get vm entry...\n" );
{ return false;
// vmprofiler init stuff... }
if (!vm::util::flatten(vm_entry, vm_entry_rva + module_base))
{ vm::util::deobfuscate( vm_entry );
std::printf("[!] failed to get vm entry...\n"); vm::util::print( vm_entry );
return false;
} if ( !( vm_handler_table = vm::handler::table::get( vm_entry ) ) )
{
vm::util::deobfuscate(vm_entry); std::printf( "[!] failed to get vm handler table...\n" );
vm::util::print(vm_entry); return false;
}
if (!(vm_handler_table = vm::handler::table::get(vm_entry)))
{ std::printf( "> vm handler table = 0x%p\n", vm_handler_table );
std::printf("[!] failed to get vm handler table...\n"); if ( !vm::handler::get_all( module_base, image_base, vm_entry, vm_handler_table, vm_handlers ) )
return false; {
} std::printf( "[!] failed to get all vm handlers...\n" );
return false;
std::printf("> vm handler table = 0x%p\n", vm_handler_table); }
if (!vm::handler::get_all(module_base, image_base, vm_entry, vm_handler_table, vm_handlers))
{ std::printf( "> got all vm handlers...\n" );
std::printf("[!] failed to get all vm handlers...\n"); for ( const vm::handler::handler_t &vm_handler : vm_handlers )
return false; std::printf( ">>> handler addr = 0x%p\n", vm_handler.address );
}
// unicorn init stuff...
std::printf("> got all vm handlers...\n"); const auto image_size = NT_HEADER( module_base )->OptionalHeader.SizeOfImage;
for (const vm::handler::handler_t& vm_handler : vm_handlers)
std::printf(">>> handler addr = 0x%p\n", vm_handler.address); std::uintptr_t stack_base = 0x1000000;
std::uintptr_t stack_addr = ( stack_base + ( 0x1000 * 20 ) ) - 0x6000;
// unicorn init stuff...
const auto image_size = uc_err err;
NT_HEADER(module_base)->OptionalHeader.SizeOfImage; if ( ( err = uc_open( UC_ARCH_X86, UC_MODE_64, &uc ) ) )
{
std::uintptr_t stack_base = 0x1000000; std::printf( "failed on uc_mem_map() with error returned %u: %s\n", err, uc_strerror( err ) );
std::uintptr_t stack_addr = (stack_base + (0x1000 * 20)) - 0x6000;
return false;
uc_err err; }
if ((err = uc_open(UC_ARCH_X86, UC_MODE_64, &uc)))
{ if ( ( err = uc_mem_map( uc, module_base, image_size, UC_PROT_ALL ) ) )
std::printf("failed on uc_mem_map() with error returned %u: %s\n", {
err, uc_strerror(err)); std::printf( "failed on uc_mem_map() with error returned %u: %s\n", err, uc_strerror( err ) );
return false; return false;
} }
if ((err = uc_mem_map(uc, module_base, image_size, UC_PROT_ALL))) if ( ( err = uc_mem_map( uc, 0x1000000, 0x1000 * 20, UC_PROT_ALL ) ) )
{ {
std::printf("failed on uc_mem_map() with error returned %u: %s\n", std::printf( "failed on uc_mem_map() with error returned %u: %s\n", err, uc_strerror( err ) );
err, uc_strerror(err));
return false;
return false; }
}
if ( ( err = uc_mem_write( uc, module_base, reinterpret_cast< void * >( module_base ), image_size ) ) )
if ((err = uc_mem_map(uc, 0x1000000, 0x1000 * 20, UC_PROT_ALL))) {
{ std::printf( "failed on uc_mem_write() with error returned %u: %s\n", err, uc_strerror( err ) );
std::printf("failed on uc_mem_map() with error returned %u: %s\n",
err, uc_strerror(err)); return false;
}
return false;
} if ( ( err = uc_reg_write( uc, UC_X86_REG_RIP, &vm_entry ) ) )
{
if ((err = uc_mem_write(uc, module_base, reinterpret_cast<void*>(module_base), image_size))) std::printf( "failed on uc_reg_write() with error returned %u: %s\n", err, uc_strerror( err ) );
{
std::printf("failed on uc_mem_write() with error returned %u: %s\n", return false;
err, uc_strerror(err)); }
return false; if ( ( err = uc_reg_write( uc, UC_X86_REG_RSP, &stack_addr ) ) )
} {
std::printf( "failed on uc_reg_write() with error returned %u: %s\n", err, uc_strerror( err ) );
if ((err = uc_reg_write(uc, UC_X86_REG_RIP, &vm_entry)))
{ return false;
std::printf("failed on uc_reg_write() with error returned %u: %s\n", }
err, uc_strerror(err));
if ( ( err = uc_hook_add( uc, &trace, UC_HOOK_CODE, &vm::emu_t::hook_code, this, module_base,
return false; module_base + image_size ) ) )
} {
std::printf( "failed on uc_hook_add() with error returned %u: %s\n", err, uc_strerror( err ) );
if ((err = uc_reg_write(uc, UC_X86_REG_RSP, &stack_addr)))
{ return false;
std::printf("failed on uc_reg_write() with error returned %u: %s\n", }
err, uc_strerror(err));
if ( ( err = uc_hook_add( uc, &trace1, UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED,
return false; vm::emu_t::hook_mem_invalid, this, 1, 0 ) ) )
} {
std::printf( "failed on uc_hook_add() with error returned %u: %s\n", err, uc_strerror( err ) );
if ((err = uc_hook_add(uc, &trace, UC_HOOK_CODE, &vm::emu_t::hook_code,
this, module_base, module_base + image_size))) return false;
{ }
std::printf("failed on uc_hook_add() with error returned %u: %s\n", return true;
err, uc_strerror(err)); }
return false; emu_t::~emu_t()
} {
if ( uc )
if ((err = uc_hook_add(uc, &trace1, UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED, uc_close( uc );
vm::emu_t::hook_mem_invalid, this, 1, 0))) }
{
std::printf("failed on uc_hook_add() with error returned %u: %s\n", bool emu_t::get_trace( std::vector< vmp2::v2::entry_t > &entries )
err, uc_strerror(err)); {
// hook_code will fill this vector up with values...
return false; trace_entries = &entries;
} uc_err err;
return true;
} if ( ( err = uc_emu_start( uc, vm_entry_rva + module_base, NULL, NULL, NULL ) ) )
{
emu_t::~emu_t() std::printf( "failed on uc_emu_start() with error returned %u: %s\n", err, uc_strerror( err ) );
{
if (uc) uc_close(uc); return false;
} }
return true;
bool emu_t::get_trace(std::vector<vmp2::v2::entry_t>& entries) }
{
// hook_code will fill this vector up with values... uc_err emu_t::create_entry( vmp2::v2::entry_t *entry )
trace_entries = &entries; {
uc_err err; uc_reg_read( uc, UC_X86_REG_R15, &entry->regs.r15 );
uc_reg_read( uc, UC_X86_REG_R14, &entry->regs.r14 );
if ((err = uc_emu_start(uc, vm_entry_rva + module_base, NULL, NULL, NULL))) uc_reg_read( uc, UC_X86_REG_R13, &entry->regs.r13 );
{ uc_reg_read( uc, UC_X86_REG_R12, &entry->regs.r12 );
std::printf("failed on uc_emu_start() with error returned %u: %s\n", uc_reg_read( uc, UC_X86_REG_R11, &entry->regs.r11 );
err, uc_strerror(err)); uc_reg_read( uc, UC_X86_REG_R10, &entry->regs.r10 );
uc_reg_read( uc, UC_X86_REG_R9, &entry->regs.r9 );
return false; uc_reg_read( uc, UC_X86_REG_R8, &entry->regs.r8 );
} uc_reg_read( uc, UC_X86_REG_RBP, &entry->regs.rbp );
return true; uc_reg_read( uc, UC_X86_REG_RDI, &entry->regs.rdi );
} uc_reg_read( uc, UC_X86_REG_RSI, &entry->regs.rsi );
uc_reg_read( uc, UC_X86_REG_RDX, &entry->regs.rdx );
uc_err emu_t::create_entry(vmp2::v2::entry_t* entry) uc_reg_read( uc, UC_X86_REG_RCX, &entry->regs.rcx );
{ uc_reg_read( uc, UC_X86_REG_RBX, &entry->regs.rbx );
uc_reg_read(uc, UC_X86_REG_R15, &entry->regs.r15); uc_reg_read( uc, UC_X86_REG_RAX, &entry->regs.rax );
uc_reg_read(uc, UC_X86_REG_R14, &entry->regs.r14); uc_reg_read( uc, UC_X86_REG_EFLAGS, &entry->regs.rflags );
uc_reg_read(uc, UC_X86_REG_R13, &entry->regs.r13);
uc_reg_read(uc, UC_X86_REG_R12, &entry->regs.r12); entry->vip = entry->regs.rsi;
uc_reg_read(uc, UC_X86_REG_R11, &entry->regs.r11); entry->handler_idx = entry->regs.rax;
uc_reg_read(uc, UC_X86_REG_R10, &entry->regs.r10); entry->decrypt_key = entry->regs.rbx;
uc_reg_read(uc, UC_X86_REG_R9, &entry->regs.r9);
uc_reg_read(uc, UC_X86_REG_R8, &entry->regs.r8); uc_err err;
uc_reg_read(uc, UC_X86_REG_RBP, &entry->regs.rbp); if ( ( err = uc_mem_read( uc, entry->regs.rdi, entry->vregs.raw, sizeof entry->vregs.raw ) ) )
uc_reg_read(uc, UC_X86_REG_RDI, &entry->regs.rdi); return err;
uc_reg_read(uc, UC_X86_REG_RSI, &entry->regs.rsi);
uc_reg_read(uc, UC_X86_REG_RDX, &entry->regs.rdx); // copy virtual stack values...
uc_reg_read(uc, UC_X86_REG_RCX, &entry->regs.rcx); for ( auto idx = 0u; idx < sizeof( entry->vsp ) / 8; ++idx )
uc_reg_read(uc, UC_X86_REG_RBX, &entry->regs.rbx); if ( ( err = uc_mem_read( uc, entry->regs.rbp + ( idx * 8 ), &entry->vsp.qword[ idx ],
uc_reg_read(uc, UC_X86_REG_RAX, &entry->regs.rax); sizeof entry->vsp.qword[ idx ] ) ) )
uc_reg_read(uc, UC_X86_REG_EFLAGS, &entry->regs.rflags); return err;
entry->vip = entry->regs.rsi; return UC_ERR_OK;
entry->handler_idx = entry->regs.rax; }
entry->decrypt_key = entry->regs.rbx;
void emu_t::hook_code( uc_engine *uc, uint64_t address, uint32_t size, vm::emu_t *obj )
uc_err err; {
if ((err = uc_mem_read(uc, entry->regs.rdi, std::printf( ">>> Tracing instruction at 0x%p, instruction size = 0x%x\n", address, size );
entry->vregs.raw, sizeof entry->vregs.raw)))
return err; // grab JMP RDX/RCX <-- this register...
static const auto jmp_reg = obj->vm_entry[ obj->vm_entry.size() ].instr.operands[ 0 ].reg.value;
// copy virtual stack values...
for (auto idx = 0u; idx < sizeof(entry->vsp) / 8; ++idx) static ZydisDecoder decoder;
if ((err = uc_mem_read(uc, entry->regs.rbp + (idx * 8), static std::once_flag once;
&entry->vsp.qword[idx], sizeof entry->vsp.qword[idx]))) static ZydisDecodedInstruction instr;
return err; static std::uintptr_t reg_val = 0u;
return UC_ERR_OK; // init zydis decoder just a single time...
} std::call_once( once, [ & ]() -> void {
ZydisDecoderInit( &decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_ADDRESS_WIDTH_64 );
void emu_t::hook_code(uc_engine* uc, uint64_t address, uint32_t size, vm::emu_t* obj) } );
{
std::printf(">>> Tracing instruction at 0x%p, instruction size = 0x%x\n", address, size);
// grab JMP RDX/RCX <-- this register...
static const auto jmp_reg = obj->vm_entry[obj->vm_entry.size()]
.instr.operands[0]
.reg
.value;
static ZydisDecoder decoder;
static std::once_flag once;
static ZydisDecodedInstruction instr;
static std::uintptr_t reg_val = 0u;
// init zydis decoder just a single time...
std::call_once(once, [&]() -> void {
ZydisDecoderInit(&decoder,
ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_ADDRESS_WIDTH_64); });
// last instruction in vm_entry is jmp rcx/rdx... // last instruction in vm_entry is jmp rcx/rdx...
if (address == obj->vm_entry[obj->vm_entry.size() - 1].addr) if ( address == obj->vm_entry[ obj->vm_entry.size() - 1 ].addr )
{ {
uc_err err; uc_err err;
vmp2::v2::entry_t new_entry; vmp2::v2::entry_t new_entry;
if ((err = obj->create_entry(&new_entry))) if ( ( err = obj->create_entry( &new_entry ) ) )
{ {
std::printf("[!] failed to create new entry... reason = %u, %s\n", std::printf( "[!] failed to create new entry... reason = %u, %s\n", err, uc_strerror( err ) );
err, uc_strerror(err));
exit( 0 );
exit(0); }
} obj->trace_entries->push_back( new_entry );
obj->trace_entries->push_back(new_entry); }
} // if we are getting a callback for a JMP RCX/RDX instruction...
// if we are getting a callback for a JMP RCX/RDX instruction... else if ( ZYAN_SUCCESS(
else if (ZYAN_SUCCESS(ZydisDecoderDecodeBuffer( ZydisDecoderDecodeBuffer( &decoder, reinterpret_cast< void * >( address ), size, &instr ) ) &&
&decoder, reinterpret_cast<void*>(address), size, &instr)) && instr.mnemonic == ZYDIS_MNEMONIC_JMP && instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.mnemonic == ZYDIS_MNEMONIC_JMP && instr.operands[ 0 ].reg.value == jmp_reg )
instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER && {
instr.operands[0].reg.value == jmp_reg) switch ( jmp_reg )
{ {
switch (jmp_reg) case ZYDIS_REGISTER_RDX:
{ uc_reg_read( uc, UC_X86_REG_RDX, &reg_val );
case ZYDIS_REGISTER_RDX: break;
uc_reg_read(uc, UC_X86_REG_RDX, &reg_val); case ZYDIS_REGISTER_RCX:
break; uc_reg_read( uc, UC_X86_REG_RCX, &reg_val );
case ZYDIS_REGISTER_RCX: break;
uc_reg_read(uc, UC_X86_REG_RCX, &reg_val); default:
break; std::printf( "[!] invalid jump register... = %d\n", jmp_reg );
default: exit( 0 );
std::printf("[!] invalid jump register... = %d\n", jmp_reg); }
exit(0);
} // checks to see if the address
// in JMP RDX/RCX is a vm handler address...
// checks to see if the address static const auto vm_handler_check = [ & ]( const vm::handler::handler_t &vm_handler ) -> bool {
// in JMP RDX/RCX is a vm handler address... return vm_handler.address == reg_val;
static const auto vm_handler_check = };
[&](const vm::handler::handler_t& vm_handler) -> bool
{ return vm_handler.address == reg_val; }; if ( std::find_if( obj->vm_handlers.begin(), obj->vm_handlers.end(), vm_handler_check ) ==
obj->vm_handlers.end() )
if (std::find_if(obj->vm_handlers.begin(), obj->vm_handlers.end(), return;
vm_handler_check) == obj->vm_handlers.end())
return; uc_err err;
vmp2::v2::entry_t new_entry;
uc_err err; if ( ( err = obj->create_entry( &new_entry ) ) )
vmp2::v2::entry_t new_entry; {
if ((err = obj->create_entry(&new_entry))) std::printf( "[!] failed to create new entry... reason = %u, %s\n", err, uc_strerror( err ) );
{
std::printf("[!] failed to create new entry... reason = %u, %s\n", exit( 0 );
err, uc_strerror(err)); }
obj->trace_entries->push_back( new_entry );
exit(0); }
} else if ( instr.mnemonic == ZYDIS_MNEMONIC_RET ) // finish tracing...
obj->trace_entries->push_back(new_entry); uc_emu_stop( uc );
} }
else if (instr.mnemonic == ZYDIS_MNEMONIC_RET) // finish tracing...
uc_emu_stop(uc); bool emu_t::hook_mem_invalid( uc_engine *uc, uc_mem_type type, uint64_t address, int size, int64_t value,
} vm::emu_t *obj )
{
bool emu_t::hook_mem_invalid(uc_engine* uc, uc_mem_type type, uc_err err;
uint64_t address, int size, int64_t value, vm::emu_t* obj) if ( ( err = uc_mem_map( obj->uc, address & ~0xFFFull, 0x1000, UC_PROT_ALL ) ) )
{ std::printf( "failed on uc_mem_map() with error returned %u: %s\n", err, uc_strerror( err ) );
uc_err err;
if ((err = uc_mem_map(obj->uc, address & ~0xFFFull, 0x1000, UC_PROT_ALL))) switch ( type )
std::printf("failed on uc_mem_map() with error returned %u: %s\n", {
err, uc_strerror(err)); case UC_MEM_WRITE_UNMAPPED:
printf( ">>> Missing memory is being WRITE at 0x%p, data size = %u, data value = 0x%p\n", address, size,
switch (type) value );
{ return true;
case UC_MEM_WRITE_UNMAPPED: case UC_MEM_READ_UNMAPPED:
printf(">>> Missing memory is being WRITE at 0x%p, data size = %u, data value = 0x%p\n", printf( ">>> Missing memory is being READ at 0x%p, data size = %u, data value = 0x%p\n", address, size,
address, size, value); value );
return true; return true;
case UC_MEM_READ_UNMAPPED: default:
printf(">>> Missing memory is being READ at 0x%p, data size = %u, data value = 0x%p\n", printf( ">>> Missing memory at 0x%p, data size = %u, data value = 0x%p\n", address, size, value );
address, size, value); return true;
return true; }
default: }
printf(">>> Missing memory at 0x%p, data size = %u, data value = 0x%p\n", } // namespace vm
address, size, value);
return true;
}
}
}

@ -1,41 +1,42 @@
#pragma once #pragma once
#include <exception> #include <Zydis/Zydis.h>
#include <cstdint> #include <cstdint>
#include <unicorn/unicorn.h> #include <exception>
#include <xtils.hpp>
#include <vmprofiler.hpp>
#include <functional> #include <functional>
#include <mutex> #include <mutex>
#include <unicorn/unicorn.h>
#include <vmp2.hpp> #include <vmp2.hpp>
#include <Zydis/Zydis.h> #include <vmprofiler.hpp>
#include <xtils.hpp>
namespace vm namespace vm
{ {
class emu_t class emu_t
{ {
using callback_t = std::function<void(uc_engine*, uint64_t, uint32_t, void*)>; using callback_t = std::function< void( uc_engine *, uint64_t, uint32_t, void * ) >;
public:
explicit emu_t(std::uint32_t vm_entry_rva, public:
std::uintptr_t image_base, std::uintptr_t module_base); explicit emu_t( std::uint32_t vm_entry_rva, std::uintptr_t image_base, std::uintptr_t module_base );
~emu_t(); ~emu_t();
bool init();
bool get_trace( std::vector< vmp2::v2::entry_t > &entries );
bool init(); private:
bool get_trace(std::vector<vmp2::v2::entry_t>& entries); uc_err create_entry( vmp2::v2::entry_t *entry );
private: static void hook_code( uc_engine *uc, uint64_t address, uint32_t size, vm::emu_t *obj );
uc_err create_entry(vmp2::v2::entry_t* entry); static bool hook_mem_invalid( uc_engine *uc, uc_mem_type type, uint64_t address, int size, int64_t value,
static void hook_code(uc_engine* uc, uint64_t address, uint32_t size, vm::emu_t* obj); vm::emu_t *obj );
static bool hook_mem_invalid(uc_engine* uc, uc_mem_type type,
uint64_t address, int size, int64_t value, vm::emu_t* obj);
uc_engine* uc; uc_engine *uc;
uc_hook trace, trace1; uc_hook trace, trace1;
std::uintptr_t image_base, module_base; std::uintptr_t image_base, module_base;
std::uint32_t vm_entry_rva; std::uint32_t vm_entry_rva;
zydis_routine_t vm_entry; zydis_routine_t vm_entry;
std::uintptr_t* vm_handler_table; std::uintptr_t *vm_handler_table;
std::vector<vm::handler::handler_t> vm_handlers; std::vector< vm::handler::handler_t > vm_handlers;
std::vector<vmp2::v2::entry_t>* trace_entries; std::vector< vmp2::v2::entry_t > *trace_entries;
}; };
} } // namespace vm
Loading…
Cancel
Save