Skip to content

Instantly share code, notes, and snippets.

@ericlagergren
Last active February 13, 2016 06:53
Show Gist options
  • Save ericlagergren/307a92d9df659187b5a5 to your computer and use it in GitHub Desktop.
Save ericlagergren/307a92d9df659187b5a5 to your computer and use it in GitHub Desktop.
package main
import (
"flag"
"fmt"
"log"
"os"
"runtime"
"unsafe"
"golang.org/x/sys/unix"
"github.com/EricLagergren/proc"
)
var debug = flag.Bool("debug", false, "")
func init() {
Sub(0, 0) // Load var a with the pc of Sub.
}
func main() {
flag.Parse()
fmt.Printf("Calling Sub(2, 1): %d\n\n", Sub(2, 1)) // Prints 1.
maps := proc.ParseMaps()
if *debug {
fmt.Println("Program maps:")
for _, m := range maps {
fmt.Println(m)
}
fmt.Println("")
}
// Find the map that contains code for Sub.
var m proc.Map
for _, mp := range maps {
if a >= mp.Start && a <= mp.End {
m = mp
break
}
}
// Load the shared object file.
buf := mmap("/home/eric/gopath/pkg/linux_amd64_dynlink/lib.so")
// Relevant code starts at 0xb10.
ptr := uintptr(unsafe.Pointer(&buf[0xb10]))
if *debug {
fmt.Printf("Address of new code: %#x\n", ptr)
}
// The following [12]byte is:
// movabs $addr,%rax
// jmpq *%rax
b := [12]byte{0x48, 0xb8}
*(*uintptr)(unsafe.Pointer(&b[2])) = ptr
b[10] = 0xff
b[11] = 0xe0
if *debug {
fmt.Println(m, "\n")
}
if err := mprotect(
unsafe.Pointer(m.Start),
m.End-m.Start,
unix.PROT_EXEC|
unix.PROT_WRITE|
unix.PROT_READ); err != nil {
log.Fatalln(err)
}
if *debug {
fmt.Println("Program maps:")
for _, m := range proc.ParseMaps() {
fmt.Println(m)
}
fmt.Println("\nFirst 12 bytes of Sub:")
for _, c := range *(*[12]byte)(unsafe.Pointer(a)) {
fmt.Printf("%#x ", c)
}
fmt.Println("")
}
*(*[12]byte)(unsafe.Pointer(a)) = b
if *debug {
fmt.Println("\nNew 12 bytes of Sub:")
for _, c := range *(*[12]byte)(unsafe.Pointer(a)) {
fmt.Printf("%#x ", c)
}
fmt.Println("\n")
}
fmt.Println("Calling hot-swapped Sub(2, 1):", Sub(2, 1))
}
// defined in in main.s
func Sub(a, b int32) (c int32)
var a uintptr
func Foo() {
pc := make([]uintptr, 100)
x := runtime.Callers(0, pc)
for _, c := range pc[:x] {
f := runtime.FuncForPC(c)
if f.Name() == "main.Sub" {
a = f.Entry()
}
}
}
func mprotect(_p0 unsafe.Pointer, length uintptr, prot int) (err error) {
_, _, e1 := unix.Syscall(unix.SYS_MPROTECT, uintptr(_p0), uintptr(length), uintptr(prot))
if e1 != 0 {
return e1
}
return
}
func mmap(name string) []byte {
file, err := os.Open(name)
if err != nil {
log.Fatalln(err)
}
defer file.Close()
stat, err := file.Stat()
if err != nil {
log.Fatalln(err)
}
buf, err := unix.Mmap(int(file.Fd()), 0, int(stat.Size()), unix.PROT_EXEC|unix.PROT_WRITE|unix.PROT_READ, unix.MAP_PRIVATE)
if err != nil {
log.Fatalln(err)
}
return buf
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment