hopefully fix access violation error
This commit is contained in:
@@ -13,7 +13,10 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
"unicode/utf16"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -1193,27 +1196,109 @@ func createSuspendedProcessOnDesktop(filePath, searchPath, replacePath, shmName
|
|||||||
}
|
}
|
||||||
|
|
||||||
func buildEnvironmentBlock(searchPath, replacePath, shmName string, dllSize int) ([]uint16, error) {
|
func buildEnvironmentBlock(searchPath, replacePath, shmName string, dllSize int) ([]uint16, error) {
|
||||||
envStrings := syscall.Environ()
|
rawPtr, err := windows.GetEnvironmentStrings()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("GetEnvironmentStrings: %w", err)
|
||||||
|
}
|
||||||
|
defer windows.FreeEnvironmentStrings(rawPtr)
|
||||||
|
|
||||||
envStrings = append(envStrings, "RDI_SEARCH_PATH="+searchPath)
|
rawSlice := (*[1 << 20]uint16)(unsafe.Pointer(rawPtr))[:]
|
||||||
envStrings = append(envStrings, "RDI_REPLACE_PATH="+replacePath)
|
blockLen := 0
|
||||||
if shmName != "" {
|
for i := 0; ; i++ {
|
||||||
envStrings = append(envStrings, "RDI_DLL_SECTION="+shmName)
|
if rawSlice[i] == 0 && i > 0 && rawSlice[i-1] == 0 {
|
||||||
envStrings = append(envStrings, fmt.Sprintf("RDI_DLL_SIZE=%d", dllSize))
|
blockLen = i + 1
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if i >= len(rawSlice)-1 {
|
||||||
|
return nil, fmt.Errorf("environment block appears unterminated")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var block []uint16
|
extra := []string{
|
||||||
for _, s := range envStrings {
|
"RDI_SEARCH_PATH=" + searchPath,
|
||||||
u, err := syscall.UTF16FromString(s)
|
"RDI_REPLACE_PATH=" + replacePath,
|
||||||
|
}
|
||||||
|
if shmName != "" {
|
||||||
|
extra = append(extra, "RDI_DLL_SECTION="+shmName)
|
||||||
|
extra = append(extra, fmt.Sprintf("RDI_DLL_SIZE=%d", dllSize))
|
||||||
|
}
|
||||||
|
|
||||||
|
return appendEnvironmentOverrides(rawSlice[:blockLen], extra)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendEnvironmentOverrides(rawBlock []uint16, extra []string) ([]uint16, error) {
|
||||||
|
entries, err := environmentBlockEntries(rawBlock)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
block := make([]uint16, 0, len(rawBlock))
|
||||||
|
for _, entry := range entries {
|
||||||
|
if isRDIEnvironmentEntry(entry) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
u, encErr := syscall.UTF16FromString(entry)
|
||||||
|
if encErr != nil {
|
||||||
|
return nil, fmt.Errorf("UTF16FromString(%q): %w", entry, encErr)
|
||||||
|
}
|
||||||
block = append(block, u...)
|
block = append(block, u...)
|
||||||
}
|
}
|
||||||
|
for _, entry := range extra {
|
||||||
|
u, encErr := syscall.UTF16FromString(entry)
|
||||||
|
if encErr != nil {
|
||||||
|
return nil, fmt.Errorf("UTF16FromString(%q): %w", entry, encErr)
|
||||||
|
}
|
||||||
|
block = append(block, u...)
|
||||||
|
}
|
||||||
|
|
||||||
block = append(block, 0)
|
block = append(block, 0)
|
||||||
return block, nil
|
return block, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func environmentBlockEntries(block []uint16) ([]string, error) {
|
||||||
|
entries := make([]string, 0, 32)
|
||||||
|
for i := 0; i < len(block); {
|
||||||
|
if block[i] == 0 {
|
||||||
|
return entries, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
start := i
|
||||||
|
for i < len(block) && block[i] != 0 {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
if i >= len(block) {
|
||||||
|
return nil, fmt.Errorf("environment block entry appears unterminated")
|
||||||
|
}
|
||||||
|
entries = append(entries, string(utf16.Decode(block[start:i])))
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("environment block appears unterminated")
|
||||||
|
}
|
||||||
|
|
||||||
|
func isRDIEnvironmentEntry(entry string) bool {
|
||||||
|
if strings.HasPrefix(entry, "=") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
name, _, ok := strings.Cut(entry, "=")
|
||||||
|
if !ok {
|
||||||
|
name = entry
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case strings.EqualFold(name, "RDI_SEARCH_PATH"):
|
||||||
|
return true
|
||||||
|
case strings.EqualFold(name, "RDI_REPLACE_PATH"):
|
||||||
|
return true
|
||||||
|
case strings.EqualFold(name, "RDI_DLL_SECTION"):
|
||||||
|
return true
|
||||||
|
case strings.EqualFold(name, "RDI_DLL_SIZE"):
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func reflectiveInject(hProcess uintptr, dllBytes []byte) error {
|
func reflectiveInject(hProcess uintptr, dllBytes []byte) error {
|
||||||
loaderOffset, err := findReflectiveLoaderOffset(dllBytes)
|
loaderOffset, err := findReflectiveLoaderOffset(dllBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package capture
|
||||||
|
|
||||||
|
import (
|
||||||
|
"slices"
|
||||||
|
"syscall"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAppendEnvironmentOverridesPreservesUnicodeAndReplacesRDI(t *testing.T) {
|
||||||
|
raw := testEnvironmentBlock(t,
|
||||||
|
"=C:=C:\\Users\\tester",
|
||||||
|
"Path=C:\\Windows\\System32",
|
||||||
|
"RDI_SEARCH_PATH=C:\\stale",
|
||||||
|
"rdi_dll_size=not-a-number",
|
||||||
|
"USERNAME=Jose\u0301",
|
||||||
|
)
|
||||||
|
|
||||||
|
block, err := appendEnvironmentOverrides(raw, []string{
|
||||||
|
"RDI_SEARCH_PATH=C:\\Users\\\u6d4b\u8bd5\\Profile",
|
||||||
|
"RDI_REPLACE_PATH=D:\\Clone\\\u590d\u5236",
|
||||||
|
"RDI_DLL_SECTION=Local\\OverlordRDI_123",
|
||||||
|
"RDI_DLL_SIZE=12345",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("appendEnvironmentOverrides: %v", err)
|
||||||
|
}
|
||||||
|
if len(block) < 2 || block[len(block)-1] != 0 || block[len(block)-2] != 0 {
|
||||||
|
t.Fatalf("environment block is not double-NUL terminated: tail=%v", block[max(0, len(block)-4):])
|
||||||
|
}
|
||||||
|
|
||||||
|
entries, err := environmentBlockEntries(block)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("environmentBlockEntries: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, stale := range []string{"RDI_SEARCH_PATH=C:\\stale", "rdi_dll_size=not-a-number"} {
|
||||||
|
if slices.Contains(entries, stale) {
|
||||||
|
t.Fatalf("stale RDI entry was preserved: %q in %#v", stale, entries)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, want := range []string{
|
||||||
|
"=C:=C:\\Users\\tester",
|
||||||
|
"USERNAME=Jose\u0301",
|
||||||
|
"RDI_SEARCH_PATH=C:\\Users\\\u6d4b\u8bd5\\Profile",
|
||||||
|
"RDI_REPLACE_PATH=D:\\Clone\\\u590d\u5236",
|
||||||
|
"RDI_DLL_SIZE=12345",
|
||||||
|
} {
|
||||||
|
if !slices.Contains(entries, want) {
|
||||||
|
t.Fatalf("missing environment entry %q in %#v", want, entries)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testEnvironmentBlock(t *testing.T, entries ...string) []uint16 {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
var block []uint16
|
||||||
|
for _, entry := range entries {
|
||||||
|
u, err := syscall.UTF16FromString(entry)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("UTF16FromString(%q): %v", entry, err)
|
||||||
|
}
|
||||||
|
block = append(block, u...)
|
||||||
|
}
|
||||||
|
return append(block, 0)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user