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) // Должно быть "hell" }