diff --git a/include/vmprofiler.hpp b/include/vmprofiler.hpp
index bf8d74b..9cbc78e 100644
--- a/include/vmprofiler.hpp
+++ b/include/vmprofiler.hpp
@@ -5,25 +5,6 @@
namespace vm
{
- namespace calc_jmp
- {
- bool get( const zydis_routine_t &vm_entry, zydis_routine_t &calc_jmp );
-
- std::optional< vmp2::exec_type_t > get_advancement( const zydis_routine_t &calc_jmp );
- } // namespace calc_jmp
-
- namespace instrs
- {
- // decrypt transformations for encrypted virtual instruction rva...
- bool get_rva_decrypt( const zydis_routine_t &vm_entry, std::vector< zydis_decoded_instr_t > &transform_instrs );
-
- std::pair< std::uint64_t, std::uint64_t > decrypt_operand( transform::map_t &transforms, std::uint64_t operand,
- std::uint64_t rolling_key );
-
- std::pair< std::uint64_t, std::uint64_t > encrypt_operand( transform::map_t &transforms, std::uint64_t operand,
- std::uint64_t rolling_key );
- } // namespace instrs
-
namespace handler
{
using instr_callback_t = bool ( * )( const zydis_decoded_instr_t &instr );
@@ -187,4 +168,89 @@ namespace vm
&lrflags, &vmexit, &call };
} // namespace profile
} // namespace handler
+
+ class ctx_t
+ {
+ public:
+ explicit ctx_t( std::uintptr_t module_base, std::uintptr_t image_base, std::uint32_t vm_entry_rva );
+ ctx_t( std::vector< vm::handler::handler_t > &vm_handlers, zydis_routine_t &vm_entry, zydis_routine_t &calc_jmp,
+ vmp2::exec_type_t exec_type );
+
+ vmp2::exec_type_t exec_type;
+ zydis_routine_t vm_entry, calc_jmp;
+ std::vector< vm::handler::handler_t > vm_handlers;
+ };
+
+ namespace instrs
+ {
+ struct virt_instr_t
+ {
+ vm::handler::mnemonic_t mnemonic_t;
+ std::uint8_t opcode; // aka vm handler idx...
+
+ // can be used to look at values on the stack...
+ vmp2::v2::entry_t trace_data;
+
+ struct
+ {
+ bool has_imm;
+ struct
+ {
+ std::uint8_t imm_size; // size in bits...
+ union
+ {
+ std::int64_t s;
+ std::uint64_t u;
+ };
+ } imm;
+ } operand;
+ };
+
+ enum class jcc_type
+ {
+ none,
+ branching,
+ absolute
+ };
+
+ struct code_block_t
+ {
+ struct
+ {
+ bool has_jcc;
+ jcc_type type;
+ std::uint32_t block_rva[ 2 ];
+ } jcc;
+
+ std::uint32_t code_block_rva;
+ std::vector< virt_instr_t > vinstrs;
+ };
+
+ // decrypt transformations for encrypted virtual instruction rva...
+ bool get_rva_decrypt( const zydis_routine_t &vm_entry, std::vector< zydis_decoded_instr_t > &transform_instrs );
+
+ std::pair< std::uint64_t, std::uint64_t > decrypt_operand( transform::map_t &transforms, std::uint64_t operand,
+ std::uint64_t rolling_key );
+
+ std::pair< std::uint64_t, std::uint64_t > encrypt_operand( transform::map_t &transforms, std::uint64_t operand,
+ std::uint64_t rolling_key );
+
+ std::optional< virt_instr_t > get( vm::ctx_t &ctx, vmp2::v2::entry_t &entry );
+
+ ///
+ /// gets the second operand (imm) given vip and vm::ctx_t...
+ ///
+ /// vm context
+ /// immediate value size in bits...
+ /// virtual instruction pointer, linear virtual address...
+ /// returns immediate value if imm_size is not 0...
+ std::optional< std::uint64_t > get_imm( vm::ctx_t &ctx, std::uint8_t imm_size, std::uintptr_t vip );
+ } // namespace instrs
+
+ namespace calc_jmp
+ {
+ bool get( const zydis_routine_t &vm_entry, zydis_routine_t &calc_jmp );
+
+ std::optional< vmp2::exec_type_t > get_advancement( const zydis_routine_t &calc_jmp );
+ } // namespace calc_jmp
} // namespace vm
\ No newline at end of file
diff --git a/src/vmctx.cpp b/src/vmctx.cpp
new file mode 100644
index 0000000..0b7e1ef
--- /dev/null
+++ b/src/vmctx.cpp
@@ -0,0 +1,20 @@
+#include
+
+namespace vm
+{
+ ctx_t::ctx_t( std::uintptr_t module_base, std::uintptr_t image_base, std::uint32_t vm_entry_rva )
+ {
+ vm::util::flatten( vm_entry, vm_entry_rva + module_base );
+ vm::util::deobfuscate( vm_entry );
+ vm::calc_jmp::get( vm_entry, calc_jmp );
+
+ auto vm_handler_table = vm::handler::table::get( vm_entry );
+ vm::handler::get_all( module_base, image_base, vm_entry, vm_handler_table, vm_handlers );
+ }
+
+ ctx_t::ctx_t( std::vector< vm::handler::handler_t > &vm_handlers, zydis_routine_t &vm_entry,
+ zydis_routine_t &calc_jmp, vmp2::exec_type_t exec_type )
+ : vm_handlers( vm_handlers ), vm_entry( vm_entry ), calc_jmp( calc_jmp ), exec_type( exec_type )
+ {
+ }
+} // namespace vm
\ No newline at end of file
diff --git a/src/vminstrs.cpp b/src/vminstrs.cpp
index 9d92817..066e159 100644
--- a/src/vminstrs.cpp
+++ b/src/vminstrs.cpp
@@ -7,12 +7,12 @@ namespace vm
std::pair< std::uint64_t, std::uint64_t > decrypt_operand( transform::map_t &transforms, std::uint64_t operand,
std::uint64_t rolling_key )
{
- const auto& generic_decrypt_0 = transforms[ transform::type::generic0 ];
- const auto& key_decrypt = transforms[ transform::type::rolling_key ];
- const auto& generic_decrypt_1 = transforms[ transform::type::generic1 ];
- const auto& generic_decrypt_2 = transforms[ transform::type::generic2 ];
- const auto& generic_decrypt_3 = transforms[ transform::type::generic3 ];
- const auto& update_key = transforms[ transform::type::update_key ];
+ const auto &generic_decrypt_0 = transforms[ transform::type::generic0 ];
+ const auto &key_decrypt = transforms[ transform::type::rolling_key ];
+ const auto &generic_decrypt_1 = transforms[ transform::type::generic1 ];
+ const auto &generic_decrypt_2 = transforms[ transform::type::generic2 ];
+ const auto &generic_decrypt_3 = transforms[ transform::type::generic3 ];
+ const auto &update_key = transforms[ transform::type::update_key ];
if ( generic_decrypt_0.mnemonic != ZYDIS_MNEMONIC_INVALID )
{
@@ -44,8 +44,7 @@ namespace vm
}
// update rolling key...
- auto result =
- transform::apply( update_key.operands[ 0 ].size, update_key.mnemonic, rolling_key, operand );
+ auto result = transform::apply( update_key.operands[ 0 ].size, update_key.mnemonic, rolling_key, operand );
// update decryption key correctly...
switch ( update_key.operands[ 0 ].size )
@@ -70,15 +69,14 @@ namespace vm
transform::map_t inverse;
inverse_transforms( transforms, inverse );
- const auto& generic_decrypt_0 = inverse[ transform::type::generic0 ];
- const auto& key_decrypt = inverse[ transform::type::rolling_key ];
- const auto& generic_decrypt_1 = inverse[ transform::type::generic1 ];
- const auto& generic_decrypt_2 = inverse[ transform::type::generic2 ];
- const auto& generic_decrypt_3 = inverse[ transform::type::generic3 ];
- const auto& update_key = inverse[ transform::type::update_key ];
+ const auto &generic_decrypt_0 = inverse[ transform::type::generic0 ];
+ const auto &key_decrypt = inverse[ transform::type::rolling_key ];
+ const auto &generic_decrypt_1 = inverse[ transform::type::generic1 ];
+ const auto &generic_decrypt_2 = inverse[ transform::type::generic2 ];
+ const auto &generic_decrypt_3 = inverse[ transform::type::generic3 ];
+ const auto &update_key = inverse[ transform::type::update_key ];
- auto result =
- transform::apply( update_key.operands[ 0 ].size, update_key.mnemonic, rolling_key, operand );
+ auto result = transform::apply( update_key.operands[ 0 ].size, update_key.mnemonic, rolling_key, operand );
// make sure we update the rolling decryption key correctly...
switch ( update_key.operands[ 0 ].size )
@@ -162,5 +160,41 @@ namespace vm
return true;
}
+
+ std::optional< std::uint64_t > get_imm( vm::ctx_t &ctx, std::uint8_t imm_size, std::uintptr_t vip )
+ {
+ if ( !imm_size )
+ return {};
+
+ return ctx.exec_type == vmp2::exec_type_t::forward
+ ? *reinterpret_cast< std::uintptr_t * >( vip + ( imm_size / 8 ) )
+ : *reinterpret_cast< std::uintptr_t * >( vip - ( imm_size / 8 ) );
+ }
+
+ std::optional< virt_instr_t > get( vm::ctx_t &ctx, vmp2::v2::entry_t &entry )
+ {
+ virt_instr_t result;
+ const auto &vm_handler = ctx.vm_handlers[ entry.handler_idx ];
+ const auto profile = vm_handler.profile;
+
+ result.mnemonic_t = profile ? profile->mnemonic : vm::handler::mnemonic_t::INVALID;
+ result.opcode = entry.handler_idx;
+ result.trace_data = entry;
+
+ if ( vm_handler.imm_size )
+ {
+ result.operand.has_imm = true;
+ const auto imm_val = get_imm( ctx, vm_handler.imm_size, entry.vip );
+
+ if ( !imm_val.has_value() )
+ return {};
+
+ result.operand.imm.u = imm_val.value();
+ }
+ else
+ result.operand.has_imm = false;
+
+ return result;
+ }
} // namespace instrs
} // namespace vm
\ No newline at end of file
diff --git a/vmprofiler.vcxproj b/vmprofiler.vcxproj
index 760225c..e357f76 100644
--- a/vmprofiler.vcxproj
+++ b/vmprofiler.vcxproj
@@ -156,6 +156,7 @@
+
diff --git a/vmprofiler.vcxproj.filters b/vmprofiler.vcxproj.filters
index 99d0148..7c02f19 100644
--- a/vmprofiler.vcxproj.filters
+++ b/vmprofiler.vcxproj.filters
@@ -234,5 +234,8 @@
Source Files
+
+ Source Files
+
\ No newline at end of file