turborex 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +674 -0
- data/README.md +38 -0
- data/README.rdoc +19 -0
- data/examples/alpc_client.rb +15 -0
- data/examples/alpc_server.rb +14 -0
- data/examples/com_client.rb +19 -0
- data/examples/com_finder.rb +39 -0
- data/examples/create_instance.rb +15 -0
- data/examples/cstruct.rb +19 -0
- data/examples/find_com_client_calls.rb +16 -0
- data/examples/find_rpc_security_callback.rb +12 -0
- data/examples/rpc_finder.rb +117 -0
- data/examples/scan_exports.rb +5 -0
- data/examples/scan_imports.rb +5 -0
- data/examples/tinysdk.rb +17 -0
- data/lib/turborex.rb +21 -0
- data/lib/turborex/cstruct.rb +565 -0
- data/lib/turborex/cstruct/struct_helper.rb +7 -0
- data/lib/turborex/exception.rb +65 -0
- data/lib/turborex/fuzzer.rb +204 -0
- data/lib/turborex/fuzzer/containers.rb +115 -0
- data/lib/turborex/fuzzer/coverage.rb +67 -0
- data/lib/turborex/fuzzer/mutators.rb +25 -0
- data/lib/turborex/fuzzer/seed.rb +30 -0
- data/lib/turborex/monkey.rb +11 -0
- data/lib/turborex/msrpc.rb +14 -0
- data/lib/turborex/msrpc/decompiler.rb +244 -0
- data/lib/turborex/msrpc/midl.rb +747 -0
- data/lib/turborex/msrpc/ndrtype.rb +167 -0
- data/lib/turborex/msrpc/rpcbase.rb +777 -0
- data/lib/turborex/msrpc/rpcfinder.rb +1426 -0
- data/lib/turborex/msrpc/utils.rb +70 -0
- data/lib/turborex/pefile.rb +8 -0
- data/lib/turborex/pefile/pe.rb +61 -0
- data/lib/turborex/pefile/scanner.rb +82 -0
- data/lib/turborex/utils.rb +321 -0
- data/lib/turborex/windows.rb +402 -0
- data/lib/turborex/windows/alpc.rb +844 -0
- data/lib/turborex/windows/com.rb +266 -0
- data/lib/turborex/windows/com/client.rb +84 -0
- data/lib/turborex/windows/com/com_finder.rb +330 -0
- data/lib/turborex/windows/com/com_registry.rb +100 -0
- data/lib/turborex/windows/com/interface.rb +522 -0
- data/lib/turborex/windows/com/utils.rb +210 -0
- data/lib/turborex/windows/constants.rb +82 -0
- data/lib/turborex/windows/process.rb +56 -0
- data/lib/turborex/windows/security.rb +12 -0
- data/lib/turborex/windows/security/ace.rb +76 -0
- data/lib/turborex/windows/security/acl.rb +25 -0
- data/lib/turborex/windows/security/security_descriptor.rb +118 -0
- data/lib/turborex/windows/tinysdk.rb +89 -0
- data/lib/turborex/windows/utils.rb +138 -0
- data/resources/headers/alpc/ntdef.h +72 -0
- data/resources/headers/alpc/ntlpcapi.h +1014 -0
- data/resources/headers/rpc/common.h +162 -0
- data/resources/headers/rpc/guiddef.h +191 -0
- data/resources/headers/rpc/internal_ndrtypes.h +262 -0
- data/resources/headers/rpc/rpc.h +10 -0
- data/resources/headers/rpc/rpcdce.h +266 -0
- data/resources/headers/rpc/rpcdcep.h +187 -0
- data/resources/headers/rpc/rpcndr.h +39 -0
- data/resources/headers/rpc/v4_x64/rpcinternals.h +154 -0
- data/resources/headers/rpc/wintype.h +517 -0
- data/resources/headers/tinysdk/tinysdk.h +5 -0
- data/resources/headers/tinysdk/tinysdk/comdef.h +645 -0
- data/resources/headers/tinysdk/tinysdk/dbghelp.h +118 -0
- data/resources/headers/tinysdk/tinysdk/guiddef.h +194 -0
- data/resources/headers/tinysdk/tinysdk/memoryapi.h +12 -0
- data/resources/headers/tinysdk/tinysdk/poppack.h +12 -0
- data/resources/headers/tinysdk/tinysdk/pshpack4.h +13 -0
- data/resources/headers/tinysdk/tinysdk/winnt.h +1059 -0
- data/resources/headers/tinysdk/tinysdk/wintype.h +326 -0
- metadata +290 -0
@@ -0,0 +1,266 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
unless OS.windows?
|
4
|
+
warn "\033[33m[-]Warning: This module doesn't currently work on non-Windows os.\033[0m"
|
5
|
+
end
|
6
|
+
|
7
|
+
module TurboRex
|
8
|
+
class Windows < ::Metasm::WinOS
|
9
|
+
module COM
|
10
|
+
module WellKnownIID
|
11
|
+
IID_IUnknown = '00000000-0000-0000-C000-000000000046'
|
12
|
+
IID_IClassFactory = '00000001-0000-0000-C000-000000000046'
|
13
|
+
IID_IStream = '0000000c-0000-0000-C000-000000000046'
|
14
|
+
IID_IStorage = '0000000b-0000-0000-C000-000000000046'
|
15
|
+
IID_IPSFactoryBuffer = 'D5F569D0-593B-101A-B569-08002B2DBF7A'
|
16
|
+
IID_IRpcProxyBuffer = 'D5F56A34-593B-101A-B569-08002B2DBF7A'
|
17
|
+
IID_IRpcStubBuffer = 'D5F56AFC-593B-101A-B569-08002B2DBF7A'
|
18
|
+
end
|
19
|
+
|
20
|
+
CLSCTX_INPROC_SERVER = 0x1
|
21
|
+
CLSCTX_INPROC_HANDLER = 0x2
|
22
|
+
CLSCTX_LOCAL_SERVER = 0x4
|
23
|
+
CLSCTX_INPROC_SERVER16 = 0x8
|
24
|
+
CLSCTX_REMOTE_SERVER = 0x10
|
25
|
+
CLSCTX_INPROC_HANDLER16 = 0x20
|
26
|
+
CLSCTX_RESERVED1 = 0x40
|
27
|
+
CLSCTX_RESERVED2 = 0x80
|
28
|
+
CLSCTX_RESERVED3 = 0x100
|
29
|
+
CLSCTX_RESERVED4 = 0x200
|
30
|
+
CLSCTX_NO_CODE_DOWNLOAD = 0x400
|
31
|
+
CLSCTX_RESERVED5 = 0x800
|
32
|
+
CLSCTX_NO_CUSTOM_MARSHAL = 0x1000
|
33
|
+
CLSCTX_ENABLE_CODE_DOWNLOAD = 0x2000
|
34
|
+
CLSCTX_NO_FAILURE_LOG = 0x4000
|
35
|
+
CLSCTX_DISABLE_AAA = 0x8000
|
36
|
+
CLSCTX_ENABLE_AAA = 0x10000
|
37
|
+
CLSCTX_FROM_DEFAULT_CONTEXT = 0x20000
|
38
|
+
CLSCTX_ACTIVATE_X86_SERVER = 0x40000
|
39
|
+
CLSCTX_ACTIVATE_32_BIT_SERVER = CLSCTX_ACTIVATE_X86_SERVER
|
40
|
+
CLSCTX_ACTIVATE_64_BIT_SERVER = 0x80000
|
41
|
+
CLSCTX_ENABLE_CLOAKING = 0x100000
|
42
|
+
CLSCTX_APPCONTAINER = 0x400000
|
43
|
+
CLSCTX_ACTIVATE_AAA_AS_IU = 0x800000
|
44
|
+
CLSCTX_RESERVED6 = 0x1000000
|
45
|
+
CLSCTX_ACTIVATE_ARM32_SERVER = 0x2000000
|
46
|
+
CLSCTX_PS_DLL = 0x80000000
|
47
|
+
|
48
|
+
# WinVer >= NT4 && DCOM
|
49
|
+
if TurboRex::Windows.version.first >= 4
|
50
|
+
CLSCTX_ALL = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER
|
51
|
+
CLSCTX_SERVER = CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER
|
52
|
+
end
|
53
|
+
|
54
|
+
# Mashal Flag
|
55
|
+
MSHLFLAGS_NORMAL = 0
|
56
|
+
MSHLFLAGS_TABLESTRONG = 1
|
57
|
+
MSHLFLAGS_TABLEWEAK = 2
|
58
|
+
MSHLFLAGS_NOPING = 4
|
59
|
+
MSHLFLAGS_RESERVED1 = 8
|
60
|
+
MSHLFLAGS_RESERVED2 = 16
|
61
|
+
MSHLFLAGS_RESERVED3 = 32
|
62
|
+
MSHLFLAGS_RESERVED4 = 64
|
63
|
+
|
64
|
+
# Mashal Context
|
65
|
+
MSHCTX_LOCAL = 0
|
66
|
+
MSHCTX_NOSHAREDMEM = 1
|
67
|
+
MSHCTX_DIFFERENTMACHINE = 2
|
68
|
+
MSHCTX_INPROC = 3
|
69
|
+
MSHCTX_CROSSCTX = 4
|
70
|
+
MSHCTX_RESERVED1 = 5
|
71
|
+
|
72
|
+
# Object Refenrence Flags
|
73
|
+
OBJREF_STANDARD = 1
|
74
|
+
OBJREF_HANDLER = 2
|
75
|
+
OBJREF_CUSTOM = 4
|
76
|
+
OBJREF_EXTENDED = 8
|
77
|
+
|
78
|
+
# STGM Constant
|
79
|
+
STGM_READ = 0x00000000
|
80
|
+
STGM_WRITE = 0x00000001
|
81
|
+
STGM_READWRITE = 0x00000002
|
82
|
+
STGM_SHARE_DENY_NONE = 0x00000040
|
83
|
+
STGM_SHARE_DENY_READ = 0x00000030
|
84
|
+
STGM_SHARE_DENY_WRITE = 0x00000020
|
85
|
+
STGM_SHARE_EXCLUSIVE = 0x00000010
|
86
|
+
STGM_PRIORITY = 0x00040000
|
87
|
+
STGM_CREATE = 0x00001000
|
88
|
+
STGM_CONVERT = 0x00020000
|
89
|
+
STGM_FAILIFTHERE = 0x00000000
|
90
|
+
STGM_DIRECT = 0x00000000
|
91
|
+
STGM_TRANSACTED = 0x00010000
|
92
|
+
STGM_NOSCRATCH = 0x00100000
|
93
|
+
STGM_NOSNAPSHOT = 0x00200000
|
94
|
+
STGM_SIMPLE = 0x08000000
|
95
|
+
STGM_DIRECT_SWMR = 0x00400000
|
96
|
+
STGM_DELETEONRELEASE = 0x04000000
|
97
|
+
|
98
|
+
INTERNAL_APIPROXY = TurboRex::Windows::Win32API.dup
|
99
|
+
INTERNAL_APIPROXY.parse_c <<-EOS
|
100
|
+
typedef struct SHashChain
|
101
|
+
{
|
102
|
+
struct SHashChain *pNext;
|
103
|
+
struct SHashChain *pPrev;
|
104
|
+
} SHashChain;
|
105
|
+
|
106
|
+
typedef struct _CIDObject {
|
107
|
+
void * pVtable;
|
108
|
+
SHashChain _pidChain;
|
109
|
+
SHashChain _oidChain;
|
110
|
+
unsigned int _dwState;
|
111
|
+
unsigned int _cRefs;
|
112
|
+
void *_pServer;
|
113
|
+
void *_pServerCtx;
|
114
|
+
GUID _oid;
|
115
|
+
unsigned int _aptID;
|
116
|
+
void *_pStdWrapper;
|
117
|
+
void *_pStdID;
|
118
|
+
unsigned int _cCalls;
|
119
|
+
unsigned int _cLocks;
|
120
|
+
SHashChain _oidUnpinReqChain;
|
121
|
+
unsigned int _dwOidUnpinReqState;
|
122
|
+
void *_pvObjectTrackCookie;
|
123
|
+
} CIDObject;
|
124
|
+
|
125
|
+
typedef struct _CStdWrapper
|
126
|
+
{
|
127
|
+
void * pVtable;
|
128
|
+
unsigned long _dwState;
|
129
|
+
unsigned int _cRefs;
|
130
|
+
unsigned int _cCalls;
|
131
|
+
unsigned int _cIFaces;
|
132
|
+
void *_pIFaceHead;
|
133
|
+
void *_pCtxEntryHead;
|
134
|
+
void *_pCtxFreeList;
|
135
|
+
void *_pServer;
|
136
|
+
CIDObject *_pID;
|
137
|
+
void *_pVtableAddress;
|
138
|
+
}CStdWrapper;
|
139
|
+
|
140
|
+
typedef struct _tagIPIDEntry
|
141
|
+
{
|
142
|
+
void *pNextIPID;
|
143
|
+
unsigned int dwFlags;
|
144
|
+
unsigned int cStrongRefs;
|
145
|
+
unsigned int cWeakRefs;
|
146
|
+
unsigned int cPrivateRefs;
|
147
|
+
void *pv;
|
148
|
+
void *pStub;
|
149
|
+
void *pOXIDEntry;
|
150
|
+
GUID ipid;
|
151
|
+
GUID iid;
|
152
|
+
void *pChnl;
|
153
|
+
void *pIRCEntry;
|
154
|
+
void *pInterfaceName;
|
155
|
+
void *pOIDFLink;
|
156
|
+
void *pOIDBLink;
|
157
|
+
} tagIPIDEntry;
|
158
|
+
|
159
|
+
|
160
|
+
typedef struct _CStdIdentity
|
161
|
+
{
|
162
|
+
void *pVtable;
|
163
|
+
void *pVtable2;
|
164
|
+
unsigned int _dwFlags;
|
165
|
+
int _cIPIDs;
|
166
|
+
tagIPIDEntry *_pFirstIPID;
|
167
|
+
void *_pStdId;
|
168
|
+
void *_pChnl;
|
169
|
+
GUID _clsidHandler;
|
170
|
+
int _cNestedCalls;
|
171
|
+
int _cTableRefs;
|
172
|
+
} CStdIdentity;
|
173
|
+
|
174
|
+
|
175
|
+
typedef struct _IRpcStubBufferVtbl
|
176
|
+
{
|
177
|
+
HRESULT (__fastcall *QueryInterface)(void *, const GUID *, void **);
|
178
|
+
unsigned int (__fastcall *AddRef)(void *);
|
179
|
+
unsigned int (__fastcall *Release)(void *);
|
180
|
+
HRESULT (__fastcall *Connect)(void *, void *);
|
181
|
+
void (__fastcall *Disconnect)(void *);
|
182
|
+
HRESULT (__fastcall *Invoke)(void *, void *, void *);
|
183
|
+
void *(__fastcall *IsIIDSupported)(void *, const GUID *);
|
184
|
+
unsigned int (__fastcall *CountRefs)(void *);
|
185
|
+
HRESULT (__fastcall *DebugServerQueryInterface)(void *, void **);
|
186
|
+
void (__fastcall *DebugServerRelease)(void *, void *);
|
187
|
+
} IRpcStubBufferVtbl;
|
188
|
+
|
189
|
+
typedef struct tagCStdStubBuffer
|
190
|
+
{
|
191
|
+
const struct IRpcStubBufferVtbl * lpVtbl;
|
192
|
+
LONG RefCount;
|
193
|
+
struct IUnknown * pvServerObject;
|
194
|
+
|
195
|
+
const struct ICallFactoryVtbl * pCallFactoryVtbl;
|
196
|
+
const IID * pAsyncIID;
|
197
|
+
struct IPSFactoryBuffer * pPSFactory;
|
198
|
+
const struct IReleaseMarshalBuffersVtbl * pRMBVtbl;
|
199
|
+
} CStdStubBuffer;
|
200
|
+
|
201
|
+
typedef struct tagCInterfaceStubHeader
|
202
|
+
{
|
203
|
+
const IID * piid;
|
204
|
+
const void * pServerInfo; // MIDL_SERVER_INFO
|
205
|
+
ULONG DispatchTableCount;
|
206
|
+
const void * pDispatchTable;
|
207
|
+
} CInterfaceStubHeader;
|
208
|
+
|
209
|
+
typedef struct tagCInterfaceProxyHeader
|
210
|
+
{
|
211
|
+
#ifdef USE_STUBLESS_PROXY
|
212
|
+
const void * pStublessProxyInfo;
|
213
|
+
#endif
|
214
|
+
const IID * piid;
|
215
|
+
} CInterfaceProxyHeader;
|
216
|
+
|
217
|
+
typedef struct tagCInterfaceProxyVtbl
|
218
|
+
{
|
219
|
+
CInterfaceProxyHeader header;
|
220
|
+
void *Vtbl[1];
|
221
|
+
} CInterfaceProxyVtbl;
|
222
|
+
|
223
|
+
typedef struct tagCInterfaceStubVtbl
|
224
|
+
{
|
225
|
+
CInterfaceStubHeader header;
|
226
|
+
IRpcStubBufferVtbl Vtbl;
|
227
|
+
} CInterfaceStubVtbl;
|
228
|
+
|
229
|
+
typedef struct tagCInterfaceStubVtbl * PCInterfaceStubVtblList;
|
230
|
+
typedef struct tagCInterfaceProxyVtbl * PCInterfaceProxyVtblList;
|
231
|
+
typedef const char * PCInterfaceName;
|
232
|
+
typedef int __stdcall IIDLookupRtn( const IID * pIID, int * pIndex );
|
233
|
+
typedef IIDLookupRtn * PIIDLookup;
|
234
|
+
|
235
|
+
typedef struct tagProxyFileInfo
|
236
|
+
{
|
237
|
+
const PCInterfaceProxyVtblList *pProxyVtblList;
|
238
|
+
const PCInterfaceStubVtblList *pStubVtblList;
|
239
|
+
const PCInterfaceName * pNamesArray;
|
240
|
+
const IID ** pDelegatedIIDs;
|
241
|
+
const PIIDLookup pIIDLookupRtn;
|
242
|
+
unsigned short TableSize;
|
243
|
+
unsigned short TableVersion;
|
244
|
+
const IID ** pAsyncIIDLookup;
|
245
|
+
LONG_PTR Filler2;
|
246
|
+
LONG_PTR Filler3;
|
247
|
+
LONG_PTR Filler4;
|
248
|
+
}ProxyFileInfo;
|
249
|
+
|
250
|
+
typedef struct tagCStdPSFactoryBuffer
|
251
|
+
{
|
252
|
+
const IPSFactoryBufferVtbl * lpVtbl;
|
253
|
+
LONG RefCount;
|
254
|
+
const ProxyFileInfo ** pProxyFileList;
|
255
|
+
LONG Filler1; //Reserved for future use.
|
256
|
+
} CStdPSFactoryBuffer;
|
257
|
+
EOS
|
258
|
+
|
259
|
+
require 'turborex/windows/com/interface.rb'
|
260
|
+
require 'turborex/windows/com/utils.rb'
|
261
|
+
require 'turborex/windows/com/client.rb'
|
262
|
+
require 'turborex/windows/com/com_registry.rb'
|
263
|
+
require 'turborex/windows/com/com_finder.rb'
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module TurboRex
|
2
|
+
class Windows < Metasm::WinOS
|
3
|
+
module COM
|
4
|
+
class Client
|
5
|
+
include WellKnownIID
|
6
|
+
|
7
|
+
attr_reader :clsid
|
8
|
+
attr_reader :api_proxy
|
9
|
+
attr_reader :iunknown
|
10
|
+
|
11
|
+
def initialize(clsid, opts = {})
|
12
|
+
@clsid = clsid
|
13
|
+
@context = opts[:cls_context] || CLSCTX_ALL
|
14
|
+
@iunknown = Interface::IUnknown.new
|
15
|
+
@apartment = opts[:apartment] || 0
|
16
|
+
@api_proxy = Win32API.dup
|
17
|
+
@cp = @api_proxy.cp
|
18
|
+
|
19
|
+
Win32API.coinitializeex(0, @apartment)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Binding to class implementation
|
23
|
+
def create_instance(opts={})
|
24
|
+
interface = opts[:interface] || @iunknown
|
25
|
+
iid = interface.iid
|
26
|
+
cls_context = opts[:cls_context] || @context
|
27
|
+
ppv = @api_proxy.alloc_c_ptr('PVOID')
|
28
|
+
pclsid = Utils.clsid_to_raw(@clsid)
|
29
|
+
piid = Utils.clsid_to_raw(iid)
|
30
|
+
|
31
|
+
hr = @api_proxy.cocreateinstance(pclsid, 0, cls_context, piid, ppv)
|
32
|
+
raise "Failed to call CoCreateInstance: #{TinySDK.format_hex_ntstatus(hr, hex_str: true)}" unless TinySDK.nt_success?(hr)
|
33
|
+
pthis = ppv[0]
|
34
|
+
interface.this = pthis
|
35
|
+
@iunknown = interface if interface.kind_of?(Interface::IUnknown)
|
36
|
+
interface
|
37
|
+
end
|
38
|
+
|
39
|
+
# Binding to class object(class factory)
|
40
|
+
def get_class_object(opts={})
|
41
|
+
interface = Interface::IClassFactory.new
|
42
|
+
iid = interface.iid
|
43
|
+
cls_context = opts[:cls_context] || @context
|
44
|
+
server_info = opts[:server_info]
|
45
|
+
ppv = @api_proxy.alloc_c_ptr('LPVOID')
|
46
|
+
pclsid = Utils.clsid_to_raw(@clsid)
|
47
|
+
piid = Utils.clsid_to_raw(iid)
|
48
|
+
|
49
|
+
hr = @api_proxy.cogetclassobject(pclsid, cls_context, server_info, piid, ppv)
|
50
|
+
raise "Failed to call CoGetClassObject: #{TinySDK.format_hex_ntstatus(hr, hex_str: true)}" unless TinySDK.nt_success?(hr)
|
51
|
+
|
52
|
+
pthis = ppv[0]
|
53
|
+
interface.this = pthis
|
54
|
+
interface
|
55
|
+
end
|
56
|
+
|
57
|
+
def query_interface(iid_or_iface)
|
58
|
+
interface = nil
|
59
|
+
if iid_or_iface.is_a?(Interface)
|
60
|
+
interface = iid_or_iface
|
61
|
+
iid = interface.iid
|
62
|
+
elsif iid_or_iface.is_a?(String)
|
63
|
+
iid = iid_or_iface
|
64
|
+
end
|
65
|
+
|
66
|
+
create_instance unless @iunknown.this
|
67
|
+
iid = Utils.clsid_to_raw(iid)
|
68
|
+
ppv = @api_proxy.alloc_c_ptr('PVOID')
|
69
|
+
|
70
|
+
if @iunknown.QueryInterface(iid, ppv).nil?
|
71
|
+
if interface
|
72
|
+
interface.this = ppv[0]
|
73
|
+
return interface
|
74
|
+
else
|
75
|
+
return ppv[0]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
false
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,330 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'turborex/pefile/scanner'
|
3
|
+
|
4
|
+
module TurboRex
|
5
|
+
class Windows < Metasm::WinOS
|
6
|
+
module COM
|
7
|
+
class Finder
|
8
|
+
include TurboRex::Utils::DisassemblerHelper
|
9
|
+
include TurboRex::PEFile::Scanner
|
10
|
+
|
11
|
+
def initialize(clsid)
|
12
|
+
@clsid = clsid
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class InProcFinder < Finder
|
17
|
+
attr_reader :clsid
|
18
|
+
attr_reader :server_path
|
19
|
+
|
20
|
+
include Utils
|
21
|
+
|
22
|
+
def initialize(clsid)
|
23
|
+
@clsid = clsid
|
24
|
+
@process = TurboRex::Windows::Process.new(nil, -1)
|
25
|
+
@memory = @process.memory
|
26
|
+
@ptr_len = @process.cpusz / 8
|
27
|
+
end
|
28
|
+
|
29
|
+
def locate_interface_methods(iid)
|
30
|
+
Win32::Registry::HKEY_CLASSES_ROOT.open("CLSID\\{#{@clsid}}") do |reg_clsid|
|
31
|
+
reg_clsid.open('InprocServer32') do |reg_inproc32|
|
32
|
+
@server_path = reg_inproc32.read_s_expand('')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class_factory = Utils.dll_get_class_object(@clsid, @server_path)
|
37
|
+
ppv = INTERNAL_APIPROXY.alloc_c_ptr('PVOID')
|
38
|
+
unless class_factory.CreateInstance(0, Utils.clsid_to_raw(iid), ppv)
|
39
|
+
# class_factory.Release
|
40
|
+
pvtbl = to_ptr(@memory.get_page(ppv[0], @ptr_len))
|
41
|
+
proxy_file_info = get_proxy_file_info(iid)
|
42
|
+
return false unless proxy_file_info
|
43
|
+
|
44
|
+
count = get_disptbl_count(proxy_file_info)
|
45
|
+
|
46
|
+
if count
|
47
|
+
methods = []
|
48
|
+
@memory.get_page(pvtbl, count * @ptr_len).split('').each_slice(@ptr_len) { |m| methods << to_ptr(m.join) }
|
49
|
+
|
50
|
+
first_method = methods.first
|
51
|
+
_module = @process.modules.find { |m| first_method > m.addr && first_method < m.addr + m.size }
|
52
|
+
if relative
|
53
|
+
return {
|
54
|
+
module: _module.path,
|
55
|
+
methods: methods.map.with_index { |method, i| { index: i, rva: method - _module.addr } }
|
56
|
+
}
|
57
|
+
else
|
58
|
+
return {
|
59
|
+
module: _module.path,
|
60
|
+
methods: methods.map.with_index { |method, i| { index: i, va: method } }
|
61
|
+
}
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class OutOfProcFinder < Finder
|
70
|
+
attr_reader :clsid
|
71
|
+
attr_reader :client
|
72
|
+
attr_reader :process
|
73
|
+
attr_reader :pid
|
74
|
+
attr_reader :handle
|
75
|
+
|
76
|
+
include Utils
|
77
|
+
|
78
|
+
def initialize(clsid, opts = {})
|
79
|
+
pid = opts[:pid]
|
80
|
+
context = opts[:context] || CLSCTX_ALL
|
81
|
+
@clsid = clsid
|
82
|
+
@client = Client.new(clsid)
|
83
|
+
@iunknown = @client.create_instance(cls_context: context, interface: Interface::IUnknown.new)
|
84
|
+
@pid = get_pid_by_std_objref(@iunknown) || pid
|
85
|
+
|
86
|
+
process = TurboRex::Windows::Process.new(@pid)
|
87
|
+
raise "Unable to open process #{pid}" unless process.handle
|
88
|
+
unless process.addrsz == (sz = Metasm::WinOS::Process.new(nil, -1).addrsz)
|
89
|
+
raise "The architecture of Ruby interpreter process(#{sz}-bit) is not same as target process"
|
90
|
+
end
|
91
|
+
|
92
|
+
@process = process
|
93
|
+
@handle = @process.handle
|
94
|
+
@ptr_len = @process.cpusz / 8
|
95
|
+
@memory = @process.memory
|
96
|
+
|
97
|
+
unless @process.load_symbol_table('combase.dll')
|
98
|
+
raise "Unable to load combase.dll's symbol"
|
99
|
+
end
|
100
|
+
|
101
|
+
@combase_base_addr = (@process.modules.find { |m| m.path =~ Regexp.new('combase.dll', true) }).addr
|
102
|
+
end
|
103
|
+
|
104
|
+
def locate_multiple_interfaces(iids, relative = true)
|
105
|
+
iids.map {|iid| locate_interface_methods(iid, relative)}.compact
|
106
|
+
end
|
107
|
+
|
108
|
+
def locate_interface_methods(iid, relative = true)
|
109
|
+
# Let the object exporter create IPID entry for target interface
|
110
|
+
tmp_interface = TurboRex::Windows::COM::Interface.define_interface(iid, {}, Interface::IUnknown)
|
111
|
+
ppv = INTERNAL_APIPROXY.alloc_c_ptr('PVOID')
|
112
|
+
raise "No such interface: #{iid}" unless @iunknown.QueryInterface(Utils.clsid_to_raw(iid), ppv).nil?
|
113
|
+
tmp_interface.this = ppv[0]
|
114
|
+
tmp_interface.marshal_to_string # For In-Proc server
|
115
|
+
return nil unless buckets_addr = find_oid_buckets_addr
|
116
|
+
|
117
|
+
headers = read_bucket_headers(buckets_addr)
|
118
|
+
walk_buckets(headers) do |_cid_obj, ipid_entry|
|
119
|
+
raw_iid = ipid_entry.str[ipid_entry.iid.stroff, ipid_entry.iid.sizeof]
|
120
|
+
_iid = TurboRex::MSRPC::Utils.raw_to_guid_str(raw_iid)
|
121
|
+
|
122
|
+
if _iid == iid
|
123
|
+
methods_count = iface_vtbl_count(ipid_entry)
|
124
|
+
return nil unless methods_count
|
125
|
+
|
126
|
+
if ipid_entry.pv
|
127
|
+
pvtbl = to_ptr(@memory.get_page(ipid_entry.pv, @ptr_len))
|
128
|
+
end
|
129
|
+
|
130
|
+
methods = []
|
131
|
+
@memory.get_page(pvtbl, methods_count * @ptr_len).split('').each_slice(@ptr_len) { |m| methods << to_ptr(m.join) }
|
132
|
+
# dasm = Metasm::Shellcode.decode(@memory, Metasm::X86_64.new).disassembler
|
133
|
+
# dasm.disassemble_fast_deep(methods.last)
|
134
|
+
|
135
|
+
first_method = methods.first
|
136
|
+
_module = @process.modules.find { |m| first_method > m.addr && first_method < m.addr + m.size }
|
137
|
+
if relative
|
138
|
+
tmp_interface.Release
|
139
|
+
return {
|
140
|
+
module: _module.path,
|
141
|
+
methods: methods.map.with_index { |method, i| { index: i, rva: method - _module.addr } }
|
142
|
+
}
|
143
|
+
|
144
|
+
# return methods.map.with_index do |method, i|
|
145
|
+
# _module = @process.modules.find { |m| method > m.addr && method < m.addr + m.size }
|
146
|
+
# _module ? {index: i, module: _module.path, rva: method - _module.addr} : nil
|
147
|
+
# end
|
148
|
+
else
|
149
|
+
tmp_interface.Release
|
150
|
+
return {
|
151
|
+
module: _module.path,
|
152
|
+
methods: methods.map.with_index { |method, i| { index: i, va: method } }
|
153
|
+
}
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# Should decrease reference count
|
159
|
+
tmp_interface.Release
|
160
|
+
nil
|
161
|
+
end
|
162
|
+
|
163
|
+
def walk_buckets(buckets, &block)
|
164
|
+
buckets.each do |bucket, base_addr|
|
165
|
+
pNext = bucket.pNext
|
166
|
+
until pNext == base_addr
|
167
|
+
obj_addr = pNext - bucket.sizeof - @ptr_len
|
168
|
+
cid_obj = INTERNAL_APIPROXY.alloc_c_struct('CIDObject')
|
169
|
+
cid_obj.str = @memory.get_page(obj_addr, cid_obj.sizeof)
|
170
|
+
pNext = cid_obj._oidChain.pNext
|
171
|
+
|
172
|
+
std_ident = INTERNAL_APIPROXY.alloc_c_struct('CStdIdentity')
|
173
|
+
std_ident.str = @memory.get_page(cid_obj._pStdID, std_ident.sizeof)
|
174
|
+
walk_ipid_entries(std_ident._pFirstIPID) do |ipid_entry|
|
175
|
+
yield(cid_obj, ipid_entry) if block_given?
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
|
182
|
+
def walk_ipid_entries(pfirst_entry)
|
183
|
+
ipid_entries = []
|
184
|
+
pNext = pfirst_entry
|
185
|
+
|
186
|
+
# TODO: stdid.cIPIDs
|
187
|
+
until pNext.nil?
|
188
|
+
ipid_entry = INTERNAL_APIPROXY.alloc_c_struct('tagIPIDEntry')
|
189
|
+
ipid_entry.str = @memory.get_page(pNext, ipid_entry.sizeof)
|
190
|
+
yield(ipid_entry) if block_given?
|
191
|
+
ipid_entries << ipid_entry
|
192
|
+
pNext = ipid_entry.pNextIPID
|
193
|
+
end
|
194
|
+
|
195
|
+
ipid_entries
|
196
|
+
end
|
197
|
+
|
198
|
+
def find_oid_buckets_addr
|
199
|
+
buffer = INTERNAL_APIPROXY.alloc_c_ary('BYTE', 300)
|
200
|
+
sym_info = INTERNAL_APIPROXY.alloc_c_struct('SYMBOL_INFO')
|
201
|
+
sym_info.SizeOfStruct = sym_info.sizeof
|
202
|
+
sym_info.MaxNameLen = 150
|
203
|
+
buffer[0, sym_info.sizeof] = sym_info.str
|
204
|
+
|
205
|
+
if INTERNAL_APIPROXY.symfromname(@handle, 'COIDTable::s_OIDBuckets', buffer) == 1
|
206
|
+
sym_info.str = buffer[0, sym_info.sizeof]
|
207
|
+
sym_info.Address
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
def read_bucket_headers(address)
|
212
|
+
headers = []
|
213
|
+
|
214
|
+
TurboRex::Windows::Constants::MAX_BUCKETS_NUM.times do |i|
|
215
|
+
header = INTERNAL_APIPROXY.alloc_c_struct('SHashChain')
|
216
|
+
header_addr = address + i * header.sizeof
|
217
|
+
header.str = @memory.get_page(header_addr, header.sizeof)
|
218
|
+
next if header.pNext == header_addr
|
219
|
+
|
220
|
+
headers << [header, header_addr]
|
221
|
+
end
|
222
|
+
|
223
|
+
headers
|
224
|
+
end
|
225
|
+
|
226
|
+
def close
|
227
|
+
# TODO: Unload symbols
|
228
|
+
if @process
|
229
|
+
@process.close_handle
|
230
|
+
@handle = nil
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
private
|
235
|
+
|
236
|
+
def iface_vtbl_count(ipid_entry)
|
237
|
+
if ipid_entry.pStub # Standard interface stub
|
238
|
+
pstub_vtbl = @memory.get_page(ipid_entry.pStub, @ptr_len)
|
239
|
+
if_stub_vtbl = INTERNAL_APIPROXY.alloc_c_struct('CInterfaceStubVtbl')
|
240
|
+
if_stub_vtbl.str = @memory.get_page(to_ptr(pstub_vtbl) - if_stub_vtbl.Vtbl.stroff, if_stub_vtbl.sizeof)
|
241
|
+
if_stub_vtbl.header.DispatchTableCount
|
242
|
+
else
|
243
|
+
# Get ProxyFileInfo->pStubVtblList->header->DispatchTableCount
|
244
|
+
raw_iid = ipid_entry.str[ipid_entry.iid.stroff, ipid_entry.iid.sizeof]
|
245
|
+
iid = TurboRex::MSRPC::Utils.raw_to_guid_str(raw_iid)
|
246
|
+
proxy_file_info = get_proxy_file_info(iid)
|
247
|
+
raise unless proxy_file_info
|
248
|
+
|
249
|
+
# pcif_stub_vtbl_list = to_ptr(@memory.get_page(proxy_file_info.pStubVtblList, @ptr_len))
|
250
|
+
# if_stub_vtbl = TurboRex::Windows::COM::INTERNAL_APIPROXY.alloc_c_struct('CInterfaceStubVtbl')
|
251
|
+
# if_stub_vtbl.str = @memory.get_page(pcif_stub_vtbl_list, if_stub_vtbl.sizeof)
|
252
|
+
# return if_stub_vtbl.header.DispatchTableCount
|
253
|
+
get_disptbl_count(proxy_file_info)
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
class ClientFinder
|
259
|
+
include TurboRex::Utils::COMApiBacktraceHelper
|
260
|
+
|
261
|
+
BACKTRACE_PROC = {
|
262
|
+
'CoCreateInstance' => :bt_cocreateinstance
|
263
|
+
}
|
264
|
+
|
265
|
+
def initialize(fname_or_dasm)
|
266
|
+
if fname_or_dasm.is_a?(String)
|
267
|
+
pe = Metasm::PE.decode_file(fname_or_dasm)
|
268
|
+
@dasm = _disassemble_executable_sections(pe)
|
269
|
+
elsif fname_or_dasm.is_a?(::Metasm::Disassembler)
|
270
|
+
@dasm = dasm
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
def find_client_call(dis=nil)
|
275
|
+
res = []
|
276
|
+
|
277
|
+
BACKTRACE_PROC.each do |k, v|
|
278
|
+
@dasm.call_sites(::Metasm::Expression[k]).each do |c|
|
279
|
+
bt_result = v.to_proc.call(self, @dasm, c)
|
280
|
+
pv = bt_result[:pv]
|
281
|
+
clsid = bt_result[:rclsid]
|
282
|
+
iid = bt_result[:riid]
|
283
|
+
context = bt_result[:context]
|
284
|
+
|
285
|
+
unless pv == :unknown
|
286
|
+
func_start = @dasm.find_function_start(c)
|
287
|
+
func_end = @dasm.function_including(c).return_address
|
288
|
+
return unless func_end
|
289
|
+
func_end = func_end.first
|
290
|
+
dis ||= @dasm.decoded.values.select {|di| di.address >= func_start && di.address <= func_end}
|
291
|
+
dis.select {|di| di.opcode.props[:saveip]}.each do |di_call|
|
292
|
+
if (obj, vtbl, index = solve_cppobj_call(@dasm, di_call))
|
293
|
+
if obj.reduce_rec.to_s == pv.to_s
|
294
|
+
res << {
|
295
|
+
clsid: clsid,
|
296
|
+
iid: iid,
|
297
|
+
context: context,
|
298
|
+
method_index: index,
|
299
|
+
call_site: di_call.address
|
300
|
+
}
|
301
|
+
end
|
302
|
+
elsif fptr = solve_guard_icall(@dasm, di_call) # TODO: check Guard Flags to detect whether cfg is enabled
|
303
|
+
if fptr.is_a?(::Metasm::Indirection)
|
304
|
+
if fptr.pointer.op == :+ &&
|
305
|
+
fptr.pointer.rexpr.is_a?(Integer) &&
|
306
|
+
fptr.pointer.lexpr.is_a?(::Metasm::Indirection)
|
307
|
+
|
308
|
+
if fptr.pointer.lexpr.pointer.reduce_rec.to_s == pv.to_s
|
309
|
+
res << {
|
310
|
+
clsid: clsid,
|
311
|
+
iid: iid,
|
312
|
+
context: context,
|
313
|
+
method_index: fptr.pointer.rexpr / (@dasm.cpu.size / 8),
|
314
|
+
call_site: di_call.address
|
315
|
+
}
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
res
|
326
|
+
end
|
327
|
+
end
|
328
|
+
end
|
329
|
+
end
|
330
|
+
end
|