summaryrefslogtreecommitdiff
path: root/loader/syscall.h
blob: 0f608baa767dd793723a0d3481010bed99825c82 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
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;
	}
};