summaryrefslogtreecommitdiff
path: root/legacy/loader/syscall.h
diff options
context:
space:
mode:
authorboris <wzn@moneybot.cc>2018-11-28 16:00:02 +1300
committerboris <wzn@moneybot.cc>2018-11-28 16:00:02 +1300
commit3d412a4b30a9f7c7f51ea6562e694315948bd3da (patch)
tree26d67dfd1f3e5fd12903ad13e85d0cb8bcf8f21c /legacy/loader/syscall.h
parente4729e4393d90271a3814c7a79950a660c48325a (diff)
cleaned up
in short, the cheat and loader are now separate solutions. unused stuff was moved into the legacy solution in case anyone wants to compile it or whatever. i can change this back if you want to. also, i configured the loader to compile in x64, and have separate build types for linux and win64
Diffstat (limited to 'legacy/loader/syscall.h')
-rw-r--r--legacy/loader/syscall.h167
1 files changed, 167 insertions, 0 deletions
diff --git a/legacy/loader/syscall.h b/legacy/loader/syscall.h
new file mode 100644
index 0000000..0f608ba
--- /dev/null
+++ b/legacy/loader/syscall.h
@@ -0,0 +1,167 @@
+#pragma once
+#include <unordered_map>
+
+#include "x86.h"
+
+using ulong_t = unsigned long;
+
+constexpr bool is86 = sizeof( uintptr_t ) == sizeof( uint32_t );
+
+class c_syscalls {
+protected:
+ std::unordered_map< std::string, std::pair< uint16_t, uint16_t > > m_syscalls;
+
+ // 16 is very arbitrary... but whatever
+ // if something crashes this is why
+ __forceinline size_t syscall_wrapper_size( uint8_t* funptr, uint16_t *ret_c_out ) {
+ for ( size_t offset{ }; offset < 0x30; offset++ ) {
+ if ( funptr[ offset ] == x86::instruction::retn ) {
+ if ( ret_c_out )
+ *ret_c_out = 0;
+
+ return offset + 1;
+ }
+ else if ( funptr[ offset ] == x86::instruction::retn_imm16 ) {
+ if ( ret_c_out )
+ *ret_c_out = *( uint16_t * )( &funptr[ offset + 1 ] );
+
+ return offset + 3;
+ }
+ }
+ return 0;
+ }
+
+ __forceinline bool is_syscall( uint8_t* funptr, size_t func_size ) {
+ const uint32_t encoded_opcode = x86::encode_mov_imm32( x86::reg::eax );
+
+ if ( /*is86*/ true ? funptr[ 0 ] != encoded_opcode : !( funptr[ 0 ] == 0x4c && funptr[ 1 ] == 0x8b && funptr[ 2 ] == 0xd1 ) )
+ return false;
+
+ for ( size_t offset{ }; offset < func_size; offset++ ) {
+ if ( true /*is86*/ ) {
+ if ( ( funptr[ offset ] == x86::instruction::fs && // win7
+ funptr[ offset + 1 ] == x86::instruction::call ) ||
+
+ ( funptr[ offset ] == x86::instruction::call && // win10
+ funptr[ offset + 1 ] == 0xd2 /*call edx*/ ) )
+
+ return true;
+
+ }
+
+ else {
+ if ( funptr[ offset ] == 0x0f && // win7 + win10
+ funptr[ offset + 1 ] == 0x05 )
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ __forceinline uint16_t get_syscall_index( uintptr_t func_addr, std::ptrdiff_t *stub_offset = nullptr, uint16_t *ret_c_out = nullptr ) {
+ uint8_t* ubp_addr = reinterpret_cast< uint8_t* >( func_addr );
+ uint16_t ret_c{ };
+ size_t wrapper_size = syscall_wrapper_size( ubp_addr, &ret_c );
+
+ if ( ret_c_out )
+ *ret_c_out = ret_c;
+
+ wrapper_size = ( wrapper_size ) ? wrapper_size : 16;
+
+ if ( is_syscall( ubp_addr, wrapper_size ) ) {
+ // mov eax, imm32
+ const uint32_t encoded_opcode = x86::encode_mov_imm32( x86::reg::eax );
+
+ for ( size_t offset{ }; offset < wrapper_size; offset++ ) {
+ if ( *reinterpret_cast< uint8_t* >( func_addr + offset ) == encoded_opcode ) {
+ if ( stub_offset )
+ *stub_offset = offset;
+
+ return ( *reinterpret_cast< uint16_t* >( func_addr + offset + 1 ) );
+ }
+ }
+ }
+
+ return 0;
+ }
+
+ std::pair< uint8_t*, size_t > m_shellcode_stub;
+ void *m_call_table;
+public:
+
+ __forceinline ~c_syscalls( ) {
+ if ( m_call_table )
+ delete[ ] m_call_table;
+
+ if ( m_shellcode_stub.first )
+ delete[ ] m_shellcode_stub.first;
+ }
+
+ __forceinline c_syscalls( ) :
+ m_syscalls{ }, m_shellcode_stub{ } {
+
+ init( );
+
+ // b1gr0fl
+ m_call_table = new char[ 0x100000 ];
+ util::set( m_call_table, 0, 0x100000 );
+
+ if ( true /*x86*/ ) {
+ for ( auto& syscall : m_syscalls ) {
+ void *stub_addr = ( void* )( uintptr_t( m_call_table ) + ( syscall.second.first * m_shellcode_stub.second ) );
+ util::copy( stub_addr, m_shellcode_stub.first, m_shellcode_stub.second );
+
+ std::ptrdiff_t index_offset{ };
+ get_syscall_index( ( uintptr_t )stub_addr, &index_offset );
+
+ auto stub_return = ( uint16_t * )( uintptr_t( stub_addr ) + m_shellcode_stub.second - 2 );
+ *stub_return = syscall.second.second;
+
+ *( uint32_t * )( uintptr_t( stub_addr ) + index_offset + 1 ) = ( syscall.second.first );
+
+ }
+ }
+ }
+
+ __forceinline void init( ) {
+ uint32_t index;
+ uint16_t ret_c{ };
+
+ if ( g_nt.m_exports.empty( ) ) {
+ g_nt.dump_exports( );
+ }
+
+ for ( const auto& exp : g_nt.m_exports ) {
+ index = get_syscall_index( exp.second, nullptr, &ret_c );
+
+ if ( index ) {
+ m_syscalls[ exp.first ].first = index;
+ m_syscalls[ exp.first ].second = ret_c;
+
+ if ( !m_shellcode_stub.first ) {
+ m_shellcode_stub.second = syscall_wrapper_size( reinterpret_cast< uint8_t* >( exp.second ), &ret_c );
+
+ m_shellcode_stub.first = new uint8_t[ m_shellcode_stub.second ];
+
+ m_syscalls[ exp.first ].second = ret_c;
+
+ util::copy( m_shellcode_stub.first, reinterpret_cast< void* >( exp.second ), m_shellcode_stub.second );
+ }
+ }
+ }
+ }
+
+ template< typename t = void* >
+ __forceinline t get_syscall_func( std::string name ) {
+ return ( t )( GetProcAddress( GetModuleHandleA( "ntdll.dll" ), name.c_str( ) ) );
+ }
+
+ __forceinline uint16_t get_syscall( std::string name ) {
+ return m_syscalls[ name ].first;
+ }
+
+ __forceinline auto& get_syscalls( ) {
+ return m_syscalls;
+ }
+}; \ No newline at end of file