added wrapper functions

This commit is contained in:
Ronnie Flathers
2020-03-13 23:31:59 -05:00
parent ba40bb7f12
commit ad8d54d75b
6 changed files with 171 additions and 32 deletions
+14
View File
@@ -86,6 +86,20 @@ type AppDomainVtbl struct {
get_DynamicDirectory uintptr
}
func GetAppDomain(runtimeHost *ICORRuntimeHost) (appDomain *AppDomain, err error) {
var pAppDomain uintptr
var pIUnknown uintptr
hr := runtimeHost.GetDefaultDomain(&pIUnknown)
err = checkOK(hr, "runtimeHost.GetDefaultDomain")
if err != nil {
return
}
iu := NewIUnknown(pIUnknown)
hr = iu.QueryInterface(&IID_AppDomain, &pAppDomain)
err = checkOK(hr, "IUnknown.QueryInterface")
return NewAppDomain(pAppDomain), err
}
func NewAppDomain(ppv uintptr) *AppDomain {
return (*AppDomain)(unsafe.Pointer(ppv))
}
+38
View File
@@ -0,0 +1,38 @@
// +build windows
package main
import (
clr "github.com/ropnop/go-clr"
"log"
"fmt"
"io/ioutil"
"runtime"
)
func main() {
fmt.Println("[+] Loading DLL from Disk")
ret, err := clr.ExecuteDLL(
"TestDLL.dll",
"TestDLL.HelloWorld",
"SayHello",
"foobar")
if err != nil {
log.Fatal(err)
}
fmt.Printf("[+] DLL Return Code: %d\n", ret)
fmt.Println("[+] Executing EXE from memory")
exebytes, err := ioutil.ReadFile("helloworld.exe")
if err != nil {
log.Fatal(err)
}
runtime.KeepAlive(exebytes)
ret2, err := clr.ExecuteByteArray(exebytes)
if err != nil {
log.Fatal(err)
}
fmt.Printf("[+] EXE Return Code: %d\n", ret2)
}
+7 -4
View File
@@ -37,14 +37,17 @@ func main() {
filename := os.Args[1]
exebytes, err := ioutil.ReadFile(filename)
must(err)
runtime.KeepAlive(&exebytes)
runtime.KeepAlive(exebytes)
var pMetaHost uintptr
hr := clr.CLRCreateInstance(&clr.CLSID_CLRMetaHost, &clr.IID_ICLRMetaHost, &pMetaHost)
checkOK(hr, "CLRCreateInstance")
metaHost := clr.NewICLRMetaHost(pMetaHost)
metaHost, err := clr.GetMetaHost()
must(err)
versionString := "v4.0.30319"
pwzVersion, _ := syscall.UTF16PtrFromString(versionString)
var pRuntimeInfo uintptr
hr := metaHost.GetRuntime(pwzVersion, &clr.IID_ICLRRuntimeInfo, &pRuntimeInfo)
hr = metaHost.GetRuntime(pwzVersion, &clr.IID_ICLRRuntimeInfo, &pRuntimeInfo)
checkOK(hr, "metahost.GetRuntime")
runtimeInfo := clr.NewICLRRuntimeInfo(pRuntimeInfo)
+109 -28
View File
@@ -4,21 +4,10 @@ package clr
import (
"fmt"
"runtime"
"strings"
"syscall"
)
var (
Metahost *ICLRMetaHost
RuntimeInfo *ICLRRuntimeInfo
IsLoadable bool
LegacyV2Runtime bool
CorRuntimeHost *ICORRuntimeHost
ClrRuntimeHost *ICLRRuntimeHost
Iu *IUnknown
LoadedAppDomain *AppDomain
LoadedAssembly *Assembly
EntryPoint *MethodInfo
"unsafe"
)
func GetMetaHost() (*ICLRMetaHost, error) {
@@ -81,23 +70,38 @@ func GetRuntimeInfo(metahost *ICLRMetaHost, version string) (*ICLRRuntimeInfo, e
func GetICLRRuntimeHost(runtimeInfo *ICLRRuntimeInfo) (*ICLRRuntimeHost, error) {
var pRuntimeHost uintptr
hr := runtimeInfo.GetInterface(&CLSID_CorRuntimeHost, &IID_ICLRRuntimeHost, &pRuntimeHost)
hr := runtimeInfo.GetInterface(&CLSID_CLRRuntimeHost, &IID_ICLRRuntimeHost, &pRuntimeHost)
err := checkOK(hr, "runtimeInfo.GetInterface")
if err != nil {
return nil, err
}
return NewICLRRuntimeHost(pRuntimeHost), nil
runtimeHost := NewICLRRuntimeHost(pRuntimeHost)
hr = runtimeHost.Start()
err = checkOK(hr, "runtimeHost.Start")
return runtimeHost, err
}
func GetICORRuntimeHost(runtimeInfo *ICLRRuntimeInfo) (*ICORRuntimeHost, error) {
var pRuntimeHost uintptr
hr := runtimeInfo.GetInterface(&CLSID_CorRuntimeHost, &IID_ICorRuntimeHost, &pRuntimeHost)
err := checkOK(hr, "runtimeInfo.GetInterface")
if err != nil {
return nil, err
}
runtimeHost := NewICORRuntimeHost(pRuntimeHost)
hr = runtimeHost.Start()
err = checkOK(hr, "runtimeHost.Start")
return runtimeHost, err
}
// ExecuteDLL is a wrapper function that will automatically load the latest installed CLR into the current process
// and execute a DLL on disk in the default app domain
func ExecuteDLL(dllpath, typeName, methodName, argument string) (retCode int, err error) {
func ExecuteDLL(dllpath, typeName, methodName, argument string) (retCode int16, err error) {
retCode = -1
metahost, err := GetMetaHost()
if err != nil {
return
}
defer metahost.Release()
runtimes, err := GetInstalledRuntimes(metahost)
if err != nil {
@@ -116,7 +120,6 @@ func ExecuteDLL(dllpath, typeName, methodName, argument string) (retCode int, er
if err != nil {
return
}
defer runtimeInfo.Release()
var isLoadable bool
hr := runtimeInfo.IsLoadable(&isLoadable)
err = checkOK(hr, "runtimeInfo.IsLoadable")
@@ -130,23 +133,101 @@ func ExecuteDLL(dllpath, typeName, methodName, argument string) (retCode int, er
if err != nil {
return
}
defer runtimeHost.Release()
hr = runtimeHost.Start()
err = checkOK(hr, "runtimeHost.Start")
if err != nil {
return
}
pDLLPath, _ := syscall.UTF16PtrFromString(dllpath)
pTypeName, _ := syscall.UTF16PtrFromString(typeName)
pMethodName, _ := syscall.UTF16PtrFromString(methodName)
pArgument, _ := syscall.UTF16PtrFromString(argument)
var pReturnVal *uint16
hr = runtimeHost.ExecuteInDefaultAppDomain(pDLLPath, pTypeName, pMethodName, pArgument, pReturnVal)
var pReturnVal uint16
hr = runtimeHost.ExecuteInDefaultAppDomain(pDLLPath, pTypeName, pMethodName, pArgument, &pReturnVal)
err = checkOK(hr, "runtimeHost.ExecuteInDefaultAppDomain")
if err != nil {
return int(*pReturnVal), err
return int16(pReturnVal), err
}
return int(*pReturnVal), nil
runtimeHost.Release()
runtimeInfo.Release()
metahost.Release()
return int16(pReturnVal), nil
}
func ExecuteByteArray(rawBytes []byte) (retCode int32, err error) {
retCode = -1
metahost, err := GetMetaHost()
if err != nil {
return
}
runtimes, err := GetInstalledRuntimes(metahost)
if err != nil {
return
}
var latestRuntime string
for _, r := range runtimes {
if strings.Contains(r, "v4") {
latestRuntime = r
break
} else {
latestRuntime = r
}
}
runtimeInfo, err := GetRuntimeInfo(metahost, latestRuntime)
if err != nil {
return
}
var isLoadable bool
hr := runtimeInfo.IsLoadable(&isLoadable)
err = checkOK(hr, "runtimeInfo.IsLoadable")
if err != nil {
return
}
if !isLoadable {
return -1, fmt.Errorf("%s is not loadable for some reason", latestRuntime)
}
runtimeHost, err := GetICORRuntimeHost(runtimeInfo)
if err != nil {
return
}
appDomain, err := GetAppDomain(runtimeHost)
if err != nil {
return
}
safeArray, err := CreateSafeArray(rawBytes)
if err != nil {
return
}
runtime.KeepAlive(&safeArray)
var pAssembly uintptr
hr = appDomain.Load_3(uintptr(unsafe.Pointer(&safeArray)), &pAssembly)
err = checkOK(hr, "appDomain.Load_3")
if err != nil {
return
}
assembly := NewAssembly(pAssembly)
var pEntryPointInfo uintptr
hr = assembly.GetEntryPoint(&pEntryPointInfo)
err = checkOK(hr, "assembly.GetEntryPoint")
if err != nil {
return
}
methodInfo := NewMethodInfo(pEntryPointInfo)
var pRetCode uintptr
nullVariant := Variant{
VT: 1,
Val: uintptr(0),
}
hr = methodInfo.Invoke_3(
nullVariant,
uintptr(0),
&pRetCode)
err = checkOK(hr, "methodInfo.Invoke_3")
if err != nil {
return
}
appDomain.Release()
runtimeHost.Release()
runtimeInfo.Release()
metahost.Release()
return int32(pRetCode), nil
}
+2
View File
@@ -34,7 +34,9 @@ func GetICLRMetaHost() (metahost *ICLRMetaHost, err error) {
}
//ICLRMetaHost Interface from metahost.h
// Couldnt have done any of this without this SO answer I stumbled on:
// https://stackoverflow.com/questions/37781676/how-to-use-com-component-object-model-in-golang
type ICLRMetaHost struct {
vtbl *ICLRMetaHostVtbl
}
+1
View File
@@ -47,6 +47,7 @@ func CreateSafeArray(rawBytes []byte) (SafeArray, error) {
cElements: uint32(size),
lLbound: 0,
}
runtime.KeepAlive(sab)
vt := uint16(0x11) // VT_UI1
ret, _, _ := procSafeArrayCreate.Call(
uintptr(vt),