Monkeypatching Go на ppc64le

Я пытаюсь выполнить "Monkeypatching" на Go, аналогично тому, что было сделано на Intel по адресу:

https://bou.ke/blog/monkey-patching-in-go/

Для powerPC в аналогичных строках (как в блоге) мои наблюдения были следующими: Чтобы "исправить" функцию, нужно было бы заменить код по адресу функции на машинный код, чтобы перейти / перейти к адресу "новой" функции..

Машинный код / ​​инструкции сборки для исправления (например, давайте рассмотрим адрес 0x20000) будут такими:

--
 00 00 80 3d    lis    r12,0
 00 00 8c 61    ori    r12,r12,0
 c6 07 8c 79    rldicr r12,r12,32,31
 02 00 8c 65    oris   r12,r12,2
 00 00 8c 61    ori    r12,r12,0
 a6 03 89 7d    mtctr  r12
 21 04 80 4e    bctrl
 --

Первые 5 строк заполняют регистр r12 значением 0x20000, 6-я строка перемещает содержимое r12 в "счетный регистр", а инструкция "bctrl" вызывает переход к адресу в "счетном регистре".

Исходя из этого, я модифицировал функцию AssemblyJump(), чтобы использовать машинные инструкции для выполнения "перехода / перехода" к новому адресу.

Я разобрал полученный двоичный файл с помощью команды "$objdump -dS ./patchbinary"

Дизассемблированный код был:

---
 000000000009c9e0 <main.a>:
         "fmt"
         "syscall"
         "unsafe"
 )

func a() int { return 7}
    9c9e0:       07 00 60 38     li      r3,7
    9c9e4:       20 00 61 f8     std     r3,32(r1)
    9c9e8:       20 00 80 4e     blr
    9c9ec:       00 00 00 00     .long 0x0

000000000009c9f0 <main.b>:
 func b() int { return 3}
    9c9f0:       03 00 60 38     li      r3,3
    9c9f4:       20 00 61 f8     std     r3,32(r1)
    9c9f8:       20 00 80 4e     blr
    9c9fc:       00 00 00 00     .long 0x0

---

Это означает, что функция a() находится по адресу 0x9c9e0, а функция b() находится по адресу 0x9c9f0 (функция a() возвращает "7", а b возвращает "3")

Теперь, когда я запускаю программу под gdb с помощью команды "$gdb -q ./patchbinary"

перед патчем:

(gdb) x 0x9c9e0
 0x9c9e0 <main.a>:      0x38600007
 (gdb) x 0x9c9f0
 0x9c9f0 <main.b>:       0x38600003

после исправления выводится следующее: (обратите внимание, что значения изменились, проблема в том, что размер исправления составляет 28 байтов, а исправляемая функция - 16 байтов, поэтому память за пределами функции перезаписывается!)

(gdb) x 0x9c9e0
 0x9c9e0 <main.a>:       0x3d80bb18
 (gdb) x 0x9c9f0
 0x9c9f0 <main.b>:       0x618c0000
 (gdb)

-

Теперь, на последнем шаге в функции "main()", где выполняются a() и b() - значения, которые печатаются, по-прежнему равны "7" и "3", которые должны были печатать исходные функции!

Несмотря на то, что код изменен по указанным адресам (как показано в GDB), старый код функции каким-то образом выполняется.

Ищу совета, есть ли у кого-нибудь указания о том, как действовать дальше, или кто-то другой может иметь замысловатое представление о том, как добиться этого "обезьяньего патчинга".

Я использовал следующий пример кода: (на основе https://bou.ke/blog/monkey-patching-in-go/)


package main
 import (
         "fmt"
         "syscall"
         "unsafe"
 )
 func a() int { return 7}
 func b() int { return 3}
 func getPage(p uintptr) []byte {
         return (*(*[0xFFFFFF]byte)(unsafe.Pointer(p & ^uintptr(syscall.Getpagesize()-1))))[:syscall.Getpagesize()]
 }
 func rawMemoryAccess(b uintptr) []byte {
         return (*(*[0xFF]byte)(unsafe.Pointer(b)))[:]
 }
 func assembleJump(f func() int) []byte {
         funcVal := *(*uintptr)(unsafe.Pointer(&f))
         return []byte{
                 byte(funcVal),
                 byte(funcVal >> 8),
                 0x80,0x3D,
                 byte(funcVal >> 16),
                 byte(funcVal >> 24),
                 0x8C,0x61,
                 0xC6,0x07,0x8C,0x79,
                 byte(funcVal >> 32),
                 byte(funcVal >> 40),
                 0x8C,0x65,
                 byte(funcVal >> 48),
                 byte(funcVal >> 56),
                 0x8C,0x61,
                 0xA6, 0x03, 0x89, 0x7d,
                 0x21, 0x04, 0x80, 0x4E,
         }
 }
 func replace(orig, replacement func() int) {
         bytes := assembleJump(replacement)

        fmt.Printf("Patch Data: %x",bytes)
         fmt.Printf("\n")
         functionLocation := **(**uintptr)(unsafe.Pointer(&orig))
         window := rawMemoryAccess(functionLocation)
         page := getPage(functionLocation)
         syscall.Mprotect(page, syscall.PROT_READ|syscall.PROT_WRITE|syscall.PROT_EXEC)
         copy(window, bytes)
 }
 func main() {
         f1 := a
         f2 := b
         fmt.Printf("0x%x\n", **(**uintptr)(unsafe.Pointer(&f1)))
         fmt.Printf("0x%x\n", **(**uintptr)(unsafe.Pointer(&f2)))
         replace(a, b)
         print(a())
         print(b())
 }

-

0 ответов

Другие вопросы по тегам