Skip to content

Commit

Permalink
Windows: fix a crash when splitting command-line arguments
Browse files Browse the repository at this point in the history
This fixes a crash when fetching a process arguments. The command-line
string read from the target process memory sometimes is not terminated.
It can cause bogus characters to be appended to the command-line
or a crash.
  • Loading branch information
adriansr committed Jul 9, 2019
1 parent 99ed9cf commit 57887ae
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 5 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).

### Fixed

- Fixed a crash when splitting command-line arguments under Windows. #124

### Changed

### Deprecated
Expand Down
32 changes: 27 additions & 5 deletions sys/windows/syscall_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -503,9 +503,17 @@ func GetUserProcessParams(handle syscall.Handle, pbi ProcessBasicInformation) (p
return params, nil
}

// ReadProcessUnicodeString returns a zero-terminated UTF-16 string from another
// process memory.
func ReadProcessUnicodeString(handle syscall.Handle, s *UnicodeString) ([]byte, error) {
buf := make([]byte, s.Size)
nRead, err := ReadProcessMemory(handle, s.Buffer, buf)
// Allocate an extra UTF-16 null character at the end in case the read string
// is not terminated.
extra := 2
if s.Size&1 != 0 {
extra = 3 // If size is odd, need 3 nulls to terminate.
}
buf := make([]byte, int(s.Size)+extra)
nRead, err := ReadProcessMemory(handle, s.Buffer, buf[:s.Size])
if err != nil {
return nil, err
}
Expand All @@ -515,12 +523,26 @@ func ReadProcessUnicodeString(handle syscall.Handle, s *UnicodeString) ([]byte,
return buf, nil
}

// Use Windows' CommandLineToArgv API to split an UTF-16 command line string
// into a list of parameters.
// ByteSliceToStringSlice uses CommandLineToArgv API to split an UTF-16 command
// line string into a list of parameters.
func ByteSliceToStringSlice(utf16 []byte) ([]string, error) {
if len(utf16) == 0 {
n := len(utf16)
// Discard odd byte
if n&1 != 0 {
n--
utf16 = utf16[:n]
}
if n == 0 {
return nil, nil
}
terminated := false
for i := 0; i < n && !terminated; i += 2 {
terminated = utf16[i] == 0 && utf16[i+1] == 0
}
if !terminated {
// Append a null uint16 at the end if terminator is missing
utf16 = append(utf16, 0, 0)
}
var numArgs int32
argsWide, err := syscall.CommandLineToArgv((*uint16)(unsafe.Pointer(&utf16[0])), &numArgs)
if err != nil {
Expand Down

0 comments on commit 57887ae

Please sign in to comment.