mirror of
https://github.com/lukaszraczylo/go-obfuscation.git
synced 2026-10-14 05:48:22 +00:00
134 lines
2.9 KiB
Go
134 lines
2.9 KiB
Go
//go:build linux
|
|
|
|
package pclntab
|
|
|
|
import (
|
|
"debug/elf"
|
|
"fmt"
|
|
"os"
|
|
"syscall"
|
|
"unsafe"
|
|
)
|
|
|
|
func runtimeCorrupt(binaryPath string, key byte) error {
|
|
self, err := os.ReadFile("/proc/self/exe")
|
|
if err != nil {
|
|
return fmt.Errorf("pclntab: cannot read /proc/self/exe: %w", err)
|
|
}
|
|
|
|
f, err := elf.NewFile(bytesReader(self))
|
|
if err != nil {
|
|
return fmt.Errorf("pclntab: cannot parse ELF from memory: %w", err)
|
|
}
|
|
|
|
sectionData, sectionAddr, sectionSize, err := findPclntabELF(f)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
nameStart, nameEnd := findMemoryNameRegion(sectionData)
|
|
if nameStart == 0 || nameEnd <= nameStart {
|
|
return fmt.Errorf("pclntab: could not locate name region")
|
|
}
|
|
|
|
baseAddr := sectionAddr &^ uintptr(syscall.Getpagesize()-1)
|
|
protSize := sectionSize + (sectionAddr - baseAddr)
|
|
|
|
if err := mprotectRW(baseAddr, protSize); err != nil {
|
|
return fmt.Errorf("pclntab: mprotect failed: %w", err)
|
|
}
|
|
|
|
basePtr := unsafe.Pointer(sectionAddr)
|
|
namePtr := unsafe.Add(basePtr, nameStart)
|
|
nameSlice := (*[1 << 30]byte)(namePtr)[: nameEnd-nameStart : nameEnd-nameStart]
|
|
for i := range nameSlice {
|
|
if nameSlice[i] != 0 {
|
|
nameSlice[i] ^= key
|
|
}
|
|
}
|
|
|
|
mprotectRO(baseAddr, protSize)
|
|
return nil
|
|
}
|
|
|
|
func findPclntabELF(f *elf.File) ([]byte, uintptr, uintptr, error) {
|
|
sectionNames := []string{
|
|
".gopclntab",
|
|
"runtime.pclntab",
|
|
"runtime.pclntab_v1",
|
|
}
|
|
|
|
for _, name := range sectionNames {
|
|
sec := f.Section(name)
|
|
if sec == nil {
|
|
continue
|
|
}
|
|
data, err := sec.Data()
|
|
if err != nil {
|
|
continue
|
|
}
|
|
buf := make([]byte, len(data))
|
|
copy(buf, data)
|
|
return buf, uintptr(sec.Addr), uintptr(sec.Size), nil
|
|
}
|
|
|
|
for _, sec := range f.Sections {
|
|
data, err := sec.Data()
|
|
if err != nil {
|
|
continue
|
|
}
|
|
if len(data) >= 8 {
|
|
for _, magic := range pclntabMagics {
|
|
if len(data) >= len(magic) && bytesEqual(data[:len(magic)], magic) {
|
|
buf := make([]byte, len(data))
|
|
copy(buf, data)
|
|
return buf, uintptr(sec.Addr), uintptr(sec.Size), nil
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil, 0, 0, fmt.Errorf("pclntab: .gopclntab section not found in memory")
|
|
}
|
|
|
|
func mprotectRW(addr uintptr, size uintptr) error {
|
|
return syscall.Mprotect(
|
|
(*[1]byte)(unsafe.Pointer(addr))[:size:size],
|
|
syscall.PROT_READ|syscall.PROT_WRITE,
|
|
)
|
|
}
|
|
|
|
func mprotectRO(addr uintptr, size uintptr) {
|
|
_ = syscall.Mprotect(
|
|
(*[1]byte)(unsafe.Pointer(addr))[:size:size],
|
|
syscall.PROT_READ,
|
|
)
|
|
}
|
|
|
|
func findMemoryNameRegion(data []byte) (uint32, uint32) {
|
|
tab := &pclntabParser{data: data}
|
|
if err := tab.parse(); err != nil {
|
|
return 0, 0
|
|
}
|
|
return findNameRegion(tab)
|
|
}
|
|
|
|
type bytesReaderWrapper struct {
|
|
data []byte
|
|
}
|
|
|
|
func bytesReader(data []byte) *bytesReaderWrapper {
|
|
return &bytesReaderWrapper{data: data}
|
|
}
|
|
|
|
func (r *bytesReaderWrapper) ReadAt(p []byte, off int64) (int, error) {
|
|
if off < 0 || int(off) >= len(r.data) {
|
|
return 0, fmt.Errorf("invalid offset")
|
|
}
|
|
n := copy(p, r.data[int(off):])
|
|
if n < len(p) {
|
|
return n, fmt.Errorf("EOF")
|
|
}
|
|
return n, nil
|
|
}
|