forked from Ne0nd0g/go-clr
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathicorruntimehost.go
More file actions
330 lines (304 loc) · 11 KB
/
icorruntimehost.go
File metadata and controls
330 lines (304 loc) · 11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
//go:build windows
// +build windows
package clr
import (
"fmt"
"strings"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
type ICORRuntimeHost struct {
vtbl *ICORRuntimeHostVtbl
}
// ICORRuntimeHostVtbl Provides methods that enable the host to start and stop the common language runtime (CLR)
// explicitly, to create and configure application domains, to access the default domain, and to enumerate all
// domains running in the process.
// https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/icorruntimehost-interface
type ICORRuntimeHostVtbl struct {
QueryInterface uintptr
AddRef uintptr
Release uintptr
// CreateLogicalThreadState Do not use.
CreateLogicalThreadState uintptr
// DeleteLogicalThreadSate Do not use.
DeleteLogicalThreadState uintptr
// SwitchInLogicalThreadState Do not use.
SwitchInLogicalThreadState uintptr
// SwitchOutLogicalThreadState Do not use.
SwitchOutLogicalThreadState uintptr
// LocksHeldByLogicalThreadState Do not use.
LocksHeldByLogicalThreadState uintptr
// MapFile Maps the specified file into memory. This method is obsolete.
MapFile uintptr
// GetConfiguration Gets an object that allows the host to specify the callback configuration of the CLR.
GetConfiguration uintptr
// Start Starts the CLR.
Start uintptr
// Stop Stops the execution of code in the runtime for the current process.
Stop uintptr
// CreateDomain Creates an application domain. The caller receives an interface pointer of
// type _AppDomain to an instance of type System.AppDomain.
CreateDomain uintptr
// GetDefaultDomain Gets an interface pointer of type _AppDomain that represents the default domain for the current process.
GetDefaultDomain uintptr
// EnumDomains Gets an enumerator for the domains in the current process.
EnumDomains uintptr
// NextDomain Gets an interface pointer to the next domain in the enumeration.
NextDomain uintptr
// CloseEnum Resets a domain enumerator back to the beginning of the domain list.
CloseEnum uintptr
// CreateDomainEx Creates an application domain. This method allows the caller to pass an
// IAppDomainSetup instance to configure additional features of the returned _AppDomain instance.
CreateDomainEx uintptr
// CreateDomainSetup Gets an interface pointer of type IAppDomainSetup to an AppDomainSetup instance.
// IAppDomainSetup provides methods to configure aspects of an application domain before it is created.
CreateDomainSetup uintptr
// CreateEvidence Gets an interface pointer of type IIdentity, which allows the host to create security
// evidence to pass to CreateDomain or CreateDomainEx.
CreateEvidence uintptr
// UnloadDomain Unloads the specified application domain from the current process.
UnloadDomain uintptr
// CurrentDomain Gets an interface pointer of type _AppDomain that represents the domain loaded on the current thread.
CurrentDomain uintptr
}
// GetICORRuntimeHost is a wrapper function that takes in an ICLRRuntimeInfo and returns an ICORRuntimeHost object
// and loads it into the current process. This is the "deprecated" API, but the only way currently to load an assembly
// from memory (afaict)
func GetICORRuntimeHost(runtimeInfo *ICLRRuntimeInfo) (*ICORRuntimeHost, error) {
debugPrint("Entering into icorruntimehost.GetICORRuntimeHost()...")
runtimeHost, err := runtimeInfo.GetInterface(CLSID_CorRuntimeHost, IID_ICorRuntimeHost)
if err != nil {
return nil, err
}
err = runtimeHost.(*ICORRuntimeHost).Start()
return runtimeHost.(*ICORRuntimeHost), err
}
func (obj *ICORRuntimeHost) QueryInterface(riid windows.GUID, ppvObject unsafe.Pointer) error {
debugPrint("Entering into icorruntimehost.QueryInterface()...")
hr, _, err := syscall.SyscallN(
obj.vtbl.QueryInterface,
uintptr(unsafe.Pointer(obj)),
uintptr(unsafe.Pointer(&riid)), // A reference to the interface identifier (IID) of the interface being queried for.
uintptr(ppvObject),
)
if err != syscall.Errno(0) {
fmt.Println("1111111111111")
return fmt.Errorf("the IUknown::QueryInterface method returned an error:\r\n%s", err)
}
if hr != S_OK {
fmt.Println("222222222222222222")
return fmt.Errorf("the IUknown::QueryInterface method method returned a non-zero HRESULT: 0x%x", hr)
}
return nil
}
func (obj *ICORRuntimeHost) AddRef() uintptr {
ret, _, _ := syscall.SyscallN(
obj.vtbl.AddRef,
uintptr(unsafe.Pointer(obj)),
)
return ret
}
func (obj *ICORRuntimeHost) Release() uintptr {
ret, _, _ := syscall.SyscallN(
obj.vtbl.Release,
uintptr(unsafe.Pointer(obj)),
)
return ret
}
// Start starts the common language runtime (CLR).
// HRESULT Start ();
// https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/icorruntimehost-start-method
func (obj *ICORRuntimeHost) Start() error {
debugPrint("Entering into icorruntimehost.Start()...")
hr, _, err := syscall.SyscallN(
obj.vtbl.Start,
uintptr(unsafe.Pointer(obj)),
)
if err != syscall.Errno(0) {
// The system could not find the environment option that was entered.
// TODO Why is this error message returned?
debugPrint(fmt.Sprintf("the ICORRuntimeHost::Start method returned an error:\r\n%s", err))
}
if hr != S_OK {
return fmt.Errorf("the ICORRuntimeHost::Start method method returned a non-zero HRESULT: 0x%x", hr)
}
return nil
}
// GetDefaultDomain gets an interface pointer of type System._AppDomain that represents the default domain for the current process.
// HRESULT GetDefaultDomain (
//
// [out] IUnknown** pAppDomain
//
// );
// https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/icorruntimehost-getdefaultdomain-method
func (obj *ICORRuntimeHost) GetDefaultDomain() (IUnknown *IUnknown, err error) {
debugPrint("Entering into icorruntimehost.GetDefaultDomain()...")
hr, _, err := syscall.SyscallN(
obj.vtbl.GetDefaultDomain,
uintptr(unsafe.Pointer(obj)),
uintptr(unsafe.Pointer(&IUnknown)),
)
if err != syscall.Errno(0) {
// The specified procedure could not be found.
// TODO Why is this error message returned?
debugPrint(fmt.Sprintf("the ICORRuntimeHost::GetDefaultDomain method returned an error:\r\n%s", err))
}
if hr != S_OK {
err = fmt.Errorf("the ICORRuntimeHost::GetDefaultDomain method method returned a non-zero HRESULT: 0x%x", hr)
return
}
err = nil
return
}
// CreateDomain Creates an application domain. The caller receives an interface pointer of type _AppDomain to an instance of type System.AppDomain.
// HRESULT CreateDomain (
//
// [in] LPWSTR pwzFriendlyName,
// [in] IUnknown* pIdentityArray,
// [out] void **pAppDomain
//
// );
// https://docs.microsoft.com/en-us/previous-versions/dotnet/netframework-4.0/ms164322(v=vs.100)
func (obj *ICORRuntimeHost) CreateDomain(FriendlyName string) (pAppDomain *AppDomain, err error) {
pwzFriendlyName := &utf16Le(FriendlyName)[0]
var iu *IUnknown
debugPrint("Entering into icorruntimehost.CreateDomain()...")
hr, _, err := syscall.SyscallN(
obj.vtbl.CreateDomain,
uintptr(unsafe.Pointer(obj)),
uintptr(unsafe.Pointer(pwzFriendlyName)), // [in] LPWSTR pwzFriendlyName - An optional parameter used to give a friendly name to the domain
uintptr(unsafe.Pointer(nil)), // [in] IUnknown* pIdentityArray - An optional array of pointers to IIdentity instances that represent evidence mapped through security policy to establish a permission set
uintptr(unsafe.Pointer(&iu)), // [out] IUnknown** pAppDomain
)
if err != syscall.Errno(0) {
// The specified procedure could not be found.
// TODO Why is this error message returned?
debugPrint(fmt.Sprintf("the ICORRuntimeHost::CreateDomain method returned an error:\r\n%s", err))
}
if hr != S_OK {
err = fmt.Errorf("the ICORRuntimeHost::CreateDomain method returned a non-zero HRESULT: 0x%x", hr)
return
}
err = iu.QueryInterface(IID_AppDomain, unsafe.Pointer(&pAppDomain))
return
}
func (obj *ICORRuntimeHost) GetDomain(dName string) (pAppDomain *AppDomain, err error) {
hEnum, err := obj.EnumDomains()
if err != nil {
return
}
for {
ad, err := obj.NextDomain(hEnum)
if err != nil {
if strings.HasSuffix(err.Error(), "0x1") {
break
}
return nil, err
}
thisName, err := ad.GetFriendlyName()
if err != nil {
return nil, err
}
if strings.EqualFold(dName, thisName) {
return ad, nil
}
}
return nil, fmt.Errorf("could not find domain: %s", dName)
}
// EnumDomains Gets an enumerator for the domains in the current process.
// HRESULT EnumDomains (
//
// [out] HCORENUM *hEnum
//
// );
func (obj *ICORRuntimeHost) EnumDomains() (hEnum windows.Handle, err error) {
debugPrint("Entering into icorruntimehost.EnumDomains()...")
hr, _, err := syscall.SyscallN(
obj.vtbl.EnumDomains,
(uintptr(unsafe.Pointer(&hEnum))),
)
if err != syscall.Errno(0) {
err = fmt.Errorf("the ICORRuntimeHost::EnumDomains method returned an error:\n%s", err)
return
}
if hr != S_OK {
err = fmt.Errorf("the ICORRuntimeHost::EnumDomains method returned a non-zero HRESULT: 0x%x", hr)
return
}
err = nil
return
}
func (obj *ICORRuntimeHost) NextDomain(hDomainEnum windows.Handle) (ad *AppDomain, err error) {
debugPrint("Entering into icorruntimehost.NextDomain()...")
var iu *IUnknown
hr, _, err := syscall.SyscallN(
obj.vtbl.NextDomain,
uintptr(unsafe.Pointer(obj)),
uintptr(hDomainEnum),
uintptr(unsafe.Pointer(&iu)),
)
if err != syscall.Errno(0) {
err = fmt.Errorf("the ICORRuntimeHost::NextDomain method returned an error:\n%s", err)
return
}
if hr != S_OK {
err = fmt.Errorf("the ICORRuntimeHost::NextDomain method returned a non-zero HRESULT: 0x%x", hr)
return
}
err = iu.QueryInterface(IID_AppDomain, unsafe.Pointer(&ad))
return
}
func (obj *ICORRuntimeHost) CloseEnum(hDomainEnum windows.Handle) (err error) {
debugPrint("Entering into icorruntimehost.CloseEnum()...")
hr, _, err := syscall.SyscallN(
obj.vtbl.CloseEnum,
uintptr(unsafe.Pointer(obj)),
uintptr(hDomainEnum),
)
if err != syscall.Errno(0) {
err = fmt.Errorf("the ICORRuntimeHost::CloseEnum method returned an error:\n%s", err)
return err
}
if hr != S_OK {
err = fmt.Errorf("the ICORRuntimeHost::CloseEnum method returned a non-zero HRESULT: 0x%x", hr)
return err
}
err = nil
return err
}
func (obj *ICORRuntimeHost) UnloadDomain(appdomain *AppDomain) (err error) {
debugPrint("Entering into icorruntimehost.UnloadDomain()...")
hr, _, err := syscall.SyscallN(
obj.vtbl.UnloadDomain,
uintptr(unsafe.Pointer(obj)),
uintptr(unsafe.Pointer(appdomain)),
)
if err != syscall.Errno(0) {
err = fmt.Errorf("the ICORRuntimeHost::UnloadDomain method returned an error:\n%s", err)
return err
}
if hr != S_OK {
err = fmt.Errorf("the ICORRuntimeHost::UnloadDomain method returned a non-zero HRESULT: 0x%x", hr)
return err
}
err = nil
return err
}
func (obj *ICORRuntimeHost) Stop() (err error) {
debugPrint("Entering into icorruntimehost.Stop()...")
hr, _, err := syscall.SyscallN(
obj.vtbl.Stop,
uintptr(unsafe.Pointer(obj)),
)
if err != syscall.Errno(0) {
err = fmt.Errorf("the ICORRuntimeHost::UnloadDomain method returned an error:\n%s", err)
return err
}
if hr != S_OK {
err = fmt.Errorf("the ICORRuntimeHost::UnloadDomain method returned a non-zero HRESULT: 0x%x", hr)
return err
}
err = nil
return err
}