Обезьяны-патчи Go на ppc64le - PullRequest
0 голосов
/ 09 апреля 2020

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

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

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

Машинный код / ​​инструкции по сборке для исправления (например, давайте рассмотрим адрес 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) старый код функции каким-то образом исполняется.

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

Пример кода, который я использовал, был следующим: (на основе 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())
 }

-

...