From 9af5e654239ed87f1ec56524083733f333cde2f4 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Mon, 5 Aug 2019 15:15:15 +0200 Subject: Fully cooked peb test --- elevate/shellexecute.go | 27 ++++++++++++++++++++------- elevate/syscall_windows.go | 23 +++++++++++++++++------ elevate/zsyscall_windows.go | 14 -------------- 3 files changed, 37 insertions(+), 27 deletions(-) diff --git a/elevate/shellexecute.go b/elevate/shellexecute.go index d784a2ed..4c213216 100644 --- a/elevate/shellexecute.go +++ b/elevate/shellexecute.go @@ -25,10 +25,6 @@ const ( /* We could use the undocumented LdrFindEntryForAddress function instead, but that's undocumented, and we're trying * to be as rock-solid as possible here. */ func findCurrentDataTableEntry() (entry *cLDR_DATA_TABLE_ENTRY, err error) { - ourBase, err := getModuleHandle(nil) /* This is the same as peb->ImageBaseAddress, but that member is undocumented. */ - if err != nil { - return - } peb := rtlGetCurrentPeb() if peb == nil || peb.Ldr == nil { err = windows.ERROR_INVALID_ADDRESS @@ -36,7 +32,7 @@ func findCurrentDataTableEntry() (entry *cLDR_DATA_TABLE_ENTRY, err error) { } for cur := peb.Ldr.InMemoryOrderModuleList.Flink; cur != &peb.Ldr.InMemoryOrderModuleList; cur = cur.Flink { entry = (*cLDR_DATA_TABLE_ENTRY)(unsafe.Pointer(uintptr(unsafe.Pointer(cur)) - unsafe.Offsetof(cLDR_DATA_TABLE_ENTRY{}.InMemoryOrderLinks))) - if entry.DllBase == ourBase { + if entry.DllBase == peb.ImageBaseAddress { return } } @@ -91,20 +87,37 @@ func ShellExecute(program string, arguments string, directory string, show int32 return } } + dataTableEntry, err := findCurrentDataTableEntry() if err != nil { return } + processParameters := rtlGetCurrentPeb().ProcessParameters + fullDllName := dataTableEntry.FullDllName.Buffer + baseDllName := dataTableEntry.BaseDllName.Buffer + imagePathName := processParameters.ImagePathName.Buffer + dllPath := processParameters.DllPath.Buffer + commandLine := processParameters.CommandLine.Buffer + var windowsDirectory [windows.MAX_PATH]uint16 if _, err = getWindowsDirectory(&windowsDirectory[0], windows.MAX_PATH); err != nil { return } - originalPath := dataTableEntry.FullDllName.Buffer explorerPath := windows.StringToUTF16Ptr(filepath.Join(windows.UTF16ToString(windowsDirectory[:]), "explorer.exe")) + explorerName := windows.StringToUTF16Ptr("explorer.exe") rtlInitUnicodeString(&dataTableEntry.FullDllName, explorerPath) + rtlInitUnicodeString(&processParameters.ImagePathName, explorerPath) + rtlInitUnicodeString(&processParameters.DllPath, explorerPath) + rtlInitUnicodeString(&dataTableEntry.BaseDllName, explorerName) + rtlInitUnicodeString(&processParameters.CommandLine, explorerName) defer func() { - rtlInitUnicodeString(&dataTableEntry.FullDllName, originalPath) + rtlInitUnicodeString(&processParameters.CommandLine, commandLine) + rtlInitUnicodeString(&dataTableEntry.BaseDllName, baseDllName) + rtlInitUnicodeString(&processParameters.DllPath, dllPath) + rtlInitUnicodeString(&processParameters.ImagePathName, imagePathName) + rtlInitUnicodeString(&dataTableEntry.FullDllName, fullDllName) runtime.KeepAlive(explorerPath) + runtime.KeepAlive(explorerName) }() if err = coInitializeEx(0, cCOINIT_APARTMENTTHREADED); err == nil { diff --git a/elevate/syscall_windows.go b/elevate/syscall_windows.go index c7def8fa..3da3bca9 100644 --- a/elevate/syscall_windows.go +++ b/elevate/syscall_windows.go @@ -32,11 +32,13 @@ type cLIST_ENTRY struct { * engineered, but the below shows only the documented and therefore stable fields from Microsoft's winternl.h header */ type cLDR_DATA_TABLE_ENTRY struct { - Reserved1 [2]uintptr + InLoadOrderLinks cLIST_ENTRY InMemoryOrderLinks cLIST_ENTRY - Reserved2 [2]uintptr + InInitializationOrderLinks cLIST_ENTRY DllBase uintptr - Reserved3 [2]uintptr + EntryPoint uintptr + SizeOfImage uint32 + BaseDllName cUNICODE_STRING FullDllName cUNICODE_STRING Reserved4 [8]byte Reserved5 [3]uintptr @@ -50,13 +52,23 @@ type cPEB_LDR_DATA struct { InMemoryOrderModuleList cLIST_ENTRY } +type cRTL_USER_PROCESS_PARAMETERS struct { + Reserved1 [16]byte + Reserved2 [8]uintptr + DllPath cUNICODE_STRING + ImagePathName cUNICODE_STRING + CommandLine cUNICODE_STRING + +} + type cPEB struct { Reserved1 [2]byte BeingDebugged byte Reserved2 [1]byte - Reserved3 [2]uintptr + Reserved3 [1]uintptr + ImageBaseAddress uintptr Ldr *cPEB_LDR_DATA - ProcessParameters uintptr + ProcessParameters *cRTL_USER_PROCESS_PARAMETERS Reserved4 [3]uintptr AtlThunkSListPtr uintptr Reserved5 uintptr @@ -77,7 +89,6 @@ const ( cCOINIT_APARTMENTTHREADED = 2 ) -//sys getModuleHandle(moduleName *uint16) (moduleHandle uintptr, err error) [failretval==0] = kernel32.GetModuleHandleW //sys getWindowsDirectory(windowsDirectory *uint16, inLen uint32) (outLen uint32, err error) [failretval==0] = kernel32.GetWindowsDirectoryW //sys rtlInitUnicodeString(destinationString *cUNICODE_STRING, sourceString *uint16) = ntdll.RtlInitUnicodeString diff --git a/elevate/zsyscall_windows.go b/elevate/zsyscall_windows.go index a3c5400d..8f7a5a8a 100644 --- a/elevate/zsyscall_windows.go +++ b/elevate/zsyscall_windows.go @@ -41,7 +41,6 @@ var ( modntdll = windows.NewLazySystemDLL("ntdll.dll") modole32 = windows.NewLazySystemDLL("ole32.dll") - procGetModuleHandleW = modkernel32.NewProc("GetModuleHandleW") procGetWindowsDirectoryW = modkernel32.NewProc("GetWindowsDirectoryW") procRtlInitUnicodeString = modntdll.NewProc("RtlInitUnicodeString") procRtlGetCurrentPeb = modntdll.NewProc("RtlGetCurrentPeb") @@ -50,19 +49,6 @@ var ( procCoGetObject = modole32.NewProc("CoGetObject") ) -func getModuleHandle(moduleName *uint16) (moduleHandle uintptr, err error) { - r0, _, e1 := syscall.Syscall(procGetModuleHandleW.Addr(), 1, uintptr(unsafe.Pointer(moduleName)), 0, 0) - moduleHandle = uintptr(r0) - if moduleHandle == 0 { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return -} - func getWindowsDirectory(windowsDirectory *uint16, inLen uint32) (outLen uint32, err error) { r0, _, e1 := syscall.Syscall(procGetWindowsDirectoryW.Addr(), 2, uintptr(unsafe.Pointer(windowsDirectory)), uintptr(inLen), 0) outLen = uint32(r0) -- cgit v1.2.3-59-g8ed1b