59 lines
1.8 KiB
Go
59 lines
1.8 KiB
Go
package main
|
||
|
||
import (
|
||
"fmt"
|
||
"syscall"
|
||
"unsafe"
|
||
)
|
||
|
||
func main() {
|
||
s := "hello"
|
||
fmt.Println("Original:", s)
|
||
|
||
// Строки в Go - структуры с двумя полями: указатель на данные и длина
|
||
// тут строка интерпретируется как структура
|
||
strHeader := (*struct {
|
||
data unsafe.Pointer
|
||
len int
|
||
})(unsafe.Pointer(&s))
|
||
|
||
// Вычисляем начало страницы памяти
|
||
pageSize := syscall.Getpagesize()
|
||
pageStart := uintptr(strHeader.data) - (uintptr(strHeader.data) % uintptr(pageSize))
|
||
fmt.Printf(
|
||
"\nАдрес строки = %d\nразмер страницы памяти = %d\nадрес строки относительно начала страницы = %d\nадрес страницы = %d\n\n",
|
||
uintptr(strHeader.data),
|
||
uintptr(pageSize),
|
||
(uintptr(strHeader.data) % uintptr(pageSize)),
|
||
pageStart)
|
||
|
||
// Имея адрес страницы и ее размер даю права на запись на данной странице памяти
|
||
ret, _, err := syscall.Syscall(
|
||
syscall.SYS_MPROTECT,
|
||
pageStart,
|
||
uintptr(pageSize),
|
||
uintptr(syscall.PROT_READ|syscall.PROT_WRITE),
|
||
)
|
||
if ret != 0 {
|
||
panic("mprotect failed: " + err.Error())
|
||
}
|
||
|
||
// Теперь можно менять строку
|
||
// поменяю, например, пятый байт
|
||
fifthBytePtr := (*byte)(unsafe.Pointer(uintptr(strHeader.data) + 4))
|
||
*fifthBytePtr = 0
|
||
|
||
// Восстанавливаю дефолтные права
|
||
ret, _, err = syscall.Syscall(
|
||
syscall.SYS_MPROTECT,
|
||
pageStart,
|
||
uintptr(pageSize),
|
||
uintptr(syscall.PROT_READ),
|
||
)
|
||
if ret != 0 {
|
||
panic("mprotect restore failed: " + err.Error())
|
||
}
|
||
|
||
fmt.Println("Modified:", s) // Должно быть "Xello"
|
||
}
|