diff --git a/pkg/powershell/chelpers.go b/pkg/powershell/chelpers.go index 4bba2cf..f984c17 100644 --- a/pkg/powershell/chelpers.go +++ b/pkg/powershell/chelpers.go @@ -14,15 +14,20 @@ func makeUintptrFromUint64(v uint64) uintptr { func allocWrapper(size uint64) (uintptr, error) { return nativePowerShell_DefaultAlloc(size) } + +func localAllocWrapper(size uint64) (uintptr, error) { + return localAlloc(size) +} + func freeWrapper(v uintptr) { nativePowerShell_DefaultFree(v) } -func mallocCopyLogStringHolder(input nativePowerShell_LogString_Holder) uintptr { +func localMallocCopyLogStringHolder(input nativePowerShell_LogString_Holder) uintptr { size := uint64(unsafe.Sizeof(input)) - data, err := allocWrapper(size) + data, err := localAllocWrapper(size) if err != nil { panic("Couldn't allocate memory") } @@ -32,16 +37,21 @@ func mallocCopyLogStringHolder(input nativePowerShell_LogString_Holder) uintptr return data } -func mallocCopyGenericPowerShellObject(input *nativePowerShell_GenericPowerShellObject, inputCount uint64) uintptr { +func mallocCopyArrayGenericPowerShellObject(input []nativePowerShell_GenericPowerShellObject) uintptr { + + inputCount := uint64(len(input)) - size := inputCount * uint64(unsafe.Sizeof(*input)) + var size uint64 + if inputCount != 0 { + size = inputCount * uint64(unsafe.Sizeof(input[0])) + } data, err := allocWrapper(size) if err != nil { panic("Couldn't allocate memory") } - _ = memcpyGenericPowerShellObject(data, input, size) + _ = memcpyGenericPowerShellObject(data, &input[0], size) return data } @@ -63,7 +73,7 @@ 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))))) + charCode = castToUint16(str + (makeUintptrFromUint64(i) * unsafe.Sizeof(charCode))) } return i } diff --git a/pkg/powershell/hostcommand.go b/pkg/powershell/hostcommand.go index b37d45d..15e329e 100644 --- a/pkg/powershell/hostcommand.go +++ b/pkg/powershell/hostcommand.go @@ -61,7 +61,7 @@ func (writer *callbackResultsWriter) filloutResults(res uintptr) { if writer.objects != nil && len(writer.objects) > 0 { results.count = uint32(len(writer.objects)) - results.objects = mallocCopyGenericPowerShellObject(&writer.objects[0], uint64(len(writer.objects))) + results.objects = mallocCopyArrayGenericPowerShellObject(writer.objects) } _ = memcpyJsonReturnValues(res, results) } diff --git a/pkg/powershell/powershell.go b/pkg/powershell/powershell.go index 12fac7a..f1e870a 100644 --- a/pkg/powershell/powershell.go +++ b/pkg/powershell/powershell.go @@ -115,11 +115,10 @@ func (command psCommand) Invoke() *InvokeResults { } 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 offset := (uintptr(index) * unsafe.Sizeof(handle)) - handle = *(*nativePowerShell_PowerShellObject)(unsafe.Pointer(objects + offset)) + handle = castToPowershellObject(objects + offset) return makePowerShellObject(handle) } diff --git a/pkg/powershell/runspacehelpers.go b/pkg/powershell/runspacehelpers.go index fa933c1..46b787b 100644 --- a/pkg/powershell/runspacehelpers.go +++ b/pkg/powershell/runspacehelpers.go @@ -136,7 +136,7 @@ var ( // intentionally leak loggerCallbackPointer (once per process) // doing this so the callback object will be around for lifetime of process // If it was golang object just marshalled for duration of call, golang garbage collection could move things and we would crash - loggerCallbackPointer uintptr = mallocCopyLogStringHolder(loggerCallbackHolder) + loggerCallbackPointer uintptr = localMallocCopyLogStringHolder(loggerCallbackHolder) commandCallbackPointer uintptr = syscall.NewCallbackCDecl(commandCallback) ) diff --git a/pkg/powershell/zpsh_host.go b/pkg/powershell/zpsh_host.go index 0adb7a5..9742782 100644 --- a/pkg/powershell/zpsh_host.go +++ b/pkg/powershell/zpsh_host.go @@ -39,7 +39,10 @@ func errnoErr(e syscall.Errno) error { var ( modpsh_host = windows.NewLazyDLL("psh_host.dll") modntdll = windows.NewLazySystemDLL("ntdll.dll") + modkernel32 = windows.NewLazySystemDLL("kernel32.dll") + procLocalAlloc = modkernel32.NewProc("LocalAlloc") + procLocalFree = modkernel32.NewProc("LocalFree") procnativePowerShell_CreatePowerShell = modpsh_host.NewProc("NativePowerShell_CreatePowerShell") procnativePowerShell_CreatePowerShellNested = modpsh_host.NewProc("NativePowerShell_CreatePowerShellNested") procnativePowerShell_DeletePowershell = modpsh_host.NewProc("NativePowerShell_DeletePowershell") @@ -197,6 +200,14 @@ func nativePowerShell_DefaultAlloc(size uint64) (status uintptr, err error) { } return } +func localAlloc(size uint64) (status uintptr, err error) { + r0, _, err := syscall.Syscall(procLocalAlloc.Addr(), 1, uintptr(size), 0, 0) + status = uintptr(r0) + if status != uintptr(0) { + err = nil + } + return +} func nativePowerShell_DefaultFree(address uintptr) { syscall.Syscall(procnativePowerShell_DefaultFree.Addr(), 1, uintptr(address), 0, 0) @@ -221,6 +232,16 @@ func memcpyJsonReturnValues(dest uintptr, src nativePowerShell_JsonReturnValues) ptr = uintptr(r0) return } +func castToPowershellObject(src uintptr) nativePowerShell_PowerShellObject { + var output nativePowerShell_PowerShellObject + _, _, _ = syscall.Syscall(procmemcpy.Addr(), 3, uintptr(unsafe.Pointer(&output)), src, uintptr(unsafe.Sizeof(output))) + return output +} +func castToUint16(src uintptr) uint16 { + var output uint16 + _, _, _ = syscall.Syscall(procmemcpy.Addr(), 3, uintptr(unsafe.Pointer(&output)), src, uintptr(unsafe.Sizeof(output))) + return output +} func memcpyGenericPowerShellObject(dest uintptr, src *nativePowerShell_GenericPowerShellObject, size uint64) (ptr uintptr) {