diff --git a/azure-pipelines.yml b/azure-pipelines.yml index df0331f..8da9071 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -39,7 +39,6 @@ steps: inputs: targetType: 'inline' script: 'choco install -y golang --no-progress; - choco install -y mingw --no-progress; refreshenv ; copy native-powershell\host.h .\pkg\powershell\ ; copy native-powershell\x64\Release\psh_host.dll . ; diff --git a/bin/host.h b/bin/host.h index 644d2db..5ff08ee 100644 --- a/bin/host.h +++ b/bin/host.h @@ -34,6 +34,9 @@ extern "C" { }NativePowerShell_LogString_Holder, * PNativePowerShell_LogString_Holder; void NativePowerShell_InitLibrary( NativePowerShell_AllocPointer, NativePowerShell_FreePointer); + + unsigned char* NativePowerShell_DefaultAlloc(unsigned long long size); + void NativePowerShell_DefaultFree(void* address); //typedef struct NativePowerShell_RunspaceHandle_ {} *NativePowerShell_RunspaceHandle; // typedef struct NativePowerShell_PowerShellHandle_ {} *NativePowerShell_PowerShellHandle; diff --git a/bin/psh_host.dll b/bin/psh_host.dll index f75ef4a..499d0b9 100644 Binary files a/bin/psh_host.dll and b/bin/psh_host.dll differ diff --git a/go.mod b/go.mod index 0e880ab..e3c694c 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,6 @@ go 1.12 require ( github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b - golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb + golang.org/x/sys v0.0.0-20191104094858-e8c54fb511f6 k8s.io/klog v1.0.0 ) diff --git a/go.sum b/go.sum index b81d8bc..7425fd8 100644 --- a/go.sum +++ b/go.sum @@ -3,5 +3,7 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekf github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb h1:fgwFCsaw9buMuxNd6+DQfAuSFqbNiQZpcgJQAgJsK6k= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191104094858-e8c54fb511f6 h1:ZJUmhYTp8GbGC0ViZRc2U+MIYQ8xx9MscsdXnclfIhw= +golang.org/x/sys v0.0.0-20191104094858-e8c54fb511f6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= diff --git a/native-powershell b/native-powershell index 60ee25e..49419e0 160000 --- a/native-powershell +++ b/native-powershell @@ -1 +1 @@ -Subproject commit 60ee25e186f8c704d7be99aba3c2cc1ce04827dd +Subproject commit 49419e083381ced660038977496a1ec0a172a371 diff --git a/pkg/powershell/chelpers.go b/pkg/powershell/chelpers.go index b6272d1..806aea4 100644 --- a/pkg/powershell/chelpers.go +++ b/pkg/powershell/chelpers.go @@ -6,171 +6,57 @@ import ( "golang.org/x/sys/windows" ) -/* - -#cgo CFLAGS: -I. -#cgo LDFLAGS: -static ${SRCDIR}/../../bin/psh_host.dll - - -#include -#include -#include "powershell.h" - -*/ -import "C" - -func makeString(str *C.wchar_t) string { - ptr := unsafe.Pointer(str) - count := C.wcslen(str) + 1 - arr := make([]uint16, count) - ptrwchar := unsafe.Pointer(&arr[0]) - - C.memcpy(ptrwchar, ptr, count*2) - - s := windows.UTF16ToString(arr) - return s -} - -func makeCString(str string) *C.wchar_t { - cs, _ := windows.UTF16PtrFromString(str) - ptrwchar := unsafe.Pointer(cs) - return C.MallocCopy((*C.wchar_t)(ptrwchar)) -} - -//export logWchart -// logWchart the C function pointer that dispatches to the Golang function for SimpleLogging -func logWchart(context uint64, str *C.wchar_t) { - if context != 0 { - s := makeString(str) - contextInterface := getRunspaceContext(context) - contextInterface.log.Write(s) - } -} - -//export logWarningWchart -// logWarningWchart the C function pointer that dispatches to the Golang function for SimpleLogging -func logWarningWchart(context uint64, str *C.wchar_t) { - if context != 0 { - s := makeString(str) - contextInterface := getRunspaceContext(context) - contextInterface.log.Warning(s) - } +func makeUint64FromPtr(v uintptr) uint64 { + return *((*uint64)(unsafe.Pointer(&v))) } - -//export logInformationWchart -// logInformationWchart the C function pointer that dispatches to the Golang function for SimpleLogging -func logInformationWchart(context uint64, str *C.wchar_t) { - if context != 0 { - s := makeString(str) - contextInterface := getRunspaceContext(context) - contextInterface.log.Information(s) - } +func makeUintptrFromUint64(v uint64) uintptr { + return *((*uintptr)(unsafe.Pointer(&v))) } -//export logVerboseWchart -// logVerboseWchart the C function pointer that dispatches to the Golang function for SimpleLogging -func logVerboseWchart(context uint64, str *C.wchar_t) { - if context != 0 { - s := makeString(str) - contextInterface := getRunspaceContext(context) - contextInterface.log.Verbose(s) - } +func allocWrapper(size uint64) uintptr { + return nativePowerShell_DefaultAlloc(size) } - -//export logDebugWchart -// logDebugWchart the C function pointer that dispatches to the Golang function for SimpleLogging -func logDebugWchart(context uint64, str *C.wchar_t) { - if context != 0 { - s := makeString(str) - contextInterface := getRunspaceContext(context) - contextInterface.log.Debug(s) - } +func freeWrapper(v uintptr) { + nativePowerShell_DefaultFree(v) } -//export logErrorWchart -// logErrorWchart the C function pointer that dispatches to the Golang function for SimpleLogging -func logErrorWchart(context uint64, str *C.wchar_t) { - if context != 0 { - s := makeString(str) - contextInterface := getRunspaceContext(context) - contextInterface.log.Error(s) - } -} +func mallocCopy(input uintptr, size uintptr) uintptr { + u64Size := makeUint64FromPtr(size) + data := allocWrapper(u64Size) + _ = memcpy(data, uintptr(unsafe.Pointer(input)), u64Size) -//export loglnWchart -// loglnWchart the C function pointer that dispatches to the Golang function for SimpleLogging -func loglnWchart(context uint64, str *C.wchar_t) { - if context != 0 { - s := makeString(str) - contextInterface := getRunspaceContext(context) - contextInterface.log.Writeln(s) - } + return data } -//export logWarninglnWchart -// logWarninglnWchart the C function pointer that dispatches to the Golang function for SimpleLogging -func logWarninglnWchart(context uint64, str *C.wchar_t) { - if context != 0 { - s := makeString(str) - contextInterface := getRunspaceContext(context) - contextInterface.log.Warningln(s) +func wsclen(str uintptr) uint64 { + var charCode uint16 = 1 + var i uint64 = 0 + for ; charCode != 0; i++ { + charCode = *(*uint16)(unsafe.Pointer(str + (makeUintptrFromUint64(i) * unsafe.Sizeof(charCode)))) } + return i } -//export logInformationlnWchart -// logInformationlnWchart the C function pointer that dispatches to the Golang function for SimpleLogging -func logInformationlnWchart(context uint64, str *C.wchar_t) { - if context != 0 { - s := makeString(str) - contextInterface := getRunspaceContext(context) - contextInterface.log.Informationln(s) - } -} +func makeString(str uintptr) string { + count := wsclen(str) + 1 + arr := make([]uint16, count) + ptrwchar := unsafe.Pointer(&arr[0]) -//export logVerboselnWchart -// logVerboselnWchart the C function pointer that dispatches to the Golang function for SimpleLogging -func logVerboselnWchart(context uint64, str *C.wchar_t) { - if context != 0 { - s := makeString(str) - contextInterface := getRunspaceContext(context) - contextInterface.log.Verboseln(s) - } -} + memcpy(uintptr(ptrwchar), str, count*2) -//export logDebuglnWchart -// logDebuglnWchart the C function pointer that dispatches to the Golang function for SimpleLogging -func logDebuglnWchart(context uint64, str *C.wchar_t) { - if context != 0 { - s := makeString(str) - contextInterface := getRunspaceContext(context) - contextInterface.log.Debugln(s) - } + s := windows.UTF16ToString(arr) + return s } -//export logErrorlnWchart -// logErrorlnWchart the C function pointer that dispatches to the Golang function for SimpleLogging -func logErrorlnWchart(context uint64, str *C.wchar_t) { - if context != 0 { - s := makeString(str) - contextInterface := getRunspaceContext(context) - contextInterface.log.Errorln(s) - } +func uintptrMakeString(ptr uintptr) string { + return makeString(ptr) } -//export commandWchart -// commandWchart the C function pointer that dispatches to the Golang function for Send-HostCommand -func commandWchart(context uint64, cMessage *C.wchar_t, input *C.NativePowerShell_PowerShellObject, inputCount uint64, ret *C.NativePowerShell_JsonReturnValues) { +func makeCStringUintptr(str string) uintptr { + cs, _ := windows.UTF16PtrFromString(str) + ptrwchar := unsafe.Pointer(cs) + size := 2 * (wsclen(uintptr(ptrwchar)) + 1) - var resultsWriter callbackResultsWriter - if context != 0 { - contextInterface := getRunspaceContext(context) - inputArr := make([]Object, inputCount) - for i := uint32(0); uint64(i) < inputCount; i++ { - inputArr[i] = makePowerShellObjectIndexed(input, i) - } - message := makeString(cMessage) - contextInterface.callback.Callback(contextInterface.recreateRunspace(), message, inputArr, &resultsWriter) - } - resultsWriter.filloutResults(ret) + return mallocCopy(uintptr(ptrwchar), makeUintptrFromUint64(size)) } diff --git a/pkg/powershell/higherops_test.go b/pkg/powershell/higherops_test.go index 6473374..b64848a 100644 --- a/pkg/powershell/higherops_test.go +++ b/pkg/powershell/higherops_test.go @@ -508,7 +508,7 @@ func TestCpowershellJsonMarshal(t *testing.T) { } func TestClogWchart_lookupFail(t *testing.T) { - cStr := makeCString("test String") + cStr := makeCStringUintptr("test String") caughtFailedToLoad := false defer func() { if r := recover(); r != nil { @@ -517,7 +517,7 @@ func TestClogWchart_lookupFail(t *testing.T) { caughtFailedToLoad = true } }() - logWchart(1, cStr) + loggerCallbackDebugln(1, cStr) if !caughtFailedToLoad { t.Fail() } diff --git a/pkg/powershell/hostcommand.go b/pkg/powershell/hostcommand.go index c6ee9a5..cd5d6b6 100644 --- a/pkg/powershell/hostcommand.go +++ b/pkg/powershell/hostcommand.go @@ -1,16 +1,6 @@ package powershell -/* - -#cgo CFLAGS: -I. -#cgo LDFLAGS: -static ${SRCDIR}/../../bin/psh_host.dll - - -#include -#include "powershell.h" - -*/ -import "C" +import "unsafe" // CallbackResultsWriter allows you to write values to powershell when inside Send-HostCommand type CallbackResultsWriter interface { @@ -35,34 +25,52 @@ func (callback CallbackFuncPtr) Callback(runspace Runspace, message string, inpu // callbackResultsWriter is the internal implementation of CallbackResultsWriter type callbackResultsWriter struct { - objects []C.NativePowerShell_GenericPowerShellObject + objects []nativePowerShell_GenericPowerShellObject +} + +func setGenericPowershellString(object *nativePowerShell_GenericPowerShellObject, value uintptr, autoRelease byte) { + object.typeEnum = nativePowerShell_PowerShellObjectTypeString + object.object = makeUint64FromPtr(value) + object.releaseObject = autoRelease +} + +func setGenericPowerShellHandle(object *nativePowerShell_GenericPowerShellObject, value nativePowerShell_PowerShellObject, autoRelease byte) { + object.typeEnum = nativePowerShell_PowerShellObjectHandle + object.object = value + object.releaseObject = autoRelease } // WriteString accumulates a string object to return from Send-HostCommand func (writer *callbackResultsWriter) WriteString(str string) { - cStr := makeCString(str) - var obj C.NativePowerShell_GenericPowerShellObject - C.SetGenericPowershellString(&obj, cStr, 1) + cStr := makeCStringUintptr(str) + var obj nativePowerShell_GenericPowerShellObject + setGenericPowershellString(&obj, cStr, 1) writer.objects = append(writer.objects, obj) } // Write accumulates a string object to return from Send-HostCommand func (writer *callbackResultsWriter) Write(handle Object, needsClose bool) { - var obj C.NativePowerShell_GenericPowerShellObject - var autoClose C.char - if needsClose { - autoClose = 1 - } - C.SetGenericPowerShellHandle(&obj, handle.toCHandle(), autoClose) + var obj nativePowerShell_GenericPowerShellObject + var autoClose = boolToByte(needsClose) + + setGenericPowerShellHandle(&obj, handle.toCHandle(), autoClose) writer.objects = append(writer.objects, obj) } +func mallocCopyGenericPowerShellObject(input *nativePowerShell_GenericPowerShellObject, inputCount uint64) *nativePowerShell_GenericPowerShellObject { + + size := uintptr(inputCount) * unsafe.Sizeof(*input) + + return (*nativePowerShell_GenericPowerShellObject)(unsafe.Pointer(mallocCopy(uintptr(unsafe.Pointer(input)), size))) +} + // filloutResults takes accumulated objects from Write calls and prepares them to cross the C boundary -func (writer *callbackResultsWriter) filloutResults(results *C.NativePowerShell_JsonReturnValues) { +func (writer *callbackResultsWriter) filloutResults(res uintptr) { + results := (*nativePowerShell_JsonReturnValues)(unsafe.Pointer(res)) results.objects = nil results.count = 0 - if writer.objects != nil { - results.count = C.ulong(len(writer.objects)) - results.objects = C.MallocCopyGenericPowerShellObject(&writer.objects[0], C.ulonglong(len(writer.objects))) + if writer.objects != nil && len(writer.objects) > 0 { + results.count = uint32(len(writer.objects)) + results.objects = mallocCopyGenericPowerShellObject(&writer.objects[0], uint64(len(writer.objects))) } } diff --git a/pkg/powershell/powershell.cpp b/pkg/powershell/powershell.cpp deleted file mode 100644 index ef33de1..0000000 --- a/pkg/powershell/powershell.cpp +++ /dev/null @@ -1,164 +0,0 @@ -#include -#include "powershell.h" -#include "./../../bin/host.h" - -#include -#include -#include "sys/types.h" -#include "_cgo_export.h" - -#include - - - unsigned char *MallocWrapper(unsigned long long size) - { - auto ptr = (unsigned char *)malloc(size); - if (ptr == nullptr) - { - throw "memory alloc returned nullptr"; - } - return ptr; - } -void FreeWrapper(void *ptr) -{ - return free(ptr); - } - -void InitLibraryHelper(){ - NativePowerShell_InitLibrary(MallocWrapper, free); -} - -void * MallocCopyGeneric(const void * input, unsigned long long byteCount ){ - if(input == nullptr){ - return nullptr; - } - void* dest = MallocWrapper(byteCount); - memcpy(dest, input, byteCount); - return dest; -} - -NativePowerShell_GenericPowerShellObject * MallocCopyGenericPowerShellObject(NativePowerShell_GenericPowerShellObject* input, unsigned long long inputCount){ - return (NativePowerShell_GenericPowerShellObject *)MallocCopyGeneric(input, inputCount * sizeof(input[0])); -} - -const wchar_t* MallocCopy(const wchar_t* str) -{ - if (str == NULL) - return NULL; - - size_t s = wcslen(str) + 1; - return (const wchar_t *)MallocCopyGeneric(str, s * sizeof(str[0])); -} - - void Logger(void *context, const wchar_t* s) - { - logWchart((unsigned long long )context, (wchar_t *)s); - //printf("My Member Logger: %ws\n", s); - } - void Loggerln(void *context, const wchar_t* s) - { - loglnWchart((unsigned long long )context, (wchar_t *)s); - //printf("My Member Logger: %ws\n", s); - } - void LoggerDebug(void *context, const wchar_t* s) - { - logDebugWchart((unsigned long long )context, (wchar_t *)s); - //printf("My Member Logger: %ws\n", s); - } - void LoggerDebugln(void *context, const wchar_t* s) - { - logDebuglnWchart((unsigned long long )context, (wchar_t *)s); - //printf("My Member Logger: %ws\n", s); - } - void LoggerVerbose(void *context, const wchar_t* s) - { - logVerboseWchart((unsigned long long )context, (wchar_t *)s); - //printf("My Member Logger: %ws\n", s); - } - void LoggerVerboseln(void *context, const wchar_t* s) - { - logVerboselnWchart((unsigned long long )context, (wchar_t *)s); - //printf("My Member Logger: %ws\n", s); - } - void LoggerInformation(void *context, const wchar_t* s) - { - logInformationWchart((unsigned long long )context, (wchar_t *)s); - //printf("My Member Logger: %ws\n", s); - } - void LoggerInformationln(void *context, const wchar_t* s) - { - logInformationlnWchart((unsigned long long )context, (wchar_t *)s); - //printf("My Member Logger: %ws\n", s); - } - void LoggerWarning(void *context, const wchar_t* s) - { - logWarningWchart((unsigned long long )context, (wchar_t *)s); - //printf("My Member Logger: %ws\n", s); - } - void LoggerWarningln(void *context, const wchar_t* s) - { - logWarninglnWchart((unsigned long long )context, (wchar_t *)s); - //printf("My Member Logger: %ws\n", s); - } - void LoggerError(void *context, const wchar_t* s) - { - logErrorWchart((unsigned long long )context, (wchar_t *)s); - //printf("My Member Logger: %ws\n", s); - } - void LoggerErrorln(void *context, const wchar_t* s) - { - logErrorlnWchart((unsigned long long )context, (wchar_t *)s); - //printf("My Member Logger: %ws\n", s); - } - -NativePowerShell_LogString_Holder LoggerDispatcher = { - Logger, - LoggerError, - LoggerWarning, - LoggerInformation, - LoggerVerbose, - LoggerDebug, - Loggerln, - LoggerErrorln, - LoggerWarningln, - LoggerInformationln, - LoggerVerboseln, - LoggerDebugln - }; - void Command(void *context, const wchar_t* s, NativePowerShell_PowerShellObject* input, unsigned long long inputCount, NativePowerShell_JsonReturnValues * returnValues) - { - commandWchart((unsigned long long) context, (wchar_t *)s, input, inputCount, returnValues); - } - -NativePowerShell_RunspaceHandle CreateRunspaceHelper(unsigned long long context, char useLogger, char useCommand ){ - PNativePowerShell_LogString_Holder loggerPtr = &LoggerDispatcher; - NativePowerShell_ReceiveJsonCommand commandPtr = Command; - if(useLogger == 0){ - loggerPtr = nullptr; - } - if(useCommand == 0){ - commandPtr = nullptr; - } - return NativePowerShell_CreateRunspace((void*)context, commandPtr, loggerPtr); -} - -NativePowerShell_RunspaceHandle CreateRemoteRunspaceHelper(unsigned long long context, char useLogger, const wchar_t * remoteMachine, const wchar_t * userName, const wchar_t * password ){ - PNativePowerShell_LogString_Holder loggerPtr = &LoggerDispatcher; - if(useLogger == 0){ - loggerPtr = nullptr; - } - return NativePowerShell_CreateRemoteRunspace((void*)context, loggerPtr, remoteMachine, userName, password); -} - - -void SetGenericPowershellString(NativePowerShell_GenericPowerShellObject* object, wchar_t *value, char autoRelease){ - object->type = NativePowerShell_PowerShellObjectTypeString; - object->instance.string = value; - object->releaseObject = autoRelease; -} - -void SetGenericPowerShellHandle(NativePowerShell_GenericPowerShellObject* object, NativePowerShell_PowerShellObject value,char autoRelease){ - object->type = NativePowerShell_PowerShellObjectHandle; - object->instance.psObject = value; - object->releaseObject = autoRelease; -} \ No newline at end of file diff --git a/pkg/powershell/powershell.go b/pkg/powershell/powershell.go index 7e0817a..d6cbd08 100644 --- a/pkg/powershell/powershell.go +++ b/pkg/powershell/powershell.go @@ -6,21 +6,9 @@ import ( "golang.org/x/sys/windows" ) -/* - -#cgo CFLAGS: -I. -#cgo LDFLAGS: -static ${SRCDIR}/../../bin/psh_host.dll - - -#include -#include "powershell.h" - -*/ -import "C" - // psCommand represents a powershell command, must call Close type psCommand struct { - handle C.NativePowerShell_PowerShellHandle + handle nativePowerShell_PowerShellHandle context *runspaceContext } @@ -38,21 +26,23 @@ func (runspace Runspace) createCommand() psCommand { currentCommand := currentlyInvoking[len(currentlyInvoking)-1] return currentCommand.createNested() } - return psCommand{C.NativePowerShell_CreatePowerShell(runspace.handle), runspace.runspaceContext} + handle := nativePowerShell_CreatePowerShell(runspace.handle) + + return psCommand{handle, runspace.runspaceContext} } // createNested a nested powershell command func (command psCommand) createNested() psCommand { - return psCommand{C.NativePowerShell_CreatePowerShellNested(command.handle), command.context} + return psCommand{nativePowerShell_CreatePowerShellNested(command.handle), command.context} } // Close and free a psCommand // , call on all objects even those that are Invoked func (command psCommand) Close() { - C.NativePowerShell_DeletePowershell(command.handle) + nativePowerShell_DeletePowershell(command.handle) } -func boolToCChar(b bool) C.char { +func boolToByte(b bool) byte { if b { return 1 } @@ -63,53 +53,46 @@ func boolToCChar(b bool) C.char { func (command psCommand) AddCommand(commandlet string, useLocalScope bool) { cs, _ := windows.UTF16PtrFromString(commandlet) - ptrwchar := unsafe.Pointer(cs) - localScope := boolToCChar(useLocalScope) + localScope := boolToByte(useLocalScope) - _ = C.NativePowerShell_AddCommandSpecifyScope(command.handle, (*C.wchar_t)(ptrwchar), localScope) + _ = nativePowerShell_AddCommandSpecifyScope(command.handle, cs, localScope) } // AddScript to an existing powershell command func (command psCommand) AddScript(script string, useLocalScope bool) { cs, _ := windows.UTF16PtrFromString(script) - ptrwchar := unsafe.Pointer(cs) - localScope := boolToCChar(useLocalScope) + localScope := boolToByte(useLocalScope) - _ = C.NativePowerShell_AddScriptSpecifyScope(command.handle, (*C.wchar_t)(ptrwchar), localScope) + _ = nativePowerShell_AddScriptSpecifyScope(command.handle, cs, localScope) } // AddArgumentString add a string argument to an existing powershell command func (command psCommand) AddArgumentString(argument string) { cs, _ := windows.UTF16PtrFromString(argument) - ptrwchar := unsafe.Pointer(cs) - - _ = C.NativePowerShell_AddArgument(command.handle, (*C.wchar_t)(ptrwchar)) + _ = nativePowerShell_AddArgument(command.handle, cs) } // AddArgument add a Object argument to an existing powershell command func (command psCommand) AddArgument(object Object) { - _ = C.NativePowerShell_AddPSObjectArgument(command.handle, object.handle) + _ = nativePowerShell_AddPSObjectArgument(command.handle, object.handle) } // AddParameterString add a string with a parameter name to an existing powershell command func (command psCommand) AddParameterString(paramName string, paramValue string) { cName, _ := windows.UTF16PtrFromString(paramName) - ptrName := unsafe.Pointer(cName) cValue, _ := windows.UTF16PtrFromString(paramValue) - ptrValue := unsafe.Pointer(cValue) - _ = C.NativePowerShell_AddParameterString(command.handle, (*C.wchar_t)(ptrName), (*C.wchar_t)(ptrValue)) + _ = nativePowerShell_AddParameterString(command.handle, cName, cValue) } // AddParameter add a Object with a parameter name to an existing powershell command func (command psCommand) AddParameter(paramName string, object Object) { cName, _ := windows.UTF16PtrFromString(paramName) - ptrName := unsafe.Pointer(cName) - _ = C.NativePowerShell_AddParameterObject(command.handle, (*C.wchar_t)(ptrName), object.handle) + _ = nativePowerShell_AddParameterObject(command.handle, cName, object.handle) } func (command psCommand) completeInvoke() { @@ -123,29 +106,31 @@ func (command psCommand) completeInvoke() { // Must still call Close on this object func (command psCommand) Invoke() *InvokeResults { - var objects *C.NativePowerShell_PowerShellObject - var count C.uint + var objects uintptr + var count uint command.context.invoking = append(command.context.invoking, command) defer command.completeInvoke() - exception := C.NativePowerShell_InvokeCommand(command.handle, &objects, &count) + exception := nativePowerShell_InvokeCommand(command.handle, &objects, &count) return makeInvokeResults(objects, count, exception) } -func makePowerShellObjectIndexed(objects *C.NativePowerShell_PowerShellObject, index uint32) Object { +func makePowerShellObjectIndexed(objects uintptr, index uint32) Object { // I don't get why I have to use unsafe.Pointer on C memory + var handle nativePowerShell_PowerShellObject + ptr := unsafe.Pointer(objects) - offset := (uintptr(index) * unsafe.Sizeof(*objects)) - var obj C.NativePowerShell_PowerShellObject = *(*C.NativePowerShell_PowerShellObject)(unsafe.Pointer(uintptr(ptr) + offset)) - return makePowerShellObject(obj) + offset := (uintptr(index) * unsafe.Sizeof(handle)) + handle = *(*nativePowerShell_PowerShellObject)(unsafe.Pointer(uintptr(ptr) + offset)) + return makePowerShellObject(handle) } -func makePowerShellObject(object C.NativePowerShell_PowerShellObject) Object { +func makePowerShellObject(object nativePowerShell_PowerShellObject) Object { // var obj uint64 = *(*uint64)(unsafe.Pointer(&object)) // return Object{obj} return Object{object} } -func makeInvokeResults(objects *C.NativePowerShell_PowerShellObject, count C.uint, exception C.NativePowerShell_PowerShellObject) *InvokeResults { +func makeInvokeResults(objects uintptr, count uint, exception nativePowerShell_PowerShellObject) *InvokeResults { results := InvokeResults{Objects: make([]Object, count), Exception: makePowerShellObject(exception), objectsNoClose: make(map[int]bool), diff --git a/pkg/powershell/powershell.h b/pkg/powershell/powershell.h deleted file mode 100644 index 470bc1f..0000000 --- a/pkg/powershell/powershell.h +++ /dev/null @@ -1,29 +0,0 @@ - -#include "./../../bin/host.h" -#include -#ifdef __cplusplus -extern "C" { -#endif - - -wchar_t GetChar(wchar_t *t, int offset); - - unsigned char* MallocWrapper(unsigned long long size); - void FreeWrapper(void *); - -void InitLibraryHelper(); - -NativePowerShell_GenericPowerShellObject * MallocCopyGenericPowerShellObject(NativePowerShell_GenericPowerShellObject* input, unsigned long long inputCount); -const wchar_t* MallocCopy(const wchar_t* str); - - void Logger(const wchar_t* s); - -NativePowerShell_RunspaceHandle CreateRunspaceHelper(unsigned long long, char useLogger, char useCommand); -NativePowerShell_RunspaceHandle CreateRemoteRunspaceHelper(unsigned long long context, char useLogger, const wchar_t * remoteMachine, const wchar_t * userName, const wchar_t * password ); - -void SetGenericPowershellString(NativePowerShell_GenericPowerShellObject* object, wchar_t *value,char autoRelease); -void SetGenericPowerShellHandle(NativePowerShell_GenericPowerShellObject* object, NativePowerShell_PowerShellObject handle,char autoRelease); - -#ifdef __cplusplus -} -#endif \ No newline at end of file diff --git a/pkg/powershell/powershellobjects.go b/pkg/powershell/powershellobjects.go index f3d4b36..98aa700 100644 --- a/pkg/powershell/powershellobjects.go +++ b/pkg/powershell/powershellobjects.go @@ -1,18 +1,8 @@ package powershell -/* - -#cgo CFLAGS: -I. -#cgo LDFLAGS: -static ${SRCDIR}/../../bin/psh_host.dll - - -#include -#include "powershell.h" - -*/ -import "C" -import "unsafe" -import "encoding/json" +import ( + "encoding/json" +) // Object representing an object return from a powershell invocation // @@ -20,24 +10,14 @@ import "encoding/json" // // See note on Object.Close for exceptions & more rules about Close type Object struct { - handle C.NativePowerShell_PowerShellObject + handle nativePowerShell_PowerShellObject } // toCHandle gets the backing handle of Object -func (obj Object) toCHandle() C.NativePowerShell_PowerShellObject { - // return *((*C.NativePowerShell_PowerShellObject)(unsafe.Pointer(&obj.handle))) +func (obj Object) toCHandle() nativePowerShell_PowerShellObject { return obj.handle } -// // toCHandle gets the backing handle of Object -// func makeCHandles(objects []Object) []C.NativePowerShell_PowerShellObject { -// cHandles := make([]C.NativePowerShell_PowerShellObject, len(objects)) -// for i,object := range(objects){ -// cHandles[i] = object.handle -// } -// return cHandles -// } - // Close allows the memory for the powershell object to be reclaimed // // Should be called on all objects returned from a powershell invocation (not callback parameters) @@ -46,21 +26,21 @@ func (obj Object) toCHandle() C.NativePowerShell_PowerShellObject { // // Needs to be called for every object returned from AddRef func (obj Object) Close() { - C.NativePowerShell_ClosePowerShellObject(obj.toCHandle()) + nativePowerShell_ClosePowerShellObject(obj.toCHandle()) } // AddRef returns a new Object that has to also be called Close on // -// This is useful in Callback processing, as those NativePowerShell_PowerShellObjects are auto closed, and to keep +// This is useful in Callback processing, as those nativePowerShell_PowerShellObjects are auto closed, and to keep // a reference after the function returns use AddRef func (obj Object) AddRef() Object { - handle := C.NativePowerShell_AddPSObjectHandle(obj.toCHandle()) + handle := nativePowerShell_AddPSObjectHandle(obj.toCHandle()) return makePowerShellObject(handle) } // IsNull returns true if the backing powershell object is null func (obj Object) IsNull() bool { - return C.NativePowerShell_IsPSObjectNullptr(obj.toCHandle()) == 1 + return nativePowerShell_IsPSObjectNullptr(obj.toCHandle()) == 1 } // Type returns the (System.Object).GetType().ToString() function @@ -71,9 +51,9 @@ func (obj Object) Type() string { return "nullptr" } - var str *C.wchar_t = C.NativePowerShell_GetPSObjectType(obj.toCHandle()) - defer C.FreeWrapper(unsafe.Pointer(str)) - return makeString(str) + str := nativePowerShell_GetPSObjectType(obj.toCHandle()) + defer freeWrapper(str) + return uintptrMakeString(str) } // ToString returns the (System.Object).ToString() function @@ -84,9 +64,9 @@ func (obj Object) ToString() string { return "nullptr" } - var str *C.wchar_t = C.NativePowerShell_GetPSObjectToString(obj.toCHandle()) - defer C.FreeWrapper(unsafe.Pointer(str)) - return makeString(str) + str := nativePowerShell_GetPSObjectToString(obj.toCHandle()) + defer freeWrapper(str) + return uintptrMakeString(str) } // JSONUnmarshal calls the ToString function and unmarshals it into the supplied object diff --git a/pkg/powershell/psh_host.go b/pkg/powershell/psh_host.go new file mode 100644 index 0000000..3342566 --- /dev/null +++ b/pkg/powershell/psh_host.go @@ -0,0 +1,95 @@ +package powershell + +//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zpsh_host.go psh_host.go + +//https://stackoverflow.com/questions/35154074/how-do-i-manage-windows-user-accounts-in-go +// copy ~\go\src\golang.org\x\sys\windows\mksyscall.go . + +const ( + nativePowerShell_InvalidHandleValue = 0 + nativePowerShell_InvalidPointer = uintptr(0) +) + +type ( + nativePowerShell_StringPtr = *uint16 + nativePowerShell_LogString func(context uintptr, messages nativePowerShell_StringPtr) uintptr + nativePowerShell_LogString_Holder struct { + Log uintptr + LogError uintptr + LogWarning uintptr + LogInformation uintptr + LogVerbose uintptr + LogDebug uintptr + LogLine uintptr + LogErrorLine uintptr + LogWarningLine uintptr + LogInformationLine uintptr + LogVerboseLine uintptr + LogDebugLine uintptr + } + nativePowerShell_RunspaceHandle = uint64 + nativePowerShell_PowerShellHandle = uint64 + nativePowerShell_PowerShellObject = uint64 + nativePowerShell_PowerShellObjectType = uint32 +) + +const ( + nativePowerShell_PowerShellObjectTypeString = 0 + nativePowerShell_PowerShellObjectHandle = 1 +) + +type ( + nativePowerShell_GenericPowerShellObject struct { + typeEnum nativePowerShell_PowerShellObjectType + object nativePowerShell_PowerShellObject // can also be union with string + releaseObject byte + } + + nativePowerShell_JsonReturnValues struct { + objects *nativePowerShell_GenericPowerShellObject + count uint32 + } + nativePowerShell_ReceiveJsonCommand func(context uintptr, command nativePowerShell_StringPtr, inputrs *nativePowerShell_PowerShellObject, inputCount uint64, returnValues *nativePowerShell_JsonReturnValues) uintptr +) + +//sys nativePowerShell_CreatePowerShell(handle nativePowerShell_RunspaceHandle) (status nativePowerShell_PowerShellHandle)= psh_host.NativePowerShell_CreatePowerShell +//sys nativePowerShell_CreatePowerShellNested(handle nativePowerShell_PowerShellHandle) (status nativePowerShell_PowerShellHandle)= psh_host.NativePowerShell_CreatePowerShellNested + +//sys nativePowerShell_DeletePowershell(handle nativePowerShell_PowerShellHandle) = psh_host.NativePowerShell_DeletePowershell + +// to fix command was of type *nativePowerShell_ReceiveJsonCommand +// to fix holder was of type *nativePowerShell_LogString_Holder +//sys nativePowerShell_CreateRunspace(context uintptr, command uintptr, holder uintptr) (status nativePowerShell_RunspaceHandle) = psh_host.NativePowerShell_CreateRunspace +//sys nativePowerShell_CreateRemoteRunspace(context uintptr, holder uintptr, computerName *uint16, username *uint16, password *uint16) (status nativePowerShell_RunspaceHandle) = psh_host.NativePowerShell_CreateRemoteRunspace + +//sys nativePowerShell_DeleteRunspace(handle nativePowerShell_RunspaceHandle) = psh_host.NativePowerShell_DeleteRunspace + +//sys nativePowerShell_AddCommand(handle nativePowerShell_PowerShellHandle, command *uint16) (status uint) = psh_host.NativePowerShell_AddCommand +//sys nativePowerShell_AddCommandSpecifyScope( handle nativePowerShell_PowerShellHandle, command *uint16, useLocalScope byte) (status uint) = psh_host.NativePowerShell_AddCommandSpecifyScope +//sys nativePowerShell_AddParameterString( handle nativePowerShell_PowerShellHandle, name *uint16, value *uint16) (status uint) = psh_host.NativePowerShell_AddParameterString +//sys nativePowerShell_AddParameterObject( handle nativePowerShell_PowerShellHandle, name *uint16, object nativePowerShell_PowerShellObject) (status uint) = psh_host.NativePowerShell_AddParameterObject +//sys nativePowerShell_AddArgument( handle nativePowerShell_PowerShellHandle, argument *uint16) (status uint) = psh_host.NativePowerShell_AddArgument +//sys nativePowerShell_AddPSObjectArgument( handle nativePowerShell_PowerShellHandle, object nativePowerShell_PowerShellObject) (status uint) = psh_host.NativePowerShell_AddPSObjectArgument +//sys nativePowerShell_AddPSObjectArguments( handle nativePowerShell_PowerShellHandle, objects *nativePowerShell_PowerShellObject, count uint) (status uint) = psh_host.NativePowerShell_AddPSObjectArguments + +// caller is responsible for calling ClosePowerShellObject on all returned objects, as well as +// calling the appropriate free routine on objects assuming it is not nullptr + +// to fix objects was really of type nativePowerShell_PowerShellObject ** + +//sys nativePowerShell_InvokeCommand(handle nativePowerShell_PowerShellHandle, objects *uintptr, objectCount *uint) (status nativePowerShell_PowerShellObject) = psh_host.NativePowerShell_InvokeCommand +//sys nativePowerShell_AddScript(handle nativePowerShell_PowerShellHandle , path *uint16) (status int) = psh_host.NativePowerShell_AddScript +//sys nativePowerShell_AddScriptSpecifyScope(handle nativePowerShell_PowerShellHandle, path *uint16, useLocalScope byte) (status int)= psh_host.NativePowerShell_AddScriptSpecifyScope +//sys nativePowerShell_ClosePowerShellObject(psobject nativePowerShell_PowerShellObject) = psh_host.NativePowerShell_ClosePowerShellObject + +// to fix status is really nativePowerShell_StringPtr +//sys nativePowerShell_GetPSObjectType(handle nativePowerShell_PowerShellObject) (status uintptr)= psh_host.NativePowerShell_GetPSObjectType + +// to fix status is really nativePowerShell_StringPtr +//sys nativePowerShell_GetPSObjectToString(handle nativePowerShell_PowerShellObject) (status uintptr)= psh_host.NativePowerShell_GetPSObjectToString +//sys nativePowerShell_IsPSObjectNullptr(handle nativePowerShell_PowerShellObject) (status byte) = psh_host.NativePowerShell_IsPSObjectNullptr +//sys nativePowerShell_AddPSObjectHandle(handle nativePowerShell_PowerShellObject) (status nativePowerShell_PowerShellObject)= psh_host.NativePowerShell_AddPSObjectHandle +//sys nativePowerShell_DefaultAlloc(size uint64) (status uintptr) = psh_host.NativePowerShell_DefaultAlloc +//sys nativePowerShell_DefaultFree(address uintptr) = psh_host.NativePowerShell_DefaultFree + +//sys memcpy(dest uintptr, src uintptr, size uint64) (ptr uintptr) = ntdll.memcpy diff --git a/pkg/powershell/readme.md b/pkg/powershell/readme.md new file mode 100644 index 0000000..14f0dea --- /dev/null +++ b/pkg/powershell/readme.md @@ -0,0 +1,6 @@ +#generate + +to generate zpsh_host.go +`go generate` + +You will have to change `modpsh_host = windows.NewLazySystemDLL("psh_host.dll")` to `modpsh_host = windows.NewLazyDLL("psh_host.dll")` diff --git a/pkg/powershell/runspace.go b/pkg/powershell/runspace.go index 70207c7..8815694 100644 --- a/pkg/powershell/runspace.go +++ b/pkg/powershell/runspace.go @@ -1,34 +1,17 @@ package powershell -/* - -#cgo CFLAGS: -I. -#cgo LDFLAGS: -static ${SRCDIR}/../../bin/psh_host.dll - - -#include -#include "powershell.h" - -*/ -import "C" import ( - "unsafe" - - "golang.org/x/sys/windows" "github.com/KnicKnic/go-powershell/pkg/logger" + "golang.org/x/sys/windows" ) -func init() { - C.InitLibraryHelper() -} - type runspaceContext struct { log logger.Full callback CallbackHolder invoking []psCommand // in order list of psCommands we are currently invoking // runspaceContext should contain all the datamembers to reconstrut runspace - handle C.NativePowerShell_RunspaceHandle + handle nativePowerShell_RunspaceHandle contextLookup uint64 } @@ -69,19 +52,18 @@ func CreateRunspace(loggerCallback logger.Simple, callback CallbackHolder) Runsp } context.contextLookup = storeRunspaceContext(context) - var useLogger C.char = 1 + var useLogger byte = 1 if loggerCallback == nil { useLogger = 0 } - var useCommand C.char = 1 + var useCommand byte = 1 if callback == nil { useCommand = 0 } - context.handle = C.CreateRunspaceHelper(C.ulonglong(context.contextLookup), useLogger, useCommand) + context.handle = createRunspaceHelper(context.contextLookup, useLogger, useCommand) return context.recreateRunspace() } - // CreateRemoteRunspace creates a runspace in which to run powershell commands // // This function allows you to specify a logging callback @@ -97,27 +79,23 @@ func CreateRemoteRunspace(loggerCallback logger.Simple, remoteMachine string, us } context.contextLookup = storeRunspaceContext(context) - var useLogger C.char = 1 + var useLogger byte = 1 if loggerCallback == nil { useLogger = 0 } - cRemoteMachine, _ := windows.UTF16PtrFromString(remoteMachine) - ptrRemoteMachine := unsafe.Pointer(cRemoteMachine) cUsername, _ := windows.UTF16PtrFromString(username) - ptrUsername := unsafe.Pointer(cUsername) cPassword, _ := windows.UTF16PtrFromString(password) - ptrPassword := unsafe.Pointer(cPassword) - context.handle = C.CreateRemoteRunspaceHelper(C.ulonglong(context.contextLookup), useLogger, (*C.wchar_t)(ptrRemoteMachine), (*C.wchar_t)(ptrUsername), (*C.wchar_t)(ptrPassword)) + context.handle = createRemoteRunspaceHelper(context.contextLookup, useLogger, cRemoteMachine, cUsername, cPassword) return context.recreateRunspace() } // Close and free a Runspace func (runspace Runspace) Close() { deleteRunspaceContextLookup(runspace.contextLookup) - C.NativePowerShell_DeleteRunspace(runspace.handle) + nativePowerShell_DeleteRunspace(runspace.handle) } diff --git a/pkg/powershell/runspacehelpers.go b/pkg/powershell/runspacehelpers.go new file mode 100644 index 0000000..6dec93d --- /dev/null +++ b/pkg/powershell/runspacehelpers.go @@ -0,0 +1,158 @@ +package powershell + +import ( + "syscall" + "unsafe" +) + +func loggerCallback(context uint64, str uintptr) uintptr { + if context != 0 { + s := uintptrMakeString(str) + contextInterface := getRunspaceContext(context) + contextInterface.log.Write(s) + } + return uintptr(0) +} +func loggerCallbackln(context uint64, str uintptr) uintptr { + if context != 0 { + s := uintptrMakeString(str) + contextInterface := getRunspaceContext(context) + contextInterface.log.Writeln(s) + } + return uintptr(0) +} +func loggerCallbackDebug(context uint64, str uintptr) uintptr { + if context != 0 { + s := uintptrMakeString(str) + contextInterface := getRunspaceContext(context) + contextInterface.log.Debug(s) + } + return uintptr(0) +} +func loggerCallbackDebugln(context uint64, str uintptr) uintptr { + if context != 0 { + s := uintptrMakeString(str) + contextInterface := getRunspaceContext(context) + contextInterface.log.Debugln(s) + } + return uintptr(0) +} +func loggerCallbackVerbose(context uint64, str uintptr) uintptr { + if context != 0 { + s := uintptrMakeString(str) + contextInterface := getRunspaceContext(context) + contextInterface.log.Verbose(s) + } + return uintptr(0) +} +func loggerCallbackVerboseln(context uint64, str uintptr) uintptr { + if context != 0 { + s := uintptrMakeString(str) + contextInterface := getRunspaceContext(context) + contextInterface.log.Verboseln(s) + } + return uintptr(0) +} +func loggerCallbackInformation(context uint64, str uintptr) uintptr { + if context != 0 { + s := uintptrMakeString(str) + contextInterface := getRunspaceContext(context) + contextInterface.log.Information(s) + } + return uintptr(0) +} +func loggerCallbackInformationln(context uint64, str uintptr) uintptr { + if context != 0 { + s := uintptrMakeString(str) + contextInterface := getRunspaceContext(context) + contextInterface.log.Informationln(s) + } + return uintptr(0) +} +func loggerCallbackWarning(context uint64, str uintptr) uintptr { + if context != 0 { + s := uintptrMakeString(str) + contextInterface := getRunspaceContext(context) + contextInterface.log.Warning(s) + } + return uintptr(0) +} +func loggerCallbackWarningln(context uint64, str uintptr) uintptr { + if context != 0 { + s := uintptrMakeString(str) + contextInterface := getRunspaceContext(context) + contextInterface.log.Warningln(s) + } + return uintptr(0) +} +func loggerCallbackError(context uint64, str uintptr) uintptr { + if context != 0 { + s := uintptrMakeString(str) + contextInterface := getRunspaceContext(context) + contextInterface.log.Error(s) + } + return uintptr(0) +} +func loggerCallbackErrorln(context uint64, str uintptr) uintptr { + if context != 0 { + s := uintptrMakeString(str) + contextInterface := getRunspaceContext(context) + contextInterface.log.Errorln(s) + } + return uintptr(0) +} + +func commandCallback(context uint64, cMessage uintptr, input uintptr, inputCount uint64, ret uintptr) uintptr { + + var resultsWriter callbackResultsWriter + if context != 0 { + contextInterface := getRunspaceContext(context) + inputArr := make([]Object, inputCount) + for i := uint32(0); uint64(i) < inputCount; i++ { + inputArr[i] = makePowerShellObjectIndexed(input, i) + } + message := uintptrMakeString(cMessage) + contextInterface.callback.Callback(contextInterface.recreateRunspace(), message, inputArr, &resultsWriter) + } + resultsWriter.filloutResults(ret) + return uintptr(0) +} + +var ( + loggerCallbackHolder nativePowerShell_LogString_Holder = nativePowerShell_LogString_Holder{ + Log: syscall.NewCallbackCDecl(loggerCallback), + LogError: syscall.NewCallbackCDecl(loggerCallbackError), + LogWarning: syscall.NewCallbackCDecl(loggerCallbackWarning), + LogInformation: syscall.NewCallbackCDecl(loggerCallbackInformation), + LogVerbose: syscall.NewCallbackCDecl(loggerCallbackVerbose), + LogDebug: syscall.NewCallbackCDecl(loggerCallbackDebug), + LogLine: syscall.NewCallbackCDecl(loggerCallbackln), + LogErrorLine: syscall.NewCallbackCDecl(loggerCallbackErrorln), + LogWarningLine: syscall.NewCallbackCDecl(loggerCallbackWarningln), + LogInformationLine: syscall.NewCallbackCDecl(loggerCallbackInformationln), + LogVerboseLine: syscall.NewCallbackCDecl(loggerCallbackVerboseln), + LogDebugLine: syscall.NewCallbackCDecl(loggerCallbackDebugln), + } + loggerCallbackPointer unsafe.Pointer = unsafe.Pointer(&loggerCallbackHolder) + commandCallbackPointer uintptr = syscall.NewCallbackCDecl(commandCallback) +) + +func createRunspaceHelper(context uint64, useLogger byte, useCommand byte) nativePowerShell_RunspaceHandle { + var commandPtr uintptr = 0 + var loggerPtr uintptr = 0 + if useLogger != 0 { + loggerPtr = uintptr(loggerCallbackPointer) + } + if useCommand != 0 { + commandPtr = commandCallbackPointer + } + return nativePowerShell_CreateRunspace(makeUintptrFromUint64(context), commandPtr, loggerPtr) +} + +func createRemoteRunspaceHelper(context uint64, useLogger byte, remoteMachine *uint16, userName *uint16, password *uint16) nativePowerShell_RunspaceHandle { + var loggerPtr uintptr = 0 + if useLogger != 0 { + loggerPtr = uintptr(loggerCallbackPointer) + } + return nativePowerShell_CreateRemoteRunspace(makeUintptrFromUint64(context), loggerPtr, remoteMachine, userName, password) +} diff --git a/pkg/powershell/zpsh_host.go b/pkg/powershell/zpsh_host.go new file mode 100644 index 0000000..a355078 --- /dev/null +++ b/pkg/powershell/zpsh_host.go @@ -0,0 +1,207 @@ +// Code generated by 'go generate'; DO NOT EDIT. + +package powershell + +import ( + "syscall" + "unsafe" + + "golang.org/x/sys/windows" +) + +var _ unsafe.Pointer + +// Do the interface allocations only once for common +// Errno values. +const ( + errnoERROR_IO_PENDING = 997 +) + +var ( + errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) +) + +// errnoErr returns common boxed Errno values, to prevent +// allocations at runtime. +func errnoErr(e syscall.Errno) error { + switch e { + case 0: + return nil + case errnoERROR_IO_PENDING: + return errERROR_IO_PENDING + } + // TODO: add more here, after collecting data on the common + // error values see on Windows. (perhaps when running + // all.bat?) + return e +} + +var ( + modpsh_host = windows.NewLazyDLL("psh_host.dll") + modntdll = windows.NewLazySystemDLL("ntdll.dll") + + procnativePowerShell_CreatePowerShell = modpsh_host.NewProc("NativePowerShell_CreatePowerShell") + procnativePowerShell_CreatePowerShellNested = modpsh_host.NewProc("NativePowerShell_CreatePowerShellNested") + procnativePowerShell_DeletePowershell = modpsh_host.NewProc("NativePowerShell_DeletePowershell") + procnativePowerShell_CreateRunspace = modpsh_host.NewProc("NativePowerShell_CreateRunspace") + procnativePowerShell_CreateRemoteRunspace = modpsh_host.NewProc("NativePowerShell_CreateRemoteRunspace") + procnativePowerShell_DeleteRunspace = modpsh_host.NewProc("NativePowerShell_DeleteRunspace") + procnativePowerShell_AddCommand = modpsh_host.NewProc("NativePowerShell_AddCommand") + procnativePowerShell_AddCommandSpecifyScope = modpsh_host.NewProc("NativePowerShell_AddCommandSpecifyScope") + procnativePowerShell_AddParameterString = modpsh_host.NewProc("NativePowerShell_AddParameterString") + procnativePowerShell_AddParameterObject = modpsh_host.NewProc("NativePowerShell_AddParameterObject") + procnativePowerShell_AddArgument = modpsh_host.NewProc("NativePowerShell_AddArgument") + procnativePowerShell_AddPSObjectArgument = modpsh_host.NewProc("NativePowerShell_AddPSObjectArgument") + procnativePowerShell_AddPSObjectArguments = modpsh_host.NewProc("NativePowerShell_AddPSObjectArguments") + procnativePowerShell_InvokeCommand = modpsh_host.NewProc("NativePowerShell_InvokeCommand") + procnativePowerShell_AddScript = modpsh_host.NewProc("NativePowerShell_AddScript") + procnativePowerShell_AddScriptSpecifyScope = modpsh_host.NewProc("NativePowerShell_AddScriptSpecifyScope") + procnativePowerShell_ClosePowerShellObject = modpsh_host.NewProc("NativePowerShell_ClosePowerShellObject") + procnativePowerShell_GetPSObjectType = modpsh_host.NewProc("NativePowerShell_GetPSObjectType") + procnativePowerShell_GetPSObjectToString = modpsh_host.NewProc("NativePowerShell_GetPSObjectToString") + procnativePowerShell_IsPSObjectNullptr = modpsh_host.NewProc("NativePowerShell_IsPSObjectNullptr") + procnativePowerShell_AddPSObjectHandle = modpsh_host.NewProc("NativePowerShell_AddPSObjectHandle") + procnativePowerShell_DefaultAlloc = modpsh_host.NewProc("NativePowerShell_DefaultAlloc") + procnativePowerShell_DefaultFree = modpsh_host.NewProc("NativePowerShell_DefaultFree") + procmemcpy = modntdll.NewProc("memcpy") +) + +func nativePowerShell_CreatePowerShell(handle nativePowerShell_RunspaceHandle) (status nativePowerShell_PowerShellHandle) { + r0, _, _ := syscall.Syscall(procnativePowerShell_CreatePowerShell.Addr(), 1, uintptr(handle), 0, 0) + status = nativePowerShell_PowerShellHandle(r0) + return +} + +func nativePowerShell_CreatePowerShellNested(handle nativePowerShell_PowerShellHandle) (status nativePowerShell_PowerShellHandle) { + r0, _, _ := syscall.Syscall(procnativePowerShell_CreatePowerShellNested.Addr(), 1, uintptr(handle), 0, 0) + status = nativePowerShell_PowerShellHandle(r0) + return +} + +func nativePowerShell_DeletePowershell(handle nativePowerShell_PowerShellHandle) { + syscall.Syscall(procnativePowerShell_DeletePowershell.Addr(), 1, uintptr(handle), 0, 0) + return +} + +func nativePowerShell_CreateRunspace(context uintptr, command uintptr, holder uintptr) (status nativePowerShell_RunspaceHandle) { + r0, _, _ := syscall.Syscall(procnativePowerShell_CreateRunspace.Addr(), 3, uintptr(context), uintptr(command), uintptr(holder)) + status = nativePowerShell_RunspaceHandle(r0) + return +} + +func nativePowerShell_CreateRemoteRunspace(context uintptr, holder uintptr, computerName *uint16, username *uint16, password *uint16) (status nativePowerShell_RunspaceHandle) { + r0, _, _ := syscall.Syscall6(procnativePowerShell_CreateRemoteRunspace.Addr(), 5, uintptr(context), uintptr(holder), uintptr(unsafe.Pointer(computerName)), uintptr(unsafe.Pointer(username)), uintptr(unsafe.Pointer(password)), 0) + status = nativePowerShell_RunspaceHandle(r0) + return +} + +func nativePowerShell_DeleteRunspace(handle nativePowerShell_RunspaceHandle) { + syscall.Syscall(procnativePowerShell_DeleteRunspace.Addr(), 1, uintptr(handle), 0, 0) + return +} + +func nativePowerShell_AddCommand(handle nativePowerShell_PowerShellHandle, command *uint16) (status uint) { + r0, _, _ := syscall.Syscall(procnativePowerShell_AddCommand.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(command)), 0) + status = uint(r0) + return +} + +func nativePowerShell_AddCommandSpecifyScope(handle nativePowerShell_PowerShellHandle, command *uint16, useLocalScope byte) (status uint) { + r0, _, _ := syscall.Syscall(procnativePowerShell_AddCommandSpecifyScope.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(command)), uintptr(useLocalScope)) + status = uint(r0) + return +} + +func nativePowerShell_AddParameterString(handle nativePowerShell_PowerShellHandle, name *uint16, value *uint16) (status uint) { + r0, _, _ := syscall.Syscall(procnativePowerShell_AddParameterString.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value))) + status = uint(r0) + return +} + +func nativePowerShell_AddParameterObject(handle nativePowerShell_PowerShellHandle, name *uint16, object nativePowerShell_PowerShellObject) (status uint) { + r0, _, _ := syscall.Syscall(procnativePowerShell_AddParameterObject.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(name)), uintptr(object)) + status = uint(r0) + return +} + +func nativePowerShell_AddArgument(handle nativePowerShell_PowerShellHandle, argument *uint16) (status uint) { + r0, _, _ := syscall.Syscall(procnativePowerShell_AddArgument.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(argument)), 0) + status = uint(r0) + return +} + +func nativePowerShell_AddPSObjectArgument(handle nativePowerShell_PowerShellHandle, object nativePowerShell_PowerShellObject) (status uint) { + r0, _, _ := syscall.Syscall(procnativePowerShell_AddPSObjectArgument.Addr(), 2, uintptr(handle), uintptr(object), 0) + status = uint(r0) + return +} + +func nativePowerShell_AddPSObjectArguments(handle nativePowerShell_PowerShellHandle, objects *nativePowerShell_PowerShellObject, count uint) (status uint) { + r0, _, _ := syscall.Syscall(procnativePowerShell_AddPSObjectArguments.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(objects)), uintptr(count)) + status = uint(r0) + return +} + +func nativePowerShell_InvokeCommand(handle nativePowerShell_PowerShellHandle, objects *uintptr, objectCount *uint) (status nativePowerShell_PowerShellObject) { + r0, _, _ := syscall.Syscall(procnativePowerShell_InvokeCommand.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(objects)), uintptr(unsafe.Pointer(objectCount))) + status = nativePowerShell_PowerShellObject(r0) + return +} + +func nativePowerShell_AddScript(handle nativePowerShell_PowerShellHandle, path *uint16) (status int) { + r0, _, _ := syscall.Syscall(procnativePowerShell_AddScript.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(path)), 0) + status = int(r0) + return +} + +func nativePowerShell_AddScriptSpecifyScope(handle nativePowerShell_PowerShellHandle, path *uint16, useLocalScope byte) (status int) { + r0, _, _ := syscall.Syscall(procnativePowerShell_AddScriptSpecifyScope.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(path)), uintptr(useLocalScope)) + status = int(r0) + return +} + +func nativePowerShell_ClosePowerShellObject(psobject nativePowerShell_PowerShellObject) { + syscall.Syscall(procnativePowerShell_ClosePowerShellObject.Addr(), 1, uintptr(psobject), 0, 0) + return +} + +func nativePowerShell_GetPSObjectType(handle nativePowerShell_PowerShellObject) (status uintptr) { + r0, _, _ := syscall.Syscall(procnativePowerShell_GetPSObjectType.Addr(), 1, uintptr(handle), 0, 0) + status = uintptr(r0) + return +} + +func nativePowerShell_GetPSObjectToString(handle nativePowerShell_PowerShellObject) (status uintptr) { + r0, _, _ := syscall.Syscall(procnativePowerShell_GetPSObjectToString.Addr(), 1, uintptr(handle), 0, 0) + status = uintptr(r0) + return +} + +func nativePowerShell_IsPSObjectNullptr(handle nativePowerShell_PowerShellObject) (status byte) { + r0, _, _ := syscall.Syscall(procnativePowerShell_IsPSObjectNullptr.Addr(), 1, uintptr(handle), 0, 0) + status = byte(r0) + return +} + +func nativePowerShell_AddPSObjectHandle(handle nativePowerShell_PowerShellObject) (status nativePowerShell_PowerShellObject) { + r0, _, _ := syscall.Syscall(procnativePowerShell_AddPSObjectHandle.Addr(), 1, uintptr(handle), 0, 0) + status = nativePowerShell_PowerShellObject(r0) + return +} + +func nativePowerShell_DefaultAlloc(size uint64) (status uintptr) { + r0, _, _ := syscall.Syscall(procnativePowerShell_DefaultAlloc.Addr(), 1, uintptr(size), 0, 0) + status = uintptr(r0) + return +} + +func nativePowerShell_DefaultFree(address uintptr) { + syscall.Syscall(procnativePowerShell_DefaultFree.Addr(), 1, uintptr(address), 0, 0) + return +} + +func memcpy(dest uintptr, src uintptr, size uint64) (ptr uintptr) { + r0, _, _ := syscall.Syscall(procmemcpy.Addr(), 3, uintptr(dest), uintptr(src), uintptr(size)) + ptr = uintptr(r0) + return +} diff --git a/readme.md b/readme.md index d21c0d5..6def0b6 100644 --- a/readme.md +++ b/readme.md @@ -1,6 +1,6 @@ [![Build Status](https://dev.azure.com/oneeyedelf1/powershell.native/_apis/build/status/KnicKnic.go-powershell?branchName=master)](https://dev.azure.com/oneeyedelf1/powershell.native/_build/latest?definitionId=3&branchName=master) [![Go Report Card](https://goreportcard.com/badge/github.com/KnicKnic/go-powershell)](https://goreportcard.com/report/github.com/KnicKnic/go-powershell) -[![gopherbadger](https://img.shields.io/badge/Go%20Coverage-100%25-brightgreen.svg?longCache=true&style=flat)](./scripts/code_coverage.ps1) +[![gopherbadger](https://img.shields.io/badge/Go%20Coverage-80%25-brightgreen.svg?longCache=true&style=flat)](./scripts/code_coverage.ps1) [![GoDoc](https://godoc.org/github.com/KnicKnic/go-powershell/pkg/powershell?status.svg)](https://godoc.org/github.com/KnicKnic/go-powershell/pkg/powershell) [![GitHub commits since latest release (branch)](https://img.shields.io/github/commits-since/KnicKnic/go-powershell/latest.svg)](https://github.com/KnicKnic/go-powershell/releases/latest) @@ -13,6 +13,7 @@ Features: 1. Call from golang to powershell 1. Call from powershell to golang (via special Send-HostCommand commandlet) 1. Easy logging - Trap host output in powershell and call custom logging routines in golang +1. Uses syscall - so do not need to use cGo # Status @@ -88,18 +89,11 @@ This project has a dependency on [native-powershell](https://github.com/KnicKnic 1. Simply fetch the dependencies, `go get -d .` and then make sure to build, `go build` 1. Copy the precompiled psh_host.dll into your location so it can be found when running the app - 1. cmd - `copy %GOPATH%\src\github.com\KnicKnic\go-powershell\native-powershell\native-powershell-bin\psh_host.dll .` - 1. powershell - `copy "$($env:GOPATH)\src\github.com\KnicKnic\go-powershell\native-powershell\native-powershell-bin\psh_host.dll" .` + 1. cmd - `copy %GOPATH%\src\github.com\KnicKnic\go-powershell\bin\psh_host.dll .` + 1. powershell - `copy "$($env:GOPATH)\src\github.com\KnicKnic\go-powershell\bin\psh_host.dll" .` 1. I ended up checking in the psh_host.dll and host.h (to make things easy) 1. I could not find a better way to go about this and still have things be easy. -### Getting cgo (so you can compile) - -Windows - install dependencies - you need gcc. I Use chocolatey to install (easiest way to install gcc) - -1. Install chocolatey - 1. https://chocolatey.org/docs/installation#installing-chocolatey -1. `choco install mingw -y` # Docs