81 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			81 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			Go
		
	
	
	
| package winapi
 | |
| 
 | |
| import (
 | |
| 	"errors"
 | |
| 	"reflect"
 | |
| 	"syscall"
 | |
| 	"unsafe"
 | |
| 
 | |
| 	"golang.org/x/sys/windows"
 | |
| )
 | |
| 
 | |
| // Uint16BufferToSlice wraps a uint16 pointer-and-length into a slice
 | |
| // for easier interop with Go APIs
 | |
| func Uint16BufferToSlice(buffer *uint16, bufferLength int) (result []uint16) {
 | |
| 	hdr := (*reflect.SliceHeader)(unsafe.Pointer(&result))
 | |
| 	hdr.Data = uintptr(unsafe.Pointer(buffer))
 | |
| 	hdr.Cap = bufferLength
 | |
| 	hdr.Len = bufferLength
 | |
| 
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // UnicodeString corresponds to UNICODE_STRING win32 struct defined here
 | |
| // https://docs.microsoft.com/en-us/windows/win32/api/ntdef/ns-ntdef-_unicode_string
 | |
| type UnicodeString struct {
 | |
| 	Length        uint16
 | |
| 	MaximumLength uint16
 | |
| 	Buffer        *uint16
 | |
| }
 | |
| 
 | |
| // NTSTRSAFE_UNICODE_STRING_MAX_CCH is a constant defined in ntstrsafe.h. This value
 | |
| // denotes the maximum number of wide chars a path can have.
 | |
| const NTSTRSAFE_UNICODE_STRING_MAX_CCH = 32767
 | |
| 
 | |
| //String converts a UnicodeString to a golang string
 | |
| func (uni UnicodeString) String() string {
 | |
| 	// UnicodeString is not guaranteed to be null terminated, therefore
 | |
| 	// use the UnicodeString's Length field
 | |
| 	return windows.UTF16ToString(Uint16BufferToSlice(uni.Buffer, int(uni.Length/2)))
 | |
| }
 | |
| 
 | |
| // NewUnicodeString allocates a new UnicodeString and copies `s` into
 | |
| // the buffer of the new UnicodeString.
 | |
| func NewUnicodeString(s string) (*UnicodeString, error) {
 | |
| 	buf, err := windows.UTF16FromString(s)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	if len(buf) > NTSTRSAFE_UNICODE_STRING_MAX_CCH {
 | |
| 		return nil, syscall.ENAMETOOLONG
 | |
| 	}
 | |
| 
 | |
| 	uni := &UnicodeString{
 | |
| 		// The length is in bytes and should not include the trailing null character.
 | |
| 		Length:        uint16((len(buf) - 1) * 2),
 | |
| 		MaximumLength: uint16((len(buf) - 1) * 2),
 | |
| 		Buffer:        &buf[0],
 | |
| 	}
 | |
| 	return uni, nil
 | |
| }
 | |
| 
 | |
| // ConvertStringSetToSlice is a helper function used to convert the contents of
 | |
| // `buf` into a string slice. `buf` contains a set of null terminated strings
 | |
| // with an additional null at the end to indicate the end of the set.
 | |
| func ConvertStringSetToSlice(buf []byte) ([]string, error) {
 | |
| 	var results []string
 | |
| 	prev := 0
 | |
| 	for i := range buf {
 | |
| 		if buf[i] == 0 {
 | |
| 			if prev == i {
 | |
| 				// found two null characters in a row, return result
 | |
| 				return results, nil
 | |
| 			}
 | |
| 			results = append(results, string(buf[prev:i]))
 | |
| 			prev = i + 1
 | |
| 		}
 | |
| 	}
 | |
| 	return nil, errors.New("string set malformed: missing null terminator at end of buffer")
 | |
| }
 |