Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

runtime: Sycall Call function modifies value of procedure argument which is underlyingly immutable #48035

Closed
cristeigabriel opened this issue Aug 28, 2021 · 2 comments

Comments

@cristeigabriel
Copy link

@cristeigabriel cristeigabriel commented Aug 28, 2021

What version of Go are you using (go version)?

$ go version
go version go1.17 windows/amd64

Does this issue reproduce with the latest release?

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
set GO111MODULE=on
set GOARCH=amd64
set GOBIN=
set GOCACHE=C:\Users\malloc\AppData\Local\go-build
set GOENV=C:\Users\malloc\AppData\Roaming\go\env
set GOEXE=.exe
set GOEXPERIMENT=
set GOFLAGS=
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOINSECURE=
set GOMODCACHE=C:\Users\malloc\go\pkg\mod
set GONOPROXY=
set GONOSUMDB=
set GOOS=windows
set GOPATH=C:\Users\malloc\go
set GOPRIVATE=
set GOPROXY=https://proxy.golang.org,direct
set GOROOT=C:\Program Files\Go
set GOSUMDB=sum.golang.org
set GOTMPDIR=
set GOTOOLDIR=C:\Program Files\Go\pkg\tool\windows_amd64
set GOVCS=
set GOVERSION=go1.17
set GCCGO=gccgo
set AR=ar
set CC=gcc
set CXX=g++
set CGO_ENABLED=1
set GOMOD=C:\Users\malloc\Desktop\gohack\go.mod
set CGO_CFLAGS=-g -O2
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-g -O2
set CGO_FFLAGS=-g -O2
set CGO_LDFLAGS=-g -O2
set PKG_CONFIG=pkg-config
set GOGCCFLAGS=-m64 -mthreads -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=C:\Users\malloc\AppData\Local\Temp\go-build1453493053=/tmp/go-build -gno-record-gcc-switches
GOROOT/bin/go version: go version go1.17 windows/amd64
GOROOT/bin/go tool compile -V: compile version go1.17

What did you do?

In the rawest form, this is what I'm doing. I don't know if there's any Go playground servers which run Windows, so I haven't tried reproducing this issue in it, yet.

	fmt.Printf("%p\n", (*(**Player)(context.playerPtr)))
	fmt.Printf("%p\n", (*(**Player)(context.playerPtr)))
	a := (*(**Player)(context.playerPtr)).getHealth()
	fmt.Printf("%d %p\n", a, (*(**Player)(context.playerPtr)))

getHealth does the following:

func (player *Player) get(size uint32, ptrdiff uintptr) unsafe.Pointer {
	return Instance.csgo.readMemory(size, uintptr(unsafe.Pointer(player))+ptrdiff)
}

func (player *Player) getHealth() int {
	return *(*int)(player.get(4, 0x100))
}

readMemory does the following:

gReadProcessMemory  = gKernel32.MustFindProc("ReadProcessMemory")

func (process *Process) readMemory(size uint32, at uintptr) unsafe.Pointer {
	var address byte
	addressPtr := unsafe.Pointer(&address)

	state, _, _ := gReadProcessMemory.Call(uintptr(process.handle), at, uintptr(addressPtr), uintptr(size), 0)

	if state == 0 {
		panic(fmt.Sprintf("Epicly failed: RPM at %x is SUS!", at))
		return nil
	}

	return addressPtr
}

ReadProcessMemory has the following as the first 2 arguments: a process handle, a const void*.

I'm respectively passing a base address which is the result of turning a pointer into an uintptr, then combining that value with 0x100 in this scenario.

I don't see how WINAPI could be at fault modifying underlying content even though it'd have the 'permission' to overwrite what we're pointing at. Even then, though, I'm passing a result of an operation, not the raw pointer itself, which is the one being modified. I think it's the result of a direct semantic in Go?

What did you expect to see?

address, same address, health (an integer that goes from 0 to 100), same address as the former two

What did you see instead?

address, same address, (correct) health, new address which is consistent on all runs (0x6480) (changes according to the ptrdiff passed in get(...), but stays consistent with the same ptrdiff.)

For more context: I have more RPM calls within my software, and they don't cause any side effect as this procedure. This is the only, unique case where this happens. In the aforementioned, I also have the scenario where I take a pointer, convert it to an uintptr, then use that value for combination, then read at the newly produced address.

@cristeigabriel cristeigabriel changed the title runtime: Sycall Call function modifies value of procedure argument which is immutable runtime: Sycall Call function modifies value of procedure argument which is underlyingly immutable Aug 28, 2021
@randall77
Copy link
Contributor

@randall77 randall77 commented Aug 28, 2021

I find it hard to understand what this code is doing, or is intended to do. It would really help to have a full program we could run ourselves. Same for #48041 .

Your use of unsafe looks problematic. Please make sure you read and adhere to the restrictions described at https://pkg.go.dev/unsafe#Pointer

Loading

@gopherbot
Copy link

@gopherbot gopherbot commented Sep 30, 2021

Timed out in state WaitingForInfo. Closing.

(I am just a bot, though. Please speak up if this is a mistake or you have the requested information.)

Loading

@gopherbot gopherbot closed this Sep 30, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
4 participants