turborex 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +674 -0
  3. data/README.md +38 -0
  4. data/README.rdoc +19 -0
  5. data/examples/alpc_client.rb +15 -0
  6. data/examples/alpc_server.rb +14 -0
  7. data/examples/com_client.rb +19 -0
  8. data/examples/com_finder.rb +39 -0
  9. data/examples/create_instance.rb +15 -0
  10. data/examples/cstruct.rb +19 -0
  11. data/examples/find_com_client_calls.rb +16 -0
  12. data/examples/find_rpc_security_callback.rb +12 -0
  13. data/examples/rpc_finder.rb +117 -0
  14. data/examples/scan_exports.rb +5 -0
  15. data/examples/scan_imports.rb +5 -0
  16. data/examples/tinysdk.rb +17 -0
  17. data/lib/turborex.rb +21 -0
  18. data/lib/turborex/cstruct.rb +565 -0
  19. data/lib/turborex/cstruct/struct_helper.rb +7 -0
  20. data/lib/turborex/exception.rb +65 -0
  21. data/lib/turborex/fuzzer.rb +204 -0
  22. data/lib/turborex/fuzzer/containers.rb +115 -0
  23. data/lib/turborex/fuzzer/coverage.rb +67 -0
  24. data/lib/turborex/fuzzer/mutators.rb +25 -0
  25. data/lib/turborex/fuzzer/seed.rb +30 -0
  26. data/lib/turborex/monkey.rb +11 -0
  27. data/lib/turborex/msrpc.rb +14 -0
  28. data/lib/turborex/msrpc/decompiler.rb +244 -0
  29. data/lib/turborex/msrpc/midl.rb +747 -0
  30. data/lib/turborex/msrpc/ndrtype.rb +167 -0
  31. data/lib/turborex/msrpc/rpcbase.rb +777 -0
  32. data/lib/turborex/msrpc/rpcfinder.rb +1426 -0
  33. data/lib/turborex/msrpc/utils.rb +70 -0
  34. data/lib/turborex/pefile.rb +8 -0
  35. data/lib/turborex/pefile/pe.rb +61 -0
  36. data/lib/turborex/pefile/scanner.rb +82 -0
  37. data/lib/turborex/utils.rb +321 -0
  38. data/lib/turborex/windows.rb +402 -0
  39. data/lib/turborex/windows/alpc.rb +844 -0
  40. data/lib/turborex/windows/com.rb +266 -0
  41. data/lib/turborex/windows/com/client.rb +84 -0
  42. data/lib/turborex/windows/com/com_finder.rb +330 -0
  43. data/lib/turborex/windows/com/com_registry.rb +100 -0
  44. data/lib/turborex/windows/com/interface.rb +522 -0
  45. data/lib/turborex/windows/com/utils.rb +210 -0
  46. data/lib/turborex/windows/constants.rb +82 -0
  47. data/lib/turborex/windows/process.rb +56 -0
  48. data/lib/turborex/windows/security.rb +12 -0
  49. data/lib/turborex/windows/security/ace.rb +76 -0
  50. data/lib/turborex/windows/security/acl.rb +25 -0
  51. data/lib/turborex/windows/security/security_descriptor.rb +118 -0
  52. data/lib/turborex/windows/tinysdk.rb +89 -0
  53. data/lib/turborex/windows/utils.rb +138 -0
  54. data/resources/headers/alpc/ntdef.h +72 -0
  55. data/resources/headers/alpc/ntlpcapi.h +1014 -0
  56. data/resources/headers/rpc/common.h +162 -0
  57. data/resources/headers/rpc/guiddef.h +191 -0
  58. data/resources/headers/rpc/internal_ndrtypes.h +262 -0
  59. data/resources/headers/rpc/rpc.h +10 -0
  60. data/resources/headers/rpc/rpcdce.h +266 -0
  61. data/resources/headers/rpc/rpcdcep.h +187 -0
  62. data/resources/headers/rpc/rpcndr.h +39 -0
  63. data/resources/headers/rpc/v4_x64/rpcinternals.h +154 -0
  64. data/resources/headers/rpc/wintype.h +517 -0
  65. data/resources/headers/tinysdk/tinysdk.h +5 -0
  66. data/resources/headers/tinysdk/tinysdk/comdef.h +645 -0
  67. data/resources/headers/tinysdk/tinysdk/dbghelp.h +118 -0
  68. data/resources/headers/tinysdk/tinysdk/guiddef.h +194 -0
  69. data/resources/headers/tinysdk/tinysdk/memoryapi.h +12 -0
  70. data/resources/headers/tinysdk/tinysdk/poppack.h +12 -0
  71. data/resources/headers/tinysdk/tinysdk/pshpack4.h +13 -0
  72. data/resources/headers/tinysdk/tinysdk/winnt.h +1059 -0
  73. data/resources/headers/tinysdk/tinysdk/wintype.h +326 -0
  74. metadata +290 -0
@@ -0,0 +1,402 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'metasm'
4
+ require 'turborex/windows/constants.rb'
5
+ require 'turborex/windows/tinysdk'
6
+ require 'turborex/windows/process'
7
+ require 'win32/api' if ::OS.windows?
8
+ require 'turborex/windows/utils'
9
+ require 'turborex/windows/alpc'
10
+ # require 'turborex/windows/com'
11
+
12
+ module TurboRex
13
+ class Windows < Metasm::WinOS
14
+ class Win32API < Metasm::WinAPI
15
+ cp.lexer.warn_redefinition = false
16
+ cp.lexer.include_search_path += TurboRex::Utils.get_all_subdir(TurboRex.root + '/resources/headers/')
17
+ #dbghelp_path = ENV.fetch('DBGHELP_PATH') { File.join(TurboRex.root, '/resources/bin/x86/dbghelp.dll') }
18
+
19
+ if TurboRex::Windows::Utils.process_arch_x64?
20
+ cp.llp64
21
+ cp.lexer.define('_WIN64')
22
+ #dbghelp_path = ENV.fetch('DBGHELP64_PATH') { File.join(TurboRex.root, '/resources/bin/x64/dbghelp.dll') }
23
+ end
24
+
25
+ parse_c(File.read(TurboRex.root + '/resources/headers/tinysdk/tinysdk.h'))
26
+
27
+ new_api_c <<-EOS, 'Psapi.dll'
28
+ BOOL EnumProcesses(
29
+ DWORD *lpidProcess,
30
+ DWORD cb,
31
+ LPDWORD lpcbNeeded
32
+ );
33
+ EOS
34
+
35
+ new_api_c <<-EOS, 'Kernel32.dll'
36
+ HLOCAL
37
+ WINAPI
38
+ LocalFree(
39
+ HLOCAL hMem
40
+ );
41
+
42
+ LPVOID GlobalLock(
43
+ HGLOBAL hMem
44
+ );
45
+
46
+ BOOL GlobalUnlock(
47
+ HGLOBAL hMem
48
+ );
49
+
50
+ DWORD GetLastError();
51
+
52
+ BOOL CloseHandle(
53
+ HANDLE hObject
54
+ );
55
+
56
+ HANDLE CreateFileMappingA(
57
+ HANDLE hFile,
58
+ LPVOID lpFileMappingAttributes,
59
+ DWORD flProtect,
60
+ DWORD dwMaximumSizeHigh,
61
+ DWORD dwMaximumSizeLow,
62
+ LPCSTR lpName
63
+ );
64
+
65
+ HANDLE OpenFileMappingA(
66
+ DWORD dwDesiredAccess,
67
+ BOOL bInheritHandle,
68
+ LPCSTR lpName
69
+ );
70
+
71
+ LPVOID MapViewOfFile(
72
+ HANDLE hFileMappingObject,
73
+ DWORD dwDesiredAccess,
74
+ DWORD dwFileOffsetHigh,
75
+ DWORD dwFileOffsetLow,
76
+ SIZE_T dwNumberOfBytesToMap
77
+ );
78
+
79
+ BOOL UnmapViewOfFile(
80
+ LPCVOID lpBaseAddress
81
+ );
82
+ EOS
83
+
84
+ new_api_c <<-EOS, 'ole32.dll'
85
+ HRESULT CoInitialize(
86
+ LPVOID pvReserved
87
+ );
88
+
89
+ HRESULT CoInitializeEx(
90
+ LPVOID pvReserved,
91
+ DWORD dwCoInit
92
+ );
93
+
94
+ HRESULT CoCreateInstance(
95
+ REFCLSID rclsid,
96
+ LPUNKNOWN pUnkOuter,
97
+ DWORD dwClsContext,
98
+ REFIID riid,
99
+ LPVOID *ppv
100
+ );
101
+
102
+ HRESULT CoGetClassObject(
103
+ REFCLSID rclsid,
104
+ DWORD dwClsContext,
105
+ LPVOID pvReserved,
106
+ REFIID riid,
107
+ LPVOID *ppv
108
+ );
109
+
110
+ HRESULT CoGetPSClsid(
111
+ REFIID riid,
112
+ CLSID *pClsid
113
+ );
114
+
115
+ HRESULT CoMarshalInterface(
116
+ LPSTREAM pStm,
117
+ REFIID riid,
118
+ LPUNKNOWN pUnk,
119
+ DWORD dwDestContext,
120
+ LPVOID pvDestContext,
121
+ DWORD mshlflags
122
+ );
123
+
124
+ HRESULT CoUnmarshalInterface(
125
+ LPSTREAM pStm,
126
+ REFIID riid,
127
+ LPVOID *ppv
128
+ );
129
+
130
+ HRESULT CreateStreamOnHGlobal(
131
+ HGLOBAL hGlobal,
132
+ BOOL fDeleteOnRelease,
133
+ LPSTREAM *ppstm
134
+ );
135
+
136
+ HRESULT GetHGlobalFromStream(
137
+ LPSTREAM pstm,
138
+ HGLOBAL *phglobal
139
+ );
140
+
141
+ HRESULT CoGetMarshalSizeMax(
142
+ ULONG *pulSize,
143
+ REFIID riid,
144
+ LPUNKNOWN pUnk,
145
+ DWORD dwDestContext,
146
+ LPVOID pvDestContext,
147
+ DWORD mshlflags
148
+ );
149
+
150
+ HRESULT CLSIDFromString(
151
+ LPCOLESTR lpsz,
152
+ LPCLSID pclsid
153
+ );
154
+
155
+ HRESULT StgCreateDocfile(
156
+ const WCHAR *pwcsName,
157
+ DWORD grfMode,
158
+ DWORD reserved,
159
+ IStorage **ppstgOpen
160
+ );
161
+ EOS
162
+
163
+ new_api_c <<-EOS, 'OleAut32.dll'
164
+ BSTR SysAllocString(
165
+ const OLECHAR *psz
166
+ );
167
+
168
+ void SysFreeString(
169
+ BSTR bstrString
170
+ );
171
+ EOS
172
+
173
+ new_api_c <<-EOS, 'dbghelp.dll'
174
+ #define IMAGEAPI __stdcall
175
+ #define SYMOPT_CASE_INSENSITIVE 0x00000001
176
+ #define SYMOPT_UNDNAME 0x00000002
177
+ #define SYMOPT_DEFERRED_LOADS 0x00000004
178
+ #define SYMOPT_NO_CPP 0x00000008
179
+ #define SYMOPT_LOAD_LINES 0x00000010
180
+ #define SYMOPT_OMAP_FIND_NEAREST 0x00000020
181
+ #define SYMOPT_LOAD_ANYTHING 0x00000040
182
+ #define SYMOPT_IGNORE_CVREC 0x00000080
183
+ #define SYMOPT_NO_UNQUALIFIED_LOADS 0x00000100
184
+ #define SYMOPT_FAIL_CRITICAL_ERRORS 0x00000200
185
+ #define SYMOPT_EXACT_SYMBOLS 0x00000400
186
+ #define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS 0x00000800
187
+ #define SYMOPT_IGNORE_NT_SYMPATH 0x00001000
188
+ #define SYMOPT_INCLUDE_32BIT_MODULES 0x00002000
189
+ #define SYMOPT_PUBLICS_ONLY 0x00004000
190
+ #define SYMOPT_NO_PUBLICS 0x00008000
191
+ #define SYMOPT_AUTO_PUBLICS 0x00010000
192
+ #define SYMOPT_NO_IMAGE_SEARCH 0x00020000
193
+ #define SYMOPT_SECURE 0x00040000
194
+ #define SYMOPT_NO_PROMPTS 0x00080000
195
+ #define SYMOPT_DEBUG 0x80000000
196
+
197
+ typedef int BOOL;
198
+ typedef char CHAR;
199
+ typedef unsigned long DWORD;
200
+ typedef unsigned __int64 DWORD64;
201
+ typedef void *HANDLE;
202
+ typedef unsigned __int64 *PDWORD64;
203
+ typedef void *PVOID;
204
+ typedef unsigned long ULONG;
205
+ typedef unsigned __int64 ULONG64;
206
+ typedef const CHAR *PCSTR;
207
+ typedef CHAR *PSTR;
208
+ typedef struct _SYMBOL_INFO *PSYMBOL_INFO;
209
+ typedef __stdcall BOOL (*PSYM_ENUMERATESYMBOLS_CALLBACK)(PSYMBOL_INFO pSymInfo, ULONG SymbolSize, PVOID UserContext);
210
+ typedef enum
211
+ {
212
+ SymNone = 0,
213
+ SymCoff,
214
+ SymCv,
215
+ SymPdb,
216
+ SymExport,
217
+ SymDeferred,
218
+ SymSym,
219
+ SymDia,
220
+ SymVirtual,
221
+ NumSymTypes
222
+ } SYM_TYPE;
223
+
224
+ typedef struct _SYMBOL_INFO {
225
+ ULONG SizeOfStruct;
226
+ ULONG TypeIndex;
227
+ ULONG64 Reserved[2];
228
+ ULONG info;
229
+ ULONG Size;
230
+ ULONG64 ModBase;
231
+ ULONG Flags;
232
+ ULONG64 Value;
233
+ ULONG64 Address;
234
+ ULONG Register;
235
+ ULONG Scope;
236
+ ULONG Tag;
237
+ ULONG NameLen;
238
+ ULONG MaxNameLen;
239
+ CHAR Name[1];
240
+ } SYMBOL_INFO, *PSYMBOL_INFO;
241
+
242
+ typedef struct _MODLOAD_DATA {
243
+ DWORD ssize;
244
+ DWORD ssig;
245
+ PVOID data;
246
+ DWORD size;
247
+ DWORD flags;
248
+ } MODLOAD_DATA, *PMODLOAD_DATA;
249
+
250
+
251
+ __stdcall DWORD SymGetOptions(void);
252
+ __stdcall DWORD SymSetOptions(DWORD SymOptions __attribute__((in)));
253
+ __stdcall BOOL SymInitialize(HANDLE hProcess __attribute__((in)), PSTR UserSearchPath __attribute__((in)), BOOL fInvadeProcess __attribute__((in)));
254
+ __stdcall DWORD64 SymLoadModule64(HANDLE hProcess __attribute__((in)), HANDLE hFile __attribute__((in)), PSTR ImageName __attribute__((in)), PSTR ModuleName __attribute__((in)), DWORD64 BaseOfDll __attribute__((in)), DWORD SizeOfDll __attribute__((in)));
255
+ __stdcall BOOL SymSetSearchPath(HANDLE hProcess __attribute__((in)), PSTR SearchPathA __attribute__((in)));
256
+ __stdcall BOOL SymFromAddr(HANDLE hProcess __attribute__((in)), DWORD64 Address __attribute__((in)), PDWORD64 Displacement __attribute__((out)), PSYMBOL_INFO Symbol __attribute__((in)) __attribute__((out)));
257
+ __stdcall BOOL SymEnumSymbols(HANDLE hProcess __attribute__((in)), ULONG64 BaseOfDll __attribute__((in)), PCSTR Mask __attribute__((in)), PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback __attribute__((in)), PVOID UserContext __attribute__((in)));
258
+
259
+ DWORD64 IMAGEAPI SymLoadModuleEx(
260
+ HANDLE hProcess,
261
+ HANDLE hFile,
262
+ PCSTR ImageName,
263
+ PCSTR ModuleName,
264
+ DWORD64 BaseOfDll,
265
+ DWORD DllSize,
266
+ PMODLOAD_DATA Data,
267
+ DWORD Flags
268
+ );
269
+
270
+ BOOL IMAGEAPI SymFromName(
271
+ HANDLE hProcess,
272
+ PCSTR Name,
273
+ PSYMBOL_INFO Symbol
274
+ );
275
+
276
+ BOOL
277
+ IMAGEAPI
278
+ SymGetModuleInfo64(
279
+ HANDLE hProcess,
280
+ DWORD64 qwAddr,
281
+ PIMAGEHLP_MODULE64 ModuleInfo
282
+ );
283
+
284
+ BOOL
285
+ IMAGEAPI
286
+ SymGetModuleInfoW64(
287
+ HANDLE hProcess,
288
+ DWORD64 qwAddr,
289
+ PIMAGEHLP_MODULEW64 ModuleInfo
290
+ );
291
+
292
+ #if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64)
293
+ #define SymGetModuleInfo SymGetModuleInfo64
294
+ #define SymGetModuleInfoW SymGetModuleInfoW64
295
+ #else
296
+ BOOL
297
+ IMAGEAPI
298
+ SymGetModuleInfo(
299
+ HANDLE hProcess,
300
+ DWORD dwAddr,
301
+ PIMAGEHLP_MODULE ModuleInfo
302
+ );
303
+
304
+ BOOL
305
+ IMAGEAPI
306
+ SymGetModuleInfoW(
307
+ HANDLE hProcess,
308
+ DWORD dwAddr,
309
+ PIMAGEHLP_MODULEW ModuleInfo
310
+ );
311
+ #endif
312
+ EOS
313
+
314
+ new_api_c <<-EOS, 'Advapi32.dll'
315
+ DWORD GetSecurityDescriptorLength(
316
+ PSECURITY_DESCRIPTOR pSecurityDescriptor
317
+ );
318
+
319
+ BOOL GetSecurityDescriptorDacl(
320
+ PSECURITY_DESCRIPTOR pSecurityDescriptor,
321
+ LPBOOL lpbDaclPresent,
322
+ PACL *pDacl,
323
+ LPBOOL lpbDaclDefaulted
324
+ );
325
+
326
+ BOOL GetSecurityDescriptorControl(
327
+ PSECURITY_DESCRIPTOR pSecurityDescriptor,
328
+ PSECURITY_DESCRIPTOR_CONTROL pControl,
329
+ LPDWORD lpdwRevision
330
+ );
331
+
332
+ BOOL GetSecurityDescriptorOwner(
333
+ PSECURITY_DESCRIPTOR pSecurityDescriptor,
334
+ PSID *pOwner,
335
+ LPBOOL lpbOwnerDefaulted
336
+ );
337
+
338
+ BOOL GetSecurityDescriptorGroup(
339
+ PSECURITY_DESCRIPTOR pSecurityDescriptor,
340
+ PSID *pGroup,
341
+ LPBOOL lpbGroupDefaulted
342
+ );
343
+
344
+ BOOL ConvertSidToStringSidA(
345
+ PSID Sid,
346
+ LPSTR *StringSid
347
+ );
348
+
349
+ BOOL ConvertStringSidToSidW(
350
+ LPCWSTR StringSid,
351
+ PSID *Sid
352
+ );
353
+
354
+ BOOL GetAclInformation(
355
+ PACL pAcl,
356
+ LPVOID pAclInformation,
357
+ DWORD nAclInformationLength,
358
+ ACL_INFORMATION_CLASS dwAclInformationClass
359
+ );
360
+
361
+ BOOL GetAce(
362
+ PACL pAcl,
363
+ DWORD dwAceIndex,
364
+ LPVOID *pAce
365
+ );
366
+ EOS
367
+ end
368
+
369
+ class Thread < Metasm::WinOS
370
+ end
371
+
372
+ class Token
373
+ end
374
+
375
+ def self.open_process(pid, mask = Metasm::WinAPI::PROCESS_QUERY_INFORMATION)
376
+ if handle = Metasm::WinAPI.openprocess(mask, 0, pid)
377
+ return open_process_handle(handle)
378
+ end
379
+
380
+ nil
381
+ end
382
+
383
+ def self.open_process_handle(handle)
384
+ pid = begin
385
+ WinAPI.getprocessid(handle)
386
+ rescue StandardError
387
+ 0
388
+ end
389
+ TurboRex::Windows::Process.new(pid, handle)
390
+ end
391
+
392
+ def self.list_all_process_pid
393
+ lpidProcess = Win32API.alloc_c_ary('DWORD', 1024)
394
+ cb = 1024
395
+ lpcbNeeded = 0
396
+
397
+ Win32API.enumprocesses(lpidProcess, cb, lpcbNeeded)
398
+
399
+ lpidProcess
400
+ end
401
+ end
402
+ end
@@ -0,0 +1,844 @@
1
+ warn "\033[33m[-]Warning: This module doesn't currently work on non-Windows os.\033[0m" unless OS.windows?
2
+
3
+ module TurboRex
4
+ class Windows < Metasm::WinOS
5
+ module ALPC
6
+ include ::TurboRex::Windows::Constants
7
+
8
+ PORMSG_PAD = 0x100
9
+
10
+ ALPC_MSGFLG_REPLY_MESSAGE = 0x1
11
+ ALPC_MSGFLG_LPC_MODE = 0x2
12
+ ALPC_MSGFLG_RELEASE_MESSAGE = 0x10000
13
+ ALPC_MSGFLG_SYNC_REQUEST = 0x20000
14
+ ALPC_MSGFLG_WAIT_USER_MODE = 0x100000
15
+ ALPC_MSGFLG_WAIT_ALERTABLE = 0x200000
16
+ ALPC_MSGFLG_WOW64_CALL = 0x80000000
17
+
18
+ ALPC_MESSAGE_SECURITY_ATTRIBUTE = 0x80000000
19
+ ALPC_MESSAGE_VIEW_ATTRIBUTE = 0x40000000
20
+ ALPC_MESSAGE_CONTEXT_ATTRIBUTE = 0x20000000
21
+ ALPC_MESSAGE_HANDLE_ATTRIBUTE = 0x10000000
22
+ ALPC_MESSAGE_TOKEN_ATTRIBUTE = 0x8000000
23
+ ALPC_MESSAGE_DIRECT_ATTRIBUTE = 0x4000000
24
+ ALPC_MESSAGE_WORK_ON_BEHALF_ATTRIBUTE = 0x2000000
25
+
26
+ ALPC_PORFLG_ALLOW_LPC_REQUESTS = 0x20000
27
+
28
+ def self.const_missing(name)
29
+ super(name) unless APIProxy.initialized?
30
+ const = APIProxy.cp.numeric_constants.assoc(name.to_s)
31
+ super(name) if const.nil?
32
+
33
+ const[1]
34
+ end
35
+
36
+ class APIProxy < Metasm::WinAPI
37
+ def self.init(cpu = Metasm::Ia32)
38
+ if @initialized
39
+ return true
40
+ end
41
+
42
+ opts = {}
43
+ opts[:cpu] = cpu
44
+ opts[:include_path] = [TurboRex.root + "/resources/headers/alpc"]
45
+ opts[:visual_studio] = true
46
+ opts[:data_model] = 'llp64' if cpu == Metasm::X86_64
47
+ opts[:predefined] = true
48
+
49
+ @np = TurboRex::CStruct::NativeParser.new(nil, opts)
50
+ @cp = @np.parser
51
+ @cp.parse("#define NT_VERSION #{TurboRex::Windows.version.join}")
52
+ @cp.parse_file TurboRex.root + '/resources/headers/alpc/ntlpcapi.h'
53
+ new_api_c('ntdll.dll')
54
+
55
+ @initialized = true
56
+ end
57
+
58
+ def self.reload(cpu = Metasm::Ia32)
59
+ @initialized = false
60
+ init(cpu)
61
+ end
62
+
63
+ def self.initialized?
64
+ @initialized
65
+ end
66
+
67
+ def self.new_api_c(fromlib = nil)
68
+ cp.toplevel.symbol.dup.each_value { |v|
69
+ next if not v.kind_of? Metasm::C::Variable # enums
70
+ cp.toplevel.symbol.delete v.name
71
+ lib = fromlib || lib_from_sym(v.name)
72
+ addr = sym_addr(lib, v.name)
73
+ if addr == 0 or addr == -1 or addr == 0xffff_ffff or addr == 0xffffffff_ffffffff
74
+ api_not_found(lib, v)
75
+ next
76
+ end
77
+
78
+ rbname = c_func_name_to_rb(v.name)
79
+ if not v.type.kind_of? Metasm::C::Function
80
+ class << self;
81
+ self;
82
+ end.send(:define_method, rbname) { addr }
83
+ next
84
+ end
85
+
86
+ next if v.initializer
87
+
88
+
89
+ new_caller_for(v, rbname, addr)
90
+ }
91
+
92
+
93
+ cexist = constants.inject({}) { |h, c| h.update c.to_s => true }
94
+ cp.toplevel.symbol.each { |k, v|
95
+ if v.kind_of? ::Integer
96
+ n = c_const_name_to_rb(k)
97
+ const_set(n, v) if v.kind_of? Integer and not cexist[n]
98
+ end
99
+ }
100
+
101
+ cp.lexer.definition.each_key { |k|
102
+ n = c_const_name_to_rb(k)
103
+ if not cexist[n] and Object.const_defined?(n) and v = @cp.macro_numeric(n)
104
+ const_set(n, v)
105
+ end
106
+ }
107
+ end
108
+
109
+ def self.np
110
+ @np
111
+ end
112
+
113
+ def self.alloc_c_type(typename, init_value = 0)
114
+ alloc_c_ary(typename, [init_value])
115
+ end
116
+ end
117
+
118
+ class Transport
119
+ def initialize(opts = {})
120
+ @conn_handle = nil
121
+ @communication_handle = []
122
+ end
123
+
124
+ def listen(conn_handle, opts = {}, &block)
125
+ @conn_handle = conn_handle
126
+ #port_message = APIProxy.alloc_c_struct('PORT_MESSAGE')
127
+ port_message = APIProxy.alloc_c_ary('BYTE', 0x1000)
128
+ message_attr = MessageAttribute.new.struct
129
+ buf_len = APIProxy.alloc_c_type('SIZE_T')
130
+ buf_len[0] = port_message.sizeof
131
+ retry_count = 0
132
+
133
+ while true
134
+ begin
135
+ # call NtAlpcSendWaitReceivePort will cause interpreter blocks, until you kill it.
136
+ ntstatus = APIProxy.ntalpcsendwaitreceiveport(@conn_handle,
137
+ opts[:flag] || 0,
138
+ 0,
139
+ 0,
140
+ port_message,
141
+ buf_len,
142
+ message_attr,
143
+ 0)
144
+ yield(port_message, buf_len, message_attr, TinySDK.format_hex_ntstatus(ntstatus, hex_str: true)) if block_given?
145
+ unless TinySDK.nt_success? ntstatus
146
+ unless buf_len[0] == port_message.sizeof
147
+ port_message = APIProxy.alloc_c_ary('BYTE', buf_len[0])
148
+ raise TurboRex::Exception::ALPC::BufferTooSmall
149
+ else
150
+ raise
151
+ end
152
+ end
153
+ rescue => e
154
+ if e.is_a? TurboRex::Exception::ALPC::BufferTooSmall
155
+ raise TurboRex::Exception::ALPC::TooManyRetries if retry_count >= 2
156
+ retry_count += 1
157
+ retry
158
+ else
159
+ raise TurboRex::Exception::UnknownError
160
+ end
161
+ end
162
+
163
+ kport_message = PortMessage.new(raw_message: port_message)
164
+ break if (kport_message.type & 0xFFF) == TurboRex::Windows::ALPC::LPC_CONNECTION_REQUEST
165
+ end
166
+
167
+ return kport_message
168
+ end
169
+
170
+ def send(handle, port_message, message_attr, opts = {})
171
+ flag = opts[:flag] || 0
172
+ timeout = opts[:timeout] || 0
173
+ #buf_len = opts.fetch(:buf_len) { APIProxy.alloc_c_type('SIZE_T') }
174
+ #buf_len = port_message.sizeof
175
+
176
+ ntstatus = APIProxy.ntalpcsendwaitreceiveport(handle, flag, port_message, message_attr, 0, 0, 0, timeout)
177
+ unless TinySDK.nt_success?(ntstatus)
178
+ raise TurboRex::Exception::NotNTSuccess.new TinySDK.format_hex_ntstatus(ntstatus, hex_str: true)
179
+ end
180
+
181
+ TinySDK.format_hex_ntstatus ntstatus
182
+ end
183
+
184
+
185
+ def recv(handle, opts = {})
186
+ port_message = opts.fetch(:port_message) { APIProxy.alloc_c_ary('BYTE', 0x1000) }
187
+ buf_len = opts.fetch(:buf_len) { APIProxy.alloc_c_type('SIZE_T') }
188
+ buf_len[0] = port_message.sizeof
189
+ #message_attr = opts.fetch(:message_attr) { APIProxy.alloc_c_struct('ALPC_MESSAGE_ATTRIBUTES') }
190
+ message_attr = MessageAttribute.new.struct
191
+ flag = opts[:flag] || 0
192
+ retry_count = opts[:retry_count] || 0
193
+ timeout = opts[:timeout] || 0
194
+
195
+ begin
196
+ ntstatus = APIProxy.ntalpcsendwaitreceiveport(handle, flag, 0, 0, port_message, buf_len, message_attr, timeout)
197
+ unless TinySDK.nt_success? ntstatus
198
+ unless buf_len[0] == port_message.sizeof
199
+ port_message = APIProxy.alloc_c_ary('BYTE', buf_len[0])
200
+ raise TurboRex::Exception::ALPC::BufferTooSmall
201
+ else
202
+ raise
203
+ end
204
+ end
205
+ rescue => e
206
+ if e.is_a? TurboRex::Exception::ALPC::BufferTooSmall
207
+ raise TurboRex::Exception::ALPC::TooManyRetries if retry_count >= 2
208
+ retry_count += 1
209
+ retry
210
+ else
211
+ raise TurboRex::Exception::NotNTSuccess.new(TinySDK.format_hex_ntstatus(ntstatus, hex_str: true))
212
+ end
213
+ end
214
+
215
+ PortMessage.new(raw_message: port_message)
216
+ end
217
+
218
+ def send_recv(handle, send_message, send_message_attr, recv_message_attr, opts = {})
219
+ port_message = opts.fetch(:port_message) { APIProxy.alloc_c_ary('BYTE', 0x1000) }
220
+ buf_len = opts.fetch(:buf_len) { APIProxy.alloc_c_type('SIZE_T') }
221
+ buf_len[0] = port_message.sizeof
222
+ message_attr = recv_message_attr
223
+ flag = opts[:flag] || TurboRex::Windows::ALPC::ALPC_MSGFLG_SYNC_REQUEST
224
+ retry_count = opts[:retry_count] || 0
225
+ timeout = opts[:timeout] || 0
226
+
227
+ begin
228
+ ntstatus = APIProxy.ntalpcsendwaitreceiveport(handle,
229
+ flag,
230
+ send_message,
231
+ send_message_attr,
232
+ port_message,
233
+ buf_len,
234
+ recv_message_attr,
235
+ timeout)
236
+ unless TinySDK.nt_success? ntstatus
237
+ unless buf_len[0] == port_message.sizeof
238
+ port_message = APIProxy.alloc_c_ary('BYTE', buf_len[0])
239
+ raise TurboRex::Exception::ALPC::BufferTooSmall
240
+ else
241
+ raise
242
+ end
243
+ end
244
+ rescue => e
245
+ if e.is_a? TurboRex::Exception::ALPC::BufferTooSmall
246
+ raise TurboRex::Exception::ALPC::TooManyRetries if retry_count >= 2
247
+ retry_count += 1
248
+ retry
249
+ else
250
+ raise TurboRex::Exception::NotNTSuccess.new(TinySDK.format_hex_ntstatus(ntstatus, hex_str: true))
251
+ end
252
+ end
253
+
254
+ PortMessage.new(raw_message: port_message)
255
+ end
256
+
257
+ def connect(opts = {}, &block)
258
+ unless wport_name = TurboRex::Windows::Utils.multibyte_to_widechar(opts[:port_name])
259
+ raise "Unable to convert characters to utf-16le encoding."
260
+ end
261
+
262
+ dest_str = APIProxy.alloc_c_ptr('UNICODE_STRING')
263
+ APIProxy.rtlinitunicodestring(dest_str, wport_name)
264
+
265
+ handle = APIProxy.alloc_c_type('HANDLE')
266
+ alpc_port_attr = APIProxy.alloc_c_struct('ALPC_PORT_ATTRIBUTES')
267
+ alpc_port_attr.Flags = TurboRex::Windows::ALPC::ALPC_PORFLG_ALLOW_LPC_REQUESTS
268
+ alpc_port_attr.MaxMessageLength = 0x1000
269
+ alpc_port_attr.MemoryBandwidth = 0
270
+ alpc_port_attr.MaxPoolUsage = 0xFFFFFFFF
271
+ alpc_port_attr.MaxSectionSize = 0xFFFFFFFF
272
+ alpc_port_attr.MaxViewSize = 0xFFFFFFFF
273
+ alpc_port_attr.MaxTotalSectionSize = 0xFFFFFFFF
274
+ alpc_port_attr.DupObjectTypes = 0xFFFFFFFF
275
+
276
+ alpc_port_attr.SecurityQos.Length = alpc_port_attr.SecurityQos.sizeof
277
+ alpc_port_attr.SecurityQos.ImpersonationLevel = opts[:impersonation_level] ||
278
+ TurboRex::Windows::Constants::SecurityIdentification
279
+
280
+ # timeout
281
+ #large_integer = APIProxy.alloc_c_struct('LARGE_INTEGER')
282
+ #large_integer.HighPart
283
+ #large_integer.LowPart
284
+
285
+ kport_message = PortMessage.new(payload: opts[:payload], alloc_size: (opts[:alloc_size]||3800))
286
+ obj_attr = opts[:obj_attr] || 0
287
+ flags = opts[:flags] || TurboRex::Windows::ALPC::ALPC_MSGFLG_SYNC_REQUEST # Don't use the ALPC_MSGFLG_SYNC_REQUEST flag when specific attributes
288
+ timeout = opts[:timeout] || 0
289
+ retry_count = opts[:retry_count] || 0
290
+
291
+ buf_len = nil
292
+ if message_size = kport_message.message_size
293
+ buf_len = APIProxy.alloc_c_type('SIZE_T')
294
+ buf_len[0] = message_size
295
+ end
296
+
297
+ out_msg_attr = 0
298
+ in_msg_attr = 0
299
+
300
+ if opts[:client_obj_attr] # perform to call NtAlpcConnectPortEx
301
+ raise NotImplementedError
302
+ else
303
+ ntstatus = APIProxy.ntalpcconnectport(handle, dest_str, obj_attr, alpc_port_attr, flags, 0, kport_message.message,
304
+ buf_len, out_msg_attr, in_msg_attr, timeout)
305
+ kport_message.refresh_message
306
+ formatted_status = TinySDK.format_hex_ntstatus(ntstatus)
307
+ if formatted_status == 0xC0000041
308
+ puts "[-] The server refused the connection.(STATUS_PORT_CONNECTION_REFUSED)"
309
+ retry_count.times do |i|
310
+ puts "[*] Retrying..."
311
+ ntstatus = APIProxy.ntalpcconnectport(handle, dest_str, obj_attr, alpc_port_attr, flags, 0, kport_message.message,
312
+ buf_len, out_msg_attr, in_msg_attr, timeout)
313
+ break unless TinySDK.format_hex_ntstatus(ntstatus) == 0xC0000041
314
+ end
315
+ elsif !TinySDK.nt_success?(ntstatus)
316
+ raise TurboRex::Exception::NotNTSuccess.new("0x#{formatted_status.to_s(16).upcase}")
317
+ end
318
+ end
319
+
320
+ @communication_handle << handle[0]
321
+ return handle[0], kport_message
322
+ end
323
+
324
+ def accept(opts = {})
325
+ communication_handle = APIProxy.alloc_c_type('HANDLE')
326
+ alpc_port_attr = APIProxy.alloc_c_struct('ALPC_PORT_ATTRIBUTES')
327
+ alpc_port_attr.Flags = 0
328
+ alpc_port_attr.MaxMessageLength = 0x1000
329
+ alpc_port_attr.MemoryBandwidth = 0
330
+ alpc_port_attr.MaxPoolUsage = 0xFFFFFFFF
331
+ alpc_port_attr.MaxSectionSize = 0xFFFFFFFF
332
+ alpc_port_attr.MaxViewSize = 0xFFFFFFFF
333
+ alpc_port_attr.MaxTotalSectionSize = 0xFFFFFFFF
334
+ alpc_port_attr.DupObjectTypes = 0xFFFFFFFF
335
+
336
+ port_context = opts[:port_context] || 0
337
+ flags = opts[:flags] || 0
338
+ uniq_process = opts[:uniq_process]
339
+ uniq_thread = opts[:uniq_thread]
340
+ message_id = opts[:message_id]
341
+ accept = 1
342
+ port_message = opts[:port_message]
343
+
344
+ if port_message.nil?
345
+ raise TurboRex::Exception::ALPC::ReplyMessageMismatch if uniq_process.nil? || uniq_thread.nil? || message_id.nil?
346
+ port_message = PortMessage.new(alloc_size: 1)
347
+ port_message.client_id = [uniq_process, uniq_thread]
348
+ port_message.message_id = message_id
349
+ end
350
+
351
+ accept = 0 if opts[:refuse]
352
+
353
+ ntstatus = APIProxy.ntalpcacceptconnectport(communication_handle,
354
+ @conn_handle,
355
+ flags,
356
+ 0,
357
+ alpc_port_attr,
358
+ port_context,
359
+ port_message.message,
360
+ 0,
361
+ accept)
362
+
363
+ unless opts[:refuse]
364
+ @communication_handle << communication_handle[0]
365
+ [communication_handle[0], TinySDK.format_hex_ntstatus(ntstatus)]
366
+ else
367
+ TinySDK.format_hex_ntstatus(ntstatus)
368
+ end
369
+ end
370
+
371
+ def refuse_connect(opts = {})
372
+ opts[:refuse] = true
373
+ accept(opts)
374
+ end
375
+
376
+ def close
377
+ APIProxy.ntalpcdisconnectport(@conn_handle, 0)
378
+ Metasm::WinAPI.closehandle @conn_handle
379
+ @conn_handle = nil
380
+ @communication_handle = []
381
+ end
382
+ end
383
+
384
+ class PortMessage
385
+ class ClientID
386
+ attr_accessor :unique_thread
387
+ attr_accessor :unique_process
388
+
389
+ def initialize(unique_process, unique_thread)
390
+ @unique_process = unique_process
391
+ @unique_thread = unique_thread
392
+ end
393
+
394
+ def to_struct
395
+ client_id = APIProxy.alloc_c_struct('CLIENT_ID')
396
+ client_id.UniqueProcess = @unique_process
397
+ client_id.UniqueThread = @unique_thread
398
+ client_id
399
+ end
400
+ end
401
+
402
+ attr_reader :message_size
403
+ attr_reader :buf_size
404
+ attr_reader :header_size
405
+ attr_reader :message
406
+ attr_reader :payload
407
+ attr_reader :payload_size
408
+ attr_accessor :total_length
409
+ attr_accessor :data_length
410
+ attr_reader :header
411
+ attr_accessor :attributes
412
+
413
+ # header data member
414
+ attr_reader :length
415
+ attr_reader :type
416
+ attr_reader :data_info_offset
417
+ attr_reader :zero_init
418
+ attr_reader :client_id
419
+ attr_reader :do_not_use_this_field
420
+ attr_reader :message_id
421
+ attr_reader :client_view_size
422
+ attr_reader :callback_id
423
+
424
+ def initialize(opts = {})
425
+ raw_message = opts[:raw_message]
426
+ payload = opts[:payload]
427
+ @payload = payload
428
+ @attributes = MessageAttribute.new.struct
429
+
430
+ if raw_message
431
+ perform_raw_message raw_message
432
+ elsif payload
433
+ port_message = opts[:port_message]
434
+ @header = (port_message ||= APIProxy.alloc_c_struct('PORT_MESSAGE'))
435
+ set_header
436
+ #@message_size = @header_size = port_message.sizeof
437
+ if payload.is_a? String
438
+ pure_set_msg payload, payload.bytesize
439
+ elsif payload.is_a? ::Metasm::C::AllocCStruct
440
+ pure_set_msg payload.str, payload.sizeof
441
+ else
442
+ raise TurboRex::Exception::ALPC::UnknownPayloadType
443
+ end
444
+ elsif opts[:alloc_size]
445
+ @header = APIProxy.alloc_c_struct('PORT_MESSAGE')
446
+ set_header
447
+
448
+ @payload = 0.chr * opts[:alloc_size].to_i
449
+ pure_set_msg @payload, @payload.bytesize
450
+ end
451
+ end
452
+
453
+ def payload=(payload)
454
+ @payload = payload
455
+ if payload.is_a? String
456
+ @payload_size = payload.bytesize
457
+ elsif payload.is_a? ::Metasm::C::AllocCStruct
458
+ @payload_size = payload.sizeof
459
+ end
460
+
461
+ if @payload_size > @buf_size
462
+ pure_set_msg payload, @payload_size
463
+ else
464
+ @message[@header_size, @payload_size] = payload
465
+ set_data_length @payload_size
466
+ end
467
+ end
468
+
469
+ def set_data_length(len)
470
+ @total_length = @header_size + len
471
+ @data_length = len
472
+
473
+ @header.u1.s1.TotalLength = @total_length
474
+ @header.u1.s1.DataLength = @data_length
475
+ end
476
+
477
+ def get_total_and_data_len
478
+ [@header.u1.s1.TotalLength, @header.u1.s1.DataLength]
479
+ end
480
+
481
+ def header=(header)
482
+ @header = header
483
+
484
+ set_header
485
+ set_data_length(@payload_size)
486
+ pure_set_msg @payload, @payload_size
487
+ end
488
+
489
+ def set_header
490
+ @total_length, @data_length = get_total_and_data_len
491
+ @length = @header.u1.Length
492
+ @type = @header.u2.s2.Type
493
+ @data_info_offset = @header.u2.s2.DataInfoOffset
494
+ @zero_init = @header.u2.ZeroInit
495
+ @client_id = @do_not_use_this_field = ClientID.new(@header.ClientId.UniqueProcess, @header.ClientId.UniqueThread)
496
+ @message_id = @header.MessageId
497
+ @client_view_size = @callback_id = @header.ClientViewSize
498
+ @header_size = @header.sizeof
499
+ end
500
+
501
+ def type=(type)
502
+ binding.pry
503
+ @type = @header.u2.s2.Type = type
504
+ @message[0, @header_size] = @header.str
505
+ end
506
+
507
+ def message_id=(id)
508
+ @message_id = @header.MessageId = id
509
+ @message[0, @header_size] = @header.str
510
+ end
511
+
512
+ def client_id=(client_id)
513
+ if client_id.is_a? ClientID
514
+ @client_id = client_id
515
+ elsif client_id.is_a? ::Metasm::C::AllocCStruct
516
+ @client_id = @do_not_use_this_field = ClientID.new(client_id.UniqueProcess, client_id.UniqueThread)
517
+ else
518
+ @client_id = @do_not_use_this_field = ClientID.new(client_id[0], client_id[1])
519
+ end
520
+
521
+ @header.ClientId.UniqueProcess = @client_id.unique_process
522
+ @header.ClientId.UniqueThread = @client_id.unique_thread
523
+
524
+ @message[0, @header_size] = @header.str
525
+ end
526
+
527
+ def callback_id=(callback_id)
528
+ @callback_id = @header.CallbackId = callback_id
529
+ @message[0, @header_size] = @header.str
530
+ end
531
+
532
+ def refresh_message
533
+ return unless @message
534
+ perform_raw_message @message
535
+ end
536
+
537
+ private
538
+
539
+ def perform_raw_message(raw_message)
540
+ raise "Invalid message class." unless raw_message.is_a?(::Metasm::C::AllocCStruct)
541
+ @message = raw_message
542
+ nport_message = APIProxy.np['PORT_MESSAGE']
543
+ @header = nport_message.from_str raw_message[0, nport_message.sizeof]
544
+ set_header
545
+
546
+ @message_size = @message.sizeof
547
+ @payload_size = @data_length
548
+ @payload = @message[@header_size, @payload_size]
549
+ @buf_size = @message.sizeof - @header_size
550
+ end
551
+
552
+ def pure_set_msg(payload, payload_size)
553
+ @message_size = @header_size = @header.sizeof
554
+ @payload_size = payload_size
555
+ @buf_size = @payload_size + PORMSG_PAD
556
+ @message_size += @buf_size
557
+ @message = APIProxy.alloc_c_ary('BYTE', @message_size)
558
+ set_data_length @payload_size
559
+ @message[0, @header_size] = @header.str
560
+ @message[@header_size, @payload_size] = payload
561
+ end
562
+ end
563
+
564
+ class MessageAttribute
565
+ attr_reader :struct
566
+ attr_reader :buf
567
+ attr_reader :attr
568
+
569
+ def initialize(attr = nil)
570
+ @attr = attr ||= (
571
+ TurboRex::Windows::ALPC::ALPC_MESSAGE_SECURITY_ATTRIBUTE |
572
+ TurboRex::Windows::ALPC::ALPC_MESSAGE_VIEW_ATTRIBUTE |
573
+ TurboRex::Windows::ALPC::ALPC_MESSAGE_CONTEXT_ATTRIBUTE |
574
+ TurboRex::Windows::ALPC::ALPC_MESSAGE_HANDLE_ATTRIBUTE |
575
+ TurboRex::Windows::ALPC::ALPC_MESSAGE_TOKEN_ATTRIBUTE |
576
+ TurboRex::Windows::ALPC::ALPC_MESSAGE_DIRECT_ATTRIBUTE |
577
+ TurboRex::Windows::ALPC::ALPC_MESSAGE_WORK_ON_BEHALF_ATTRIBUTE
578
+ )
579
+ msg_attr = APIProxy.alloc_c_struct('ALPC_MESSAGE_ATTRIBUTES')
580
+ reqired_buf_size = APIProxy.alloc_c_type('ULONG')
581
+ @buf = required_buf(attr)
582
+ ntstatus = APIProxy.alpcinitializemessageattribute(attr, @buf, @buf.sizeof, reqired_buf_size)
583
+ unless TinySDK.nt_success? ntstatus
584
+ formatted = TurboRex::Windows::TinySDK.format_hex_ntstatus ntstatus, hex_str: true
585
+ raise "Failed to call AlpcInitializeMessageAttribute: #{formatted}"
586
+ end
587
+
588
+ @struct = @buf
589
+ end
590
+
591
+ def required_buf(attr)
592
+ size = required_buf_size(attr)
593
+ APIProxy.alloc_c_ary('BYTE', size)
594
+ end
595
+
596
+ def required_buf_size(attr)
597
+ required_bud_size = APIProxy.alloc_c_type('ULONG')
598
+ ntstatus = APIProxy.alpcinitializemessageattribute(attr, 0, 0, required_bud_size)
599
+ required_bud_size.str.unpack('V')[0]
600
+ end
601
+ end
602
+
603
+ class Client
604
+ class ServerProxy
605
+ def initialize(communication_handle, transport, server_pid, server_tid)
606
+ @communication_handle = communication_handle
607
+ @transport = transport
608
+ @server_pid = server_pid
609
+ @server_tid = server_tid
610
+ end
611
+
612
+ def gets(opts = {})
613
+ @transport.recv(@communication_handle, opts)
614
+ end
615
+
616
+ def puts(message, opts = {})
617
+ if message.is_a? String
618
+ port_message = PortMessage.new(payload: message)
619
+ if opts[:last_header]
620
+ port_message.header = opts[:last_header]
621
+ end
622
+ elsif message.is_a? PortMessage
623
+ port_message = message
624
+ else
625
+ raise TurboRex::Exception::ALPC::UnknownPayloadType
626
+ end
627
+
628
+ message_attr = opts.delete(:message_attr) || MessageAttribute.new.struct
629
+ @transport.send(@communication_handle, port_message.message, message_attr, opts)
630
+ end
631
+
632
+ def send_recv(message, opts = {})
633
+ if message.is_a? String
634
+ port_message = PortMessage.new(payload: message)
635
+ elsif message.is_a? ::Metasm::C::AllocCStruct
636
+ port_message = message
637
+ else
638
+ raise TurboRex::Exception::ALPC::UnknownPayloadType
639
+ end
640
+
641
+ send_attr = port_message.attributes || opts[:attributes] || 0
642
+ recv_attr = opts[:recv_attr] || MessageAttribute.new.struct
643
+ @transport.send_recv(@communication_handle, port_message.message, send_attr, recv_attr)
644
+ end
645
+
646
+ def disconnect
647
+ @transport.close
648
+ end
649
+
650
+ alias_method :write, :puts
651
+ alias_method :read, :gets
652
+ end
653
+
654
+ def initialize(port_name, opts = {})
655
+ if TurboRex::Windows::Utils.is_wow64?
656
+ default_cpu = Metasm::Ia32
657
+ else
658
+ default_cpu = Metasm::X86_64
659
+ end
660
+
661
+ cpu = opts[:cpu] || default_cpu
662
+ APIProxy.init(cpu)
663
+
664
+ unless port_name.start_with? '\\'
665
+ port_name = '\\' + port_name
666
+ end
667
+ @port_name = port_name
668
+
669
+ @transport = Transport.new
670
+ end
671
+
672
+ def connect(opts = {}, &block)
673
+ opts[:port_name] = @port_name
674
+ @communication_handle, msg = @transport.connect(opts)
675
+ server_pid = msg.client_id&.unique_process
676
+ server_tid = msg.client_id&.unique_thread
677
+ @server = ServerProxy.new(@communication_handle, @transport, server_pid, server_tid)
678
+ yield(@server) if block_given?
679
+ [@server, msg]
680
+ end
681
+ end
682
+
683
+ class Server
684
+ include TurboRex::Windows::ALPC
685
+
686
+ attr_reader :port_name
687
+ attr_reader :obj_attr
688
+
689
+ class ClientStub
690
+ def initialize(communication_handle, conn_handle, transport, conn_message)
691
+ @communication_handle = communication_handle
692
+ @connection_handle = conn_handle
693
+ @conn_message = conn_message
694
+ @transport = transport
695
+ @client_id = conn_message.client_id
696
+ end
697
+
698
+ def gets(opts = {})
699
+ @transport.recv(@connection_handle, opts)
700
+ end
701
+
702
+ def puts(message, message_id = nil, opts = {})
703
+ if message.is_a? String
704
+ port_message = PortMessage.new(payload: message)
705
+ if opts[:last_header]
706
+ port_message.header = opts[:last_header]
707
+ elsif message_id
708
+ port_message.message_id = message_id
709
+ else
710
+ raise "Message ID must be specified when :last_header option is not specified."
711
+ end
712
+ elsif message.is_a? PortMessage
713
+ port_message = message
714
+ else
715
+ raise TurboRex::Exception::ALPC::UnknownPayloadType
716
+ end
717
+
718
+ message_attr = opts.delete(:message_attr) || port_message.attributes
719
+ @transport.send(@communication_handle, port_message.message, message_attr, opts)
720
+ end
721
+
722
+ # def impersonate(msg)
723
+ # ntstatus = APIProxy.ntalpcimpersonateclientofport(@communication_handle, msg.message, 0)
724
+ # TurboRex::Windows::TinySDK.format_hex_ntstatus ntstatus
725
+ # end
726
+
727
+ alias_method :write, :puts
728
+ alias_method :read, :gets
729
+ end
730
+
731
+ def initialize(port_name, opts = {})
732
+ if TurboRex::Windows::Utils.is_wow64?
733
+ default_cpu = Metasm::Ia32
734
+ else
735
+ default_cpu = Metasm::X86_64
736
+ end
737
+
738
+ cpu = opts[:cpu] || default_cpu
739
+ APIProxy.init(cpu)
740
+
741
+ @communication_port_handles = []
742
+ @clients = []
743
+
744
+ unless port_name.start_with? '\\'
745
+ port_name = '\\' + port_name
746
+ end
747
+ @port_name = port_name
748
+
749
+ if wport_name = TurboRex::Windows::Utils.multibyte_to_widechar(port_name)
750
+ dest_str = APIProxy.alloc_c_struct('UNICODE_STRING')
751
+ APIProxy.rtlinitunicodestring(dest_str, wport_name)
752
+
753
+ handle = APIProxy.alloc_c_type('HANDLE')
754
+ alpc_port_attr, obj_attr = make_attr(obj_name: dest_str)
755
+ ntstatus = APIProxy.ntalpccreateport(handle, obj_attr, alpc_port_attr)
756
+
757
+ unless TinySDK.nt_success? ntstatus
758
+ formatted = TurboRex::Windows::TinySDK.format_hex_ntstatus ntstatus, hex_str: true
759
+ raise "Unable to create alpc port: #{formatted}"
760
+ end
761
+
762
+ @conn_port_handle = handle[0]
763
+ @transport = Transport.new
764
+ else
765
+ raise "Unable to convert characters to utf-16le encoding."
766
+ end
767
+ end
768
+
769
+ def run(opts = {}, &block)
770
+ loop do
771
+ conn_message = @transport.listen(@conn_port_handle)
772
+ puts "[*] Receiving connection request"
773
+
774
+ if opts[:conn_req_cb]
775
+ unless (permit_conn = opts[:conn_req_cb].call(:connection_req, conn_message, self))
776
+ ######################################################################################################################
777
+ ## Requires following params(UniqueProcess, UniqueThread, MessageId), otherwise raise STATUS_REPLY_MESSAGE_MISMATCH ##
778
+ ## uniq_process = conn_message.client_id.unique_process ##
779
+ ## uniq_thread = conn_message.client_id.unique_thread ##
780
+ ## message_id = conn_message.message_id ##
781
+ ## ##
782
+ ## Or we can pass a instance of PortMessage with the 'port_message' key ##
783
+ ######################################################################################################################
784
+ @transport.refuse_connect(port_message: conn_message) and next
785
+ end
786
+ end
787
+
788
+ client = accept(conn_message)
789
+ if block_given?
790
+ yield(client)
791
+ end
792
+ end
793
+ end
794
+
795
+ def accept(conn_message, &block)
796
+ handle, ntstatus = @transport.accept(port_message: conn_message)
797
+ if TinySDK.nt_success?(ntstatus)
798
+ @communication_port_handles << handle
799
+ client_stub = ClientStub.new(handle, @conn_port_handle, @transport, conn_message)
800
+ @clients << client_stub
801
+ yield(client_stub) if block_given?
802
+ client_stub
803
+ else
804
+ puts "[-] Unable to accept connection. (0x#{ntstatus.to_s(16).upcase})"
805
+ raise TurboRex::Exception::ALPC::UnableToAcceptConnection
806
+ end
807
+ end
808
+
809
+ #def impersonate_client(client)
810
+ # client.impersonate
811
+ #end
812
+
813
+ private
814
+
815
+ def make_attr(opts = {})
816
+ unless @alpc_port_attr
817
+ alpc_port_attr = APIProxy.alloc_c_struct('ALPC_PORT_ATTRIBUTES')
818
+ alpc_port_attr.Flags = ALPC::ALPC_PORFLG_ALLOW_LPC_REQUESTS
819
+ alpc_port_attr.MaxMessageLength = 0x1000
820
+ alpc_port_attr.MemoryBandwidth = 0
821
+ alpc_port_attr.MaxPoolUsage = 0xFFFFFFFF
822
+ alpc_port_attr.MaxSectionSize = 0xFFFFFFFF
823
+ alpc_port_attr.MaxViewSize = 0xFFFFFFFF
824
+ alpc_port_attr.MaxTotalSectionSize = 0xFFFFFFFF
825
+ alpc_port_attr.DupObjectTypes = 0xFFFFFFFF
826
+ end
827
+
828
+ unless @obj_attr
829
+ obj_attr = APIProxy.alloc_c_struct('OBJECT_ATTRIBUTES')
830
+ obj_attr.Length = obj_attr.sizeof
831
+ obj_attr.ObjectName = opts[:obj_name]
832
+ @obj_attr = obj_attr
833
+ end
834
+
835
+ [alpc_port_attr, obj_attr]
836
+ end
837
+
838
+ def np
839
+ APIProxy.np
840
+ end
841
+ end
842
+ end
843
+ end
844
+ end