diff --git a/windows/syscall_windows.go b/windows/syscall_windows.go index 968f211f..39e3b386 100644 --- a/windows/syscall_windows.go +++ b/windows/syscall_windows.go @@ -402,11 +402,12 @@ func NewCallbackCDecl(fn interface{}) uintptr { //sys rtlGetVersion(info *OsVersionInfoEx) (ntstatus error) = ntdll.RtlGetVersion //sys rtlGetNtVersionNumbers(majorVersion *uint32, minorVersion *uint32, buildNumber *uint32) = ntdll.RtlGetNtVersionNumbers //sys RtlGetCurrentPeb() (peb *PEB) = ntdll.RtlGetCurrentPeb -//sys RtlInitUnicodeString(destinationString *UNICODE_STRING, sourceString *uint16) = ntdll.RtlInitUnicodeString +//sys RtlInitUnicodeString(destinationString *NTUnicodeString, sourceString *uint16) = ntdll.RtlInitUnicodeString +//sys RtlInitString(destinationString *NTString, sourceString *byte) = ntdll.RtlInitString //sys NtCreateFile(handle *Handle, access uint32, oa *OBJECT_ATTRIBUTES, iosb *IO_STATUS_BLOCK, allocationSize *int64, attributes uint32, share uint32, disposition uint32, options uint32, eabuffer uintptr, ealength uint32) (ntstatus error) = ntdll.NtCreateFile //sys NtCreateNamedPipeFile(pipe *Handle, access uint32, oa *OBJECT_ATTRIBUTES, iosb *IO_STATUS_BLOCK, share uint32, disposition uint32, options uint32, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (ntstatus error) = ntdll.NtCreateNamedPipeFile -//sys RtlDosPathNameToNtPathName(dosName *uint16, ntName *UNICODE_STRING, ntFileNamePart *uint16, relativeName *RTL_RELATIVE_NAME) (ntstatus error) = ntdll.RtlDosPathNameToNtPathName_U_WithStatus -//sys RtlDosPathNameToRelativeNtPathName(dosName *uint16, ntName *UNICODE_STRING, ntFileNamePart *uint16, relativeName *RTL_RELATIVE_NAME) (ntstatus error) = ntdll.RtlDosPathNameToRelativeNtPathName_U_WithStatus +//sys RtlDosPathNameToNtPathName(dosName *uint16, ntName *NTUnicodeString, ntFileNamePart *uint16, relativeName *RTL_RELATIVE_NAME) (ntstatus error) = ntdll.RtlDosPathNameToNtPathName_U_WithStatus +//sys RtlDosPathNameToRelativeNtPathName(dosName *uint16, ntName *NTUnicodeString, ntFileNamePart *uint16, relativeName *RTL_RELATIVE_NAME) (ntstatus error) = ntdll.RtlDosPathNameToRelativeNtPathName_U_WithStatus //sys RtlDefaultNpAcl(acl **ACL) (ntstatus error) = ntdll.RtlDefaultNpAcl //sys NtQueryInformationProcess(proc Handle, procInfoClass int32, procInfo unsafe.Pointer, procInfoLen uint32, retLen *uint32) (ntstatus error) = ntdll.NtQueryInformationProcess //sys NtSetInformationProcess(proc Handle, procInfoClass int32, procInfo unsafe.Pointer, procInfoLen uint32) (ntstatus error) = ntdll.NtSetInformationProcess @@ -1560,12 +1561,12 @@ func (s NTStatus) Error() string { return string(utf16.Decode(b[:n])) } -// NewUnicodeString returns a new UNICODE_STRING structure for use with native -// NT APIs that work over the UNICODE_STRING type. Note that most Windows APIs -// do not use UNICODE_STRING, and instead UTF16PtrFromString should be used for +// NewNTUnicodeString returns a new NTUnicodeString structure for use with native +// NT APIs that work over the NTUnicodeString type. Note that most Windows APIs +// do not use NTUnicodeString, and instead UTF16PtrFromString should be used for // the more common *uint16 string type. -func NewUnicodeString(s string) (*UNICODE_STRING, error) { - var u UNICODE_STRING +func NewNTUnicodeString(s string) (*NTUnicodeString, error) { + var u NTUnicodeString s16, err := UTF16PtrFromString(s) if err != nil { return nil, err @@ -1574,8 +1575,8 @@ func NewUnicodeString(s string) (*UNICODE_STRING, error) { return &u, nil } -// Slice returns a uint16 slice that aliases the data in the UNICODE_STRING. -func (s *UNICODE_STRING) Slice() []uint16 { +// Slice returns a uint16 slice that aliases the data in the NTUnicodeString. +func (s *NTUnicodeString) Slice() []uint16 { var slice []uint16 hdr := (*unsafeheader.Slice)(unsafe.Pointer(&slice)) hdr.Data = unsafe.Pointer(s.Buffer) @@ -1584,10 +1585,38 @@ func (s *UNICODE_STRING) Slice() []uint16 { return slice } -func (s *UNICODE_STRING) String() string { +func (s *NTUnicodeString) String() string { return UTF16ToString(s.Slice()) } +// NewNTString returns a new NTString structure for use with native +// NT APIs that work over the NTString type. Note that most Windows APIs +// do not use NTString, and instead UTF16PtrFromString should be used for +// the more common *uint16 string type. +func NewNTString(s string) (*NTString, error) { + var nts NTString + s8, err := BytePtrFromString(s) + if err != nil { + return nil, err + } + RtlInitString(&nts, s8) + return &nts, nil +} + +// Slice returns a byte slice that aliases the data in the NTString. +func (s *NTString) Slice() []byte { + var slice []byte + hdr := (*unsafeheader.Slice)(unsafe.Pointer(&slice)) + hdr.Data = unsafe.Pointer(s.Buffer) + hdr.Len = int(s.Length) + hdr.Cap = int(s.MaximumLength) + return slice +} + +func (s *NTString) String() string { + return ByteSliceToString(s.Slice()) +} + // FindResource resolves a resource of the given name and resource type. func FindResource(module Handle, name, resType ResourceIDOrString) (Handle, error) { var namePtr, resTypePtr uintptr diff --git a/windows/syscall_windows_test.go b/windows/syscall_windows_test.go index 100c43ab..0f17fb18 100644 --- a/windows/syscall_windows_test.go +++ b/windows/syscall_windows_test.go @@ -560,7 +560,20 @@ func TestPEBFilePath(t *testing.T) { } pebPath := entry.FullDllName.String() if osPath != pebPath { - t.Errorf("expected os.Executable() to return same value as peb.Ldr.{entry}.FullDllName - want %#q; got %#q", osPath, pebPath) + t.Errorf("peb.Ldr.{entry}.FullDllName = %#q; want %#q", pebPath, osPath) + } + paramPath := peb.ProcessParameters.ImagePathName.String() + if osPath != paramPath { + t.Errorf("peb.ProcessParameters.ImagePathName.{entry}.ImagePathName = %#q; want %#q", paramPath, osPath) + } + osCwd, err := os.Getwd() + if err != nil { + t.Errorf("unable to get working directory: %v", err) + } + osCwd = filepath.Clean(osCwd) + paramCwd := filepath.Clean(peb.ProcessParameters.CurrentDirectory.DosPath.String()) + if paramCwd != osCwd { + t.Errorf("peb.ProcessParameters.CurrentDirectory.DosPath = %#q; want %#q", paramCwd, osCwd) } } diff --git a/windows/types_windows.go b/windows/types_windows.go index dfd81162..369cc91d 100644 --- a/windows/types_windows.go +++ b/windows/types_windows.go @@ -2277,12 +2277,20 @@ type CommTimeouts struct { WriteTotalTimeoutConstant uint32 } -type UNICODE_STRING struct { +// NTUnicodeString is a UTF-16 string for NT native APIs, corresponding to UNICODE_STRING. +type NTUnicodeString struct { Length uint16 MaximumLength uint16 Buffer *uint16 } +// NTString is an ANSI string for NT native APIs, corresponding to STRING. +type NTString struct { + Length uint16 + MaximumLength uint16 + Buffer *byte +} + type LIST_ENTRY struct { Flink *LIST_ENTRY Blink *LIST_ENTRY @@ -2294,7 +2302,7 @@ type LDR_DATA_TABLE_ENTRY struct { reserved2 [2]uintptr DllBase uintptr reserved3 [2]uintptr - FullDllName UNICODE_STRING + FullDllName NTUnicodeString reserved4 [8]byte reserved5 [3]uintptr reserved6 uintptr @@ -2307,6 +2315,51 @@ type PEB_LDR_DATA struct { InMemoryOrderModuleList LIST_ENTRY } +type CURDIR struct { + DosPath NTUnicodeString + Handle Handle +} + +type RTL_DRIVE_LETTER_CURDIR struct { + Flags uint16 + Length uint16 + TimeStamp uint32 + DosPath NTString +} + +type RTL_USER_PROCESS_PARAMETERS struct { + MaximumLength, Length uint32 + + Flags, DebugFlags uint32 + + ConsoleHandle Handle + ConsoleFlags uint32 + StandardInput, StandardOutput, StandardError Handle + + CurrentDirectory CURDIR + DllPath NTUnicodeString + ImagePathName NTUnicodeString + CommandLine NTUnicodeString + Environment unsafe.Pointer + + StartingX, StartingY, CountX, CountY, CountCharsX, CountCharsY, FillAttribute uint32 + + WindowFlags, ShowWindowFlags uint32 + WindowTitle, DesktopInfo, ShellInfo, RuntimeData NTUnicodeString + CurrentDirectories [32]RTL_DRIVE_LETTER_CURDIR + + EnvironmentSize, EnvironmentVersion uintptr + + PackageDependencyData unsafe.Pointer + ProcessGroupId uint32 + LoaderThreads uint32 + + RedirectionDllName NTUnicodeString + HeapPartitionName NTUnicodeString + DefaultThreadpoolCpuSetMasks uintptr + DefaultThreadpoolCpuSetMaskCount uint32 +} + type PEB struct { reserved1 [2]byte BeingDebugged byte @@ -2314,7 +2367,7 @@ type PEB struct { reserved3 uintptr ImageBaseAddress uintptr Ldr *PEB_LDR_DATA - ProcessParameters uintptr + ProcessParameters *RTL_USER_PROCESS_PARAMETERS reserved4 [3]uintptr AtlThunkSListPtr uintptr reserved5 uintptr @@ -2333,7 +2386,7 @@ type PEB struct { type OBJECT_ATTRIBUTES struct { Length uint32 RootDirectory Handle - ObjectName *UNICODE_STRING + ObjectName *NTUnicodeString Attributes uint32 SecurityDescriptor *SECURITY_DESCRIPTOR SecurityQoS *SECURITY_QUALITY_OF_SERVICE @@ -2365,7 +2418,7 @@ type RTLP_CURDIR_REF struct { } type RTL_RELATIVE_NAME struct { - RelativeName UNICODE_STRING + RelativeName NTUnicodeString ContainingDirectory Handle CurDirRef *RTLP_CURDIR_REF } @@ -2470,7 +2523,7 @@ const ( ProcessHandleTracing ProcessIoPriority ProcessExecuteFlags - ProcessResourceManagement + ProcessTlsInformation ProcessCookie ProcessImageInformation ProcessCycleTime @@ -2545,8 +2598,8 @@ type PROCESS_BASIC_INFORMATION struct { PebBaseAddress *PEB AffinityMask uintptr BasePriority int32 - UniqueProcessId Handle - InheritedFromUniqueProcessId Handle + UniqueProcessId uintptr + InheritedFromUniqueProcessId uintptr } // Constants for LocalAlloc flags. diff --git a/windows/zsyscall_windows.go b/windows/zsyscall_windows.go index 6a8143a4..4e463c07 100644 --- a/windows/zsyscall_windows.go +++ b/windows/zsyscall_windows.go @@ -364,6 +364,7 @@ var ( procRtlGetCurrentPeb = modntdll.NewProc("RtlGetCurrentPeb") procRtlGetNtVersionNumbers = modntdll.NewProc("RtlGetNtVersionNumbers") procRtlGetVersion = modntdll.NewProc("RtlGetVersion") + procRtlInitString = modntdll.NewProc("RtlInitString") procRtlInitUnicodeString = modntdll.NewProc("RtlInitUnicodeString") procRtlNtStatusToDosErrorNoTeb = modntdll.NewProc("RtlNtStatusToDosErrorNoTeb") procCLSIDFromString = modole32.NewProc("CLSIDFromString") @@ -3096,7 +3097,7 @@ func RtlDefaultNpAcl(acl **ACL) (ntstatus error) { return } -func RtlDosPathNameToNtPathName(dosName *uint16, ntName *UNICODE_STRING, ntFileNamePart *uint16, relativeName *RTL_RELATIVE_NAME) (ntstatus error) { +func RtlDosPathNameToNtPathName(dosName *uint16, ntName *NTUnicodeString, ntFileNamePart *uint16, relativeName *RTL_RELATIVE_NAME) (ntstatus error) { r0, _, _ := syscall.Syscall6(procRtlDosPathNameToNtPathName_U_WithStatus.Addr(), 4, uintptr(unsafe.Pointer(dosName)), uintptr(unsafe.Pointer(ntName)), uintptr(unsafe.Pointer(ntFileNamePart)), uintptr(unsafe.Pointer(relativeName)), 0, 0) if r0 != 0 { ntstatus = NTStatus(r0) @@ -3104,7 +3105,7 @@ func RtlDosPathNameToNtPathName(dosName *uint16, ntName *UNICODE_STRING, ntFileN return } -func RtlDosPathNameToRelativeNtPathName(dosName *uint16, ntName *UNICODE_STRING, ntFileNamePart *uint16, relativeName *RTL_RELATIVE_NAME) (ntstatus error) { +func RtlDosPathNameToRelativeNtPathName(dosName *uint16, ntName *NTUnicodeString, ntFileNamePart *uint16, relativeName *RTL_RELATIVE_NAME) (ntstatus error) { r0, _, _ := syscall.Syscall6(procRtlDosPathNameToRelativeNtPathName_U_WithStatus.Addr(), 4, uintptr(unsafe.Pointer(dosName)), uintptr(unsafe.Pointer(ntName)), uintptr(unsafe.Pointer(ntFileNamePart)), uintptr(unsafe.Pointer(relativeName)), 0, 0) if r0 != 0 { ntstatus = NTStatus(r0) @@ -3131,7 +3132,12 @@ func rtlGetVersion(info *OsVersionInfoEx) (ntstatus error) { return } -func RtlInitUnicodeString(destinationString *UNICODE_STRING, sourceString *uint16) { +func RtlInitString(destinationString *NTString, sourceString *byte) { + syscall.Syscall(procRtlInitString.Addr(), 2, uintptr(unsafe.Pointer(destinationString)), uintptr(unsafe.Pointer(sourceString)), 0) + return +} + +func RtlInitUnicodeString(destinationString *NTUnicodeString, sourceString *uint16) { syscall.Syscall(procRtlInitUnicodeString.Addr(), 2, uintptr(unsafe.Pointer(destinationString)), uintptr(unsafe.Pointer(sourceString)), 0) return }