Skip to content

Instantly share code, notes, and snippets.

@taoso
Created August 28, 2021 05:01
Show Gist options
  • Save taoso/76279c7c6233444dce12d2ab1ab38324 to your computer and use it in GitHub Desktop.
Save taoso/76279c7c6233444dce12d2ab1ab38324 to your computer and use it in GitHub Desktop.
package main
import (
"fmt"
"reflect"
"syscall"
"unsafe"
)
func a() int {
return 1
}
func b() int {
return 2
}
func patch(target, replacement interface{}) {
from := reflect.ValueOf(target).Pointer()
to := reflect.ValueOf(replacement).Pointer()
data := jmp(to)
copyTo(from, data)
}
func jmp(to uintptr) []byte {
return []byte{
0x48, 0xBA,
byte(to),
byte(to >> 8),
byte(to >> 16),
byte(to >> 24),
byte(to >> 32),
byte(to >> 40),
byte(to >> 48),
byte(to >> 56), // movabs rdx,to
0xFF, 0xE2, // jmp rdx
}
}
func copyTo(location uintptr, data []byte) {
f := rawMemoryAccess(location, len(data))
mprotectCrossPage(location, len(data), syscall.PROT_READ|syscall.PROT_EXEC|syscall.PROT_WRITE)
copy(f, data[:])
mprotectCrossPage(location, len(data), syscall.PROT_READ|syscall.PROT_EXEC)
}
func rawMemoryAccess(p uintptr, length int) []byte {
return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
Data: p,
Len: length,
Cap: length,
}))
}
func mprotectCrossPage(addr uintptr, length int, prot int) {
pageSize := syscall.Getpagesize()
for p := pageStart(addr); p < addr+uintptr(length); p += uintptr(pageSize) {
page := rawMemoryAccess(p, pageSize)
if err := syscall.Mprotect(page, prot); err != nil {
panic(err)
}
}
}
func pageStart(ptr uintptr) uintptr {
return ptr & ^(uintptr(syscall.Getpagesize() - 1))
}
func main() {
patch(a, b)
fmt.Println(a())
}
@moltenWood
Copy link

moltenWood commented Sep 17, 2021

excuse me, why I got 1 instead of 2 as you said after I copied your code and ran it? Did I miss something? go version go1.17 linux/amd64

go run -gcflags '-N -l' main.go

@taoso
Copy link
Author

taoso commented Sep 17, 2021

excuse me, why I got 1 instead of 2 as you said after I copied your code and ran it? Did I miss something? go version go1.17 linux/amd64

go run -gcflags '-N -l' main.go

hi @moltenWood
here is my test result on linux amd64 vm
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment