turborex 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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