unpacker is working. need to add reloc stuff and it should be good..

merge-requests/6/head
_xeroxz 3 years ago
parent 3dd5f9d7ca
commit 0007b4024e

@ -1,9 +1,10 @@
#pragma once #pragma once
#include <functional>
#include <unicorn/unicorn.h> #include <unicorn/unicorn.h>
#include <Zydis/Zydis.h> #include <Zydis/Zydis.h>
#include <atomic> #include <atomic>
#include <functional> #include <fstream>
#include <map> #include <map>
#include <nt/image.hpp> #include <nt/image.hpp>
#include <vector> #include <vector>
@ -11,18 +12,18 @@
#define PAGE_4KB 0x1000 #define PAGE_4KB 0x1000
#define STACK_SIZE PAGE_4KB * 512 #define STACK_SIZE PAGE_4KB * 512
#define IAT_VECTOR_TABLE 0xFFFFF0000000000 #define IAT_VECTOR_TABLE 0xFFFFF00000000000
#define STACK_BASE 0xFFFF000000000000 #define STACK_BASE 0xFFFF000000000000
#define HEAP_BASE 0xFFF0000000000000
#define EX_ALLOCATE_POOL_VECTOR 0 #define EX_ALLOCATE_POOL_VECTOR 0
#define EX_FREE_POOL_VECTOR 1 #define EX_FREE_POOL_VECTOR 1
#define LOCAL_ALLOC_VECTOR 2 #define LOCAL_ALLOC_VECTOR 2
#define LOCAL_FREE_VECTOR 3 #define LOCAL_FREE_VECTOR 3
#define LOAD_LIBRARY_VECTOR 4
namespace engine namespace engine
{ {
using iat_hook_t = std::function< void( uc_engine * ) >;
class unpack_t class unpack_t
{ {
public: public:
@ -33,28 +34,36 @@ namespace engine
bool unpack( std::vector< std::uint8_t > &output ); bool unpack( std::vector< std::uint8_t > &output );
private: private:
using iat_hook_t = std::function< void( uc_engine *, unpack_t * ) >;
uc_engine *uc_ctx; uc_engine *uc_ctx;
std::vector< uint8_t > bin, map_bin; std::vector< uint8_t > bin, map_bin;
std::vector< uc_hook * > uc_hooks; std::vector< uc_hook * > uc_hooks;
std::uintptr_t img_base, img_size; std::uintptr_t img_base, img_size, heap_offset, pack_section_offset;
win::image_t<> *win_img; win::image_t<> *win_img;
static void alloc_pool_hook( uc_engine * ); static void alloc_pool_hook( uc_engine *, unpack_t * );
static void free_pool_hook( uc_engine * ); static void free_pool_hook( uc_engine *, unpack_t * );
static void local_alloc_hook( uc_engine * ); static void local_alloc_hook( uc_engine *, unpack_t * );
static void local_free_hook( uc_engine * ); static void local_free_hook( uc_engine *, unpack_t * );
static void load_library_hook( uc_engine *, unpack_t * );
static void uc_strcpy( uc_engine *, char *buff, std::uintptr_t addr );
static bool iat_dispatcher( uc_engine *uc, uint64_t address, uint32_t size, unpack_t *unpack ); static bool iat_dispatcher( uc_engine *uc, uint64_t address, uint32_t size, unpack_t *unpack );
static bool unpack_section_callback( uc_engine *uc, uint64_t address, uint32_t size, unpack_t *unpack ); static bool unpack_section_callback( uc_engine *uc, uc_mem_type type, uint64_t address, int size, int64_t value,
unpack_t *unpack );
static bool code_exec_callback( uc_engine *uc, uint64_t address, uint32_t size, unpack_t *unpack ); static bool code_exec_callback( uc_engine *uc, uint64_t address, uint32_t size, unpack_t *unpack );
static void invalid_mem( uc_engine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, static void invalid_mem( uc_engine *uc, uc_mem_type type, uint64_t address, int size, int64_t value,
unpack_t *unpack ); unpack_t *unpack );
std::vector< std::uintptr_t > loaded_modules;
std::map< std::string, std::pair< std::uint32_t, iat_hook_t > > iat_hooks = { std::map< std::string, std::pair< std::uint32_t, iat_hook_t > > iat_hooks = {
{ "ExAllocatePool", { EX_ALLOCATE_POOL_VECTOR, &alloc_pool_hook } }, { "ExAllocatePool", { EX_ALLOCATE_POOL_VECTOR, &alloc_pool_hook } },
{ "ExFreePool", { EX_FREE_POOL_VECTOR, &free_pool_hook } }, { "ExFreePool", { EX_FREE_POOL_VECTOR, &free_pool_hook } },
{ "LocalAlloc", { LOCAL_ALLOC_VECTOR, &local_alloc_hook } }, { "LocalAlloc", { LOCAL_ALLOC_VECTOR, &local_alloc_hook } },
{ "LocalFree", { LOCAL_FREE_VECTOR, &local_free_hook } } }; { "LocalFree", { LOCAL_FREE_VECTOR, &local_free_hook } },
{ "LoadLibraryA", { LOAD_LIBRARY_VECTOR, &load_library_hook } } };
}; };
} // namespace engine } // namespace engine

@ -144,7 +144,8 @@ int __cdecl main( int argc, const char *argv[] )
return -1; return -1;
} }
std::ofstream output( parser.get< std::string >( "output" ), std::ios::binary ); std::printf( "> writing result to = %s\n", parser.get< std::string >( "out" ).c_str() );
std::ofstream output( parser.get< std::string >( "out" ), std::ios::binary );
output.write( reinterpret_cast< char * >( unpacked_bin.data() ), unpacked_bin.size() ); output.write( reinterpret_cast< char * >( unpacked_bin.data() ), unpacked_bin.size() );
output.close(); output.close();
} }

@ -2,7 +2,8 @@
namespace engine namespace engine
{ {
unpack_t::unpack_t( const std::vector< std::uint8_t > &packed_bin ) : bin( packed_bin ), uc_ctx( nullptr ) unpack_t::unpack_t( const std::vector< std::uint8_t > &packed_bin )
: bin( packed_bin ), uc_ctx( nullptr ), heap_offset( 0ull ), pack_section_offset( 0ull )
{ {
win_img = reinterpret_cast< win::image_t<> * >( bin.data() ); win_img = reinterpret_cast< win::image_t<> * >( bin.data() );
img_base = win_img->get_nt_headers()->optional_header.image_base; img_base = win_img->get_nt_headers()->optional_header.image_base;
@ -68,15 +69,9 @@ namespace engine
win::section_header_t *sec_begin = win_img->get_nt_headers()->get_sections(), win::section_header_t *sec_begin = win_img->get_nt_headers()->get_sections(),
*sec_end = sec_begin + win_img->get_nt_headers()->file_header.num_sections; *sec_end = sec_begin + win_img->get_nt_headers()->file_header.num_sections;
// map sections...
std::for_each( sec_begin, sec_end, [ & ]( const win::section_header_t &sec_header ) { std::for_each( sec_begin, sec_end, [ & ]( const win::section_header_t &sec_header ) {
memcpy( map_bin.data() + sec_header.virtual_address, bin.data() + sec_header.ptr_raw_data, memcpy( map_bin.data() + sec_header.virtual_address, bin.data() + sec_header.ptr_raw_data,
sec_header.size_raw_data ); sec_header.size_raw_data );
std::printf(
"> mapped section = %s, virt address = 0x%p, virt size = 0x%x, phys offset = 0x%x, phys size = 0x%x\n",
sec_header.name.to_string().data(), sec_header.virtual_address, sec_header.virtual_size,
sec_header.ptr_raw_data, sec_header.size_raw_data );
} ); } );
auto basereloc_dir = win_img->get_directory( win::directory_id::directory_entry_basereloc ); auto basereloc_dir = win_img->get_directory( win::directory_id::directory_entry_basereloc );
@ -110,8 +105,8 @@ namespace engine
win_img->get_directory( win::directory_id::directory_entry_import )->rva + map_bin.data() ); win_img->get_directory( win::directory_id::directory_entry_import )->rva + map_bin.data() );
import_dir->rva_name; ++import_dir ) import_dir->rva_name; ++import_dir )
{ {
for ( auto iat_thunk = reinterpret_cast< win::image_thunk_data_t<> * >( for ( auto iat_thunk =
import_dir->rva_original_first_thunk + map_bin.data() ); reinterpret_cast< win::image_thunk_data_t<> * >( import_dir->rva_first_thunk + map_bin.data() );
iat_thunk->address; ++iat_thunk ) iat_thunk->address; ++iat_thunk )
{ {
auto iat_name = reinterpret_cast< win::image_named_import_t * >( iat_thunk->address + map_bin.data() ); auto iat_name = reinterpret_cast< win::image_named_import_t * >( iat_thunk->address + map_bin.data() );
@ -120,6 +115,8 @@ namespace engine
} }
} }
*reinterpret_cast< std::uintptr_t * >( map_bin.data() + 0x599038 ) = LOAD_LIBRARY_VECTOR + IAT_VECTOR_TABLE;
// map the entire map buffer into unicorn-engine since we have set everything else up... // map the entire map buffer into unicorn-engine since we have set everything else up...
if ( ( err = uc_mem_write( uc_ctx, img_base, map_bin.data(), map_bin.size() ) ) ) if ( ( err = uc_mem_write( uc_ctx, img_base, map_bin.data(), map_bin.size() ) ) )
{ {
@ -140,7 +137,8 @@ namespace engine
uc_hooks.push_back( new uc_hook ); uc_hooks.push_back( new uc_hook );
if ( ( err = uc_hook_add( uc_ctx, uc_hooks.back(), if ( ( err = uc_hook_add( uc_ctx, uc_hooks.back(),
UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED | UC_HOOK_MEM_FETCH_UNMAPPED, UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED | UC_HOOK_MEM_FETCH_UNMAPPED |
UC_HOOK_INSN_INVALID,
&engine::unpack_t::invalid_mem, this, true, false ) ) ) &engine::unpack_t::invalid_mem, this, true, false ) ) )
{ {
std::printf( "> uc_hook_add error, reason = %d\n", err ); std::printf( "> uc_hook_add error, reason = %d\n", err );
@ -150,10 +148,10 @@ namespace engine
// execution break points on all sections that are executable but have no physical size on disk... // execution break points on all sections that are executable but have no physical size on disk...
std::for_each( sec_begin, sec_end, [ & ]( win::section_header_t &header ) { std::for_each( sec_begin, sec_end, [ & ]( win::section_header_t &header ) {
if ( !header.ptr_raw_data && !header.size_raw_data && header.characteristics.mem_execute && if ( !header.ptr_raw_data && !header.size_raw_data && header.characteristics.mem_execute &&
!header.is_discardable() ) header.characteristics.mem_write && !header.is_discardable() )
{ {
uc_hooks.push_back( new uc_hook ); uc_hooks.push_back( new uc_hook );
if ( ( err = uc_hook_add( uc_ctx, uc_hooks.back(), UC_HOOK_CODE, if ( ( err = uc_hook_add( uc_ctx, uc_hooks.back(), UC_HOOK_CODE | UC_HOOK_MEM_WRITE,
&engine::unpack_t::unpack_section_callback, this, &engine::unpack_t::unpack_section_callback, this,
header.virtual_address + img_base, header.virtual_address + img_base,
header.virtual_address + header.virtual_size + img_base ) ) ) header.virtual_address + header.virtual_size + img_base ) ) )
@ -162,6 +160,7 @@ namespace engine
return false; return false;
} }
pack_section_offset = header.virtual_address + header.virtual_size;
std::printf( "> adding unpack watch on section = %s\n", header.name.to_string().data() ); std::printf( "> adding unpack watch on section = %s\n", header.name.to_string().data() );
} }
else if ( header.characteristics.mem_execute ) else if ( header.characteristics.mem_execute )
@ -201,29 +200,139 @@ namespace engine
} }
std::printf( "> beginning execution at = 0x%p\n", rip ); std::printf( "> beginning execution at = 0x%p\n", rip );
if ( ( err = uc_emu_start( uc_ctx, rip, 0ull, 0ull, 0ull ) ) ) if ( ( err = uc_emu_start( uc_ctx, rip, 0ull, 0ull, 0ull ) ) )
{ {
std::printf( "> error starting emu... reason = %d\n", err ); std::printf( "> error starting emu... reason = %d\n", err );
return false; return false;
} }
output.resize( img_size );
if ( ( err = uc_mem_read( uc_ctx, img_base, output.data(), output.size() ) ) )
{
std::printf( "> uc_mem_read failed... err = %d\n", err );
return false;
}
auto img = reinterpret_cast< win::image_t<> * >( output.data() );
auto sections = img->get_nt_headers()->get_sections();
auto section_cnt = img->get_file_header()->num_sections;
std::for_each( sections, sections + section_cnt, [ & ]( win::section_header_t &header ) {
header.ptr_raw_data = header.virtual_address;
header.size_raw_data = header.virtual_size;
} );
return true; return true;
} }
void unpack_t::alloc_pool_hook( uc_engine *uc_ctx ) void unpack_t::alloc_pool_hook( uc_engine *uc_ctx, unpack_t *obj )
{ {
// TODO
} }
void unpack_t::free_pool_hook( uc_engine *uc_ctx ) void unpack_t::free_pool_hook( uc_engine *uc_ctx, unpack_t *obj )
{ {
// TODO
} }
void unpack_t::local_alloc_hook( uc_engine *uc_ctx ) void unpack_t::local_alloc_hook( uc_engine *uc_ctx, unpack_t *obj )
{ {
uc_err err;
std::uintptr_t rax, rdx;
if ( ( err = uc_reg_read( uc_ctx, UC_X86_REG_RDX, &rdx ) ) )
{
std::printf( "> failed to read RDX... reason = %d\n", rdx );
return;
}
auto size = ( ( rdx + PAGE_4KB ) & ~0xFFFull );
if ( ( err = uc_mem_map( uc_ctx, HEAP_BASE + obj->heap_offset, size, UC_PROT_ALL ) ) )
{
std::printf( "> failed to allocate memory... reason = %d\n", err );
return;
}
rax = HEAP_BASE + obj->heap_offset;
obj->heap_offset += size;
if ( ( err = uc_reg_write( uc_ctx, UC_X86_REG_RAX, &rax ) ) )
{
std::printf( "> failed to write rax... reason = %d\n", err );
return;
}
} }
void unpack_t::local_free_hook( uc_engine *uc_ctx ) void unpack_t::local_free_hook( uc_engine *uc_ctx, unpack_t *obj )
{ {
// TODO
}
void unpack_t::load_library_hook( uc_engine *uc_ctx, unpack_t *obj )
{
uc_err err;
std::uintptr_t rcx = 0ull;
if ( ( err = uc_reg_read( uc_ctx, UC_X86_REG_RCX, &rcx ) ) )
{
std::printf( "> uc_reg_read error, reason = %d\n", err );
return;
}
char buff[ 256 ];
uc_strcpy( uc_ctx, buff, rcx );
std::printf( "> LoadLibraryA(\"%s\")\n", buff );
auto module_base = reinterpret_cast< std::uintptr_t >( LoadLibraryA( buff ) );
auto module_size =
reinterpret_cast< win::image_t<> * >( module_base )->get_nt_headers()->optional_header.size_image;
if ( std::find( obj->loaded_modules.begin(), obj->loaded_modules.end(), module_base ) !=
obj->loaded_modules.end() )
{
if ( ( err = uc_reg_write( uc_ctx, UC_X86_REG_RAX, &module_base ) ) )
{
std::printf( "> failed to set rax... reason = %d\n", err );
return;
}
}
else
{
if ( ( err = uc_mem_map( uc_ctx, module_base, module_size, UC_PROT_ALL ) ) )
{
std::printf( "> failed to load library... reason = %d\n", err );
return;
}
if ( ( err = uc_mem_write( uc_ctx, module_base, reinterpret_cast< void * >( module_base ), module_size ) ) )
{
std::printf( "> failed to copy module into emulator... reason = %d\n", err );
return;
}
if ( ( err = uc_reg_write( uc_ctx, UC_X86_REG_RAX, &module_base ) ) )
{
std::printf( "> failed to set rax... reason = %d\n", err );
return;
}
obj->loaded_modules.push_back( module_base );
}
}
void unpack_t::uc_strcpy( uc_engine *uc_ctx, char *buff, std::uintptr_t addr )
{
uc_err err;
char i = 0u;
auto idx = 0ul;
do
{
if ( ( err = uc_mem_read( uc_ctx, addr + idx, &i, sizeof i ) ) )
break;
} while ( ( buff[ idx++ ] = i ) );
} }
bool unpack_t::iat_dispatcher( uc_engine *uc, uint64_t address, uint32_t size, unpack_t *unpack ) bool unpack_t::iat_dispatcher( uc_engine *uc, uint64_t address, uint32_t size, unpack_t *unpack )
@ -234,7 +343,7 @@ namespace engine
if ( iat_hook_data.first == vec ) if ( iat_hook_data.first == vec )
{ {
std::printf( "> hooking import = %s\n", iat_name.c_str() ); std::printf( "> hooking import = %s\n", iat_name.c_str() );
iat_hook_data.second( uc ); iat_hook_data.second( uc, unpack );
return true; return true;
} }
} }
@ -256,19 +365,33 @@ namespace engine
auto instr_ptr = reinterpret_cast< void * >( unpack->map_bin.data() + ( address - unpack->img_base ) ); auto instr_ptr = reinterpret_cast< void * >( unpack->map_bin.data() + ( address - unpack->img_base ) );
if ( ZYAN_SUCCESS( ZydisDecoderDecodeBuffer( &decoder, instr_ptr, PAGE_4KB, &instr ) ) ) if ( ZYAN_SUCCESS( ZydisDecoderDecodeBuffer( &decoder, instr_ptr, PAGE_4KB, &instr ) ) )
{ {
char buffer[ 0x1000 ]; if ( instr.mnemonic == ZYDIS_MNEMONIC_CALL && instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
ZydisFormatterFormatInstruction( &formatter, &instr, buffer, sizeof( buffer ), address ); instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RAX )
std::printf( "> 0x%p ", address ); {
puts( buffer ); std::uintptr_t rax = 0u, rip = 0u;
uc_reg_read( uc, UC_X86_REG_RAX, &rax );
uc_reg_read( uc, UC_X86_REG_RIP, &rip );
if ( rax > unpack->img_base + unpack->img_size )
{
rip += instr.length;
uc_reg_write( uc, UC_X86_REG_RIP, &rip );
}
}
} }
return true; return true;
} }
bool unpack_t::unpack_section_callback( uc_engine *uc, uint64_t address, uint32_t size, unpack_t *unpack ) bool unpack_t::unpack_section_callback( uc_engine *uc, uc_mem_type type, uint64_t address, int size, int64_t value,
unpack_t *unpack )
{ {
std::printf( "> might be dump time...\n" ); if ( address == unpack->pack_section_offset + unpack->img_base )
std::getchar(); {
std::printf( "> dumping...\n" );
uc_emu_stop( uc );
return false;
}
return true; return true;
} }
@ -285,8 +408,10 @@ namespace engine
value ); value );
break; break;
case UC_MEM_FETCH_UNMAPPED: case UC_MEM_FETCH_UNMAPPED:
{
std::printf( ">>> fetching invalid instructions at address = 0x%p\n", address ); std::printf( ">>> fetching invalid instructions at address = 0x%p\n", address );
break; break;
}
default: default:
break; break;
} }

Loading…
Cancel
Save