mirror of
https://github.com/lukaszraczylo/go-obfuscation.git
synced 2026-10-14 05:48:22 +00:00
Initial commit
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
package syscallobf
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
dispatchKey uint64
|
||||
dispatchOnce sync.Once
|
||||
)
|
||||
|
||||
func initDispatchKey() {
|
||||
dispatchOnce.Do(func() {
|
||||
var buf [8]byte
|
||||
rand.Read(buf[:])
|
||||
dispatchKey = binary.LittleEndian.Uint64(buf[:])
|
||||
if dispatchKey == 0 {
|
||||
dispatchKey = 0xDEADBEEFCAFEBABE
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func EncodeTrap(num uintptr) uintptr {
|
||||
initDispatchKey()
|
||||
return uintptr(uint64(num) ^ dispatchKey)
|
||||
}
|
||||
|
||||
func DecodeTrap(encoded uintptr) uintptr {
|
||||
return uintptr(uint64(encoded) ^ dispatchKey)
|
||||
}
|
||||
|
||||
type encodedSyscall struct {
|
||||
encoded uintptr
|
||||
}
|
||||
|
||||
func NewEncodedSyscall(num uintptr) encodedSyscall {
|
||||
return encodedSyscall{encoded: EncodeTrap(num)}
|
||||
}
|
||||
|
||||
func (e encodedSyscall) Trap() uintptr {
|
||||
return DecodeTrap(e.encoded)
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package syscallobf
|
||||
|
||||
import "syscall"
|
||||
|
||||
func ObfPtrace(request int, pid uintptr, addr uintptr, data uintptr) (uintptr, uintptr, syscall.Errno) {
|
||||
return 0, 0, syscall.ENOSYS
|
||||
}
|
||||
|
||||
func ObfGetpid() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func ObfKill(pid int, sig int) error {
|
||||
return syscall.ENOSYS
|
||||
}
|
||||
|
||||
func ObfOpen(path string, flags int, mode int) (int, error) {
|
||||
return -1, syscall.ENOSYS
|
||||
}
|
||||
|
||||
func ObfClose(fd int) error {
|
||||
return syscall.ENOSYS
|
||||
}
|
||||
|
||||
func ObfRead(fd int, buf []byte) (int, error) {
|
||||
return 0, syscall.ENOSYS
|
||||
}
|
||||
|
||||
func ObfMmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset uintptr) (uintptr, error) {
|
||||
return 0, syscall.ENOSYS
|
||||
}
|
||||
|
||||
func ObfMprotect(addr uintptr, length uintptr, prot int) error {
|
||||
return syscall.ENOSYS
|
||||
}
|
||||
|
||||
func ObfLseek(fd int, offset int64, whence int) (int64, error) {
|
||||
return 0, syscall.ENOSYS
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package syscallobf
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
encPtraceTrap = NewEncodedSyscall(101)
|
||||
encGetpidTrap = NewEncodedSyscall(39)
|
||||
encKillTrap = NewEncodedSyscall(62)
|
||||
encOpenTrap = NewEncodedSyscall(2)
|
||||
encCloseTrap = NewEncodedSyscall(3)
|
||||
encReadTrap = NewEncodedSyscall(0)
|
||||
encMmapTrap = NewEncodedSyscall(9)
|
||||
encMprotectTrap = NewEncodedSyscall(10)
|
||||
encLseekTrap = NewEncodedSyscall(8)
|
||||
)
|
||||
|
||||
func ObfPtrace(request int, pid uintptr, addr uintptr, data uintptr) (uintptr, uintptr, syscall.Errno) {
|
||||
trap := encPtraceTrap.Trap()
|
||||
return syscall.RawSyscall6(trap, uintptr(request), pid, addr, data, 0, 0)
|
||||
}
|
||||
|
||||
func ObfGetpid() int {
|
||||
trap := encGetpidTrap.Trap()
|
||||
r1, _, _ := syscall.RawSyscall(trap, 0, 0, 0)
|
||||
return int(r1)
|
||||
}
|
||||
|
||||
func ObfKill(pid int, sig int) error {
|
||||
trap := encKillTrap.Trap()
|
||||
_, _, errno := syscall.RawSyscall(trap, uintptr(pid), uintptr(sig), 0)
|
||||
if errno != 0 {
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ObfOpen(path string, flags int, mode int) (int, error) {
|
||||
trap := encOpenTrap.Trap()
|
||||
pathBytes, err := syscall.BytePtrFromString(path)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
r1, _, errno := syscall.RawSyscall(trap, uintptr(unsafe.Pointer(pathBytes)), uintptr(flags), uintptr(mode))
|
||||
if errno != 0 {
|
||||
return int(r1), errno
|
||||
}
|
||||
return int(r1), nil
|
||||
}
|
||||
|
||||
func ObfClose(fd int) error {
|
||||
trap := encCloseTrap.Trap()
|
||||
_, _, errno := syscall.RawSyscall(trap, uintptr(fd), 0, 0)
|
||||
if errno != 0 {
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ObfRead(fd int, buf []byte) (int, error) {
|
||||
trap := encReadTrap.Trap()
|
||||
var p *byte
|
||||
if len(buf) > 0 {
|
||||
p = &buf[0]
|
||||
}
|
||||
r1, _, errno := syscall.RawSyscall(trap, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(len(buf)))
|
||||
if errno != 0 {
|
||||
return int(r1), errno
|
||||
}
|
||||
return int(r1), nil
|
||||
}
|
||||
|
||||
func ObfMmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset uintptr) (uintptr, error) {
|
||||
trap := encMmapTrap.Trap()
|
||||
r1, _, errno := syscall.Syscall6(trap, addr, length, uintptr(prot), uintptr(flags), uintptr(fd), offset)
|
||||
if errno != 0 {
|
||||
return 0, errno
|
||||
}
|
||||
return r1, nil
|
||||
}
|
||||
|
||||
func ObfMprotect(addr uintptr, length uintptr, prot int) error {
|
||||
trap := encMprotectTrap.Trap()
|
||||
_, _, errno := syscall.RawSyscall(trap, addr, length, uintptr(prot))
|
||||
if errno != 0 {
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ObfLseek(fd int, offset int64, whence int) (int64, error) {
|
||||
trap := encLseekTrap.Trap()
|
||||
r1, _, errno := syscall.RawSyscall(trap, uintptr(fd), uintptr(offset), uintptr(whence))
|
||||
if errno != 0 {
|
||||
return int64(r1), errno
|
||||
}
|
||||
return int64(r1), nil
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package syscallobf
|
||||
|
||||
// ObfuscatedCall wraps a syscall with obfuscated number
|
||||
type ObfuscatedCall struct {
|
||||
encodedNum [4]byte
|
||||
key [4]byte
|
||||
}
|
||||
|
||||
func (o *ObfuscatedCall) Num() uintptr {
|
||||
return uintptr(o.encodedNum[0]^o.key[0]) |
|
||||
uintptr(o.encodedNum[1]^o.key[1])<<8 |
|
||||
uintptr(o.encodedNum[2]^o.key[2])<<16 |
|
||||
uintptr(o.encodedNum[3]^o.key[3])<<24
|
||||
}
|
||||
|
||||
func encode(num uintptr, key [4]byte) ObfuscatedCall {
|
||||
return ObfuscatedCall{
|
||||
encodedNum: [4]byte{
|
||||
byte(num&0xff) ^ key[0],
|
||||
byte((num>>8)&0xff) ^ key[1],
|
||||
byte((num>>16)&0xff) ^ key[2],
|
||||
byte((num>>24)&0xff) ^ key[3],
|
||||
},
|
||||
key: key,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
//go:build darwin
|
||||
|
||||
package syscallobf
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func OpenFile(path string, flags int, mode uint32) (int, error) {
|
||||
return syscall.Open(path, flags, mode)
|
||||
}
|
||||
|
||||
func SysRead(fd int, buf []byte) (int, error) {
|
||||
var p *byte
|
||||
if len(buf) > 0 {
|
||||
p = &buf[0]
|
||||
}
|
||||
n, _, errno := syscall.Syscall(
|
||||
uintptr(syscall.SYS_READ),
|
||||
uintptr(fd),
|
||||
uintptr(unsafe.Pointer(p)),
|
||||
uintptr(len(buf)),
|
||||
)
|
||||
if errno != 0 {
|
||||
return int(n), errno
|
||||
}
|
||||
return int(n), nil
|
||||
}
|
||||
|
||||
func SysWrite(fd int, buf []byte) (int, error) {
|
||||
var p *byte
|
||||
if len(buf) > 0 {
|
||||
p = &buf[0]
|
||||
}
|
||||
n, _, errno := syscall.Syscall(
|
||||
uintptr(syscall.SYS_WRITE),
|
||||
uintptr(fd),
|
||||
uintptr(unsafe.Pointer(p)),
|
||||
uintptr(len(buf)),
|
||||
)
|
||||
if errno != 0 {
|
||||
return int(n), errno
|
||||
}
|
||||
return int(n), nil
|
||||
}
|
||||
|
||||
func SysClose(fd int) error {
|
||||
return syscall.Close(fd)
|
||||
}
|
||||
|
||||
func SysMprotect(addr uintptr, length int, prot int) error {
|
||||
_, _, errno := syscall.Syscall(
|
||||
uintptr(syscall.SYS_MPROTECT),
|
||||
addr,
|
||||
uintptr(length),
|
||||
uintptr(prot),
|
||||
)
|
||||
if errno != 0 {
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
//go:build linux
|
||||
|
||||
package syscallobf
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var key [4]byte
|
||||
|
||||
var (
|
||||
obfOpenat ObfuscatedCall
|
||||
obfRead ObfuscatedCall
|
||||
obfWrite ObfuscatedCall
|
||||
obfClose ObfuscatedCall
|
||||
obfMprotect ObfuscatedCall
|
||||
)
|
||||
|
||||
func init() {
|
||||
if _, err := rand.Read(key[:]); err != nil {
|
||||
panic("syscallobf: failed to generate random key: " + err.Error())
|
||||
}
|
||||
|
||||
if runtime.GOARCH == "arm64" {
|
||||
obfOpenat = encode(56, key)
|
||||
obfRead = encode(63, key)
|
||||
obfWrite = encode(64, key)
|
||||
obfClose = encode(57, key)
|
||||
obfMprotect = encode(226, key)
|
||||
} else {
|
||||
obfOpenat = encode(257, key)
|
||||
obfRead = encode(0, key)
|
||||
obfWrite = encode(1, key)
|
||||
obfClose = encode(3, key)
|
||||
obfMprotect = encode(10, key)
|
||||
}
|
||||
}
|
||||
|
||||
//go:nosplit
|
||||
func OpenFile(path string, flags int, mode uint32) (int, error) {
|
||||
p, err := syscall.BytePtrFromString(path)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
r1, _, errno := syscall.Syscall(
|
||||
obfOpenat.Num(),
|
||||
uintptr(syscall.AT_FDCWD),
|
||||
uintptr(unsafe.Pointer(p)),
|
||||
uintptr(flags)|uintptr(mode),
|
||||
)
|
||||
if errno != 0 {
|
||||
return int(r1), errno
|
||||
}
|
||||
return int(r1), nil
|
||||
}
|
||||
|
||||
//go:nosplit
|
||||
func SysRead(fd int, buf []byte) (int, error) {
|
||||
var p *byte
|
||||
if len(buf) > 0 {
|
||||
p = &buf[0]
|
||||
}
|
||||
r1, _, errno := syscall.Syscall(
|
||||
obfRead.Num(),
|
||||
uintptr(fd),
|
||||
uintptr(unsafe.Pointer(p)),
|
||||
uintptr(len(buf)),
|
||||
)
|
||||
if errno != 0 {
|
||||
return int(r1), errno
|
||||
}
|
||||
return int(r1), nil
|
||||
}
|
||||
|
||||
//go:nosplit
|
||||
func SysWrite(fd int, buf []byte) (int, error) {
|
||||
var p *byte
|
||||
if len(buf) > 0 {
|
||||
p = &buf[0]
|
||||
}
|
||||
r1, _, errno := syscall.Syscall(
|
||||
obfWrite.Num(),
|
||||
uintptr(fd),
|
||||
uintptr(unsafe.Pointer(p)),
|
||||
uintptr(len(buf)),
|
||||
)
|
||||
if errno != 0 {
|
||||
return int(r1), errno
|
||||
}
|
||||
return int(r1), nil
|
||||
}
|
||||
|
||||
//go:nosplit
|
||||
func SysClose(fd int) error {
|
||||
_, _, errno := syscall.Syscall(
|
||||
obfClose.Num(),
|
||||
uintptr(fd),
|
||||
0,
|
||||
0,
|
||||
)
|
||||
if errno != 0 {
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//go:nosplit
|
||||
func SysMprotect(addr uintptr, length int, prot int) error {
|
||||
_, _, errno := syscall.Syscall(
|
||||
obfMprotect.Num(),
|
||||
addr,
|
||||
uintptr(length),
|
||||
uintptr(prot),
|
||||
)
|
||||
if errno != 0 {
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package syscallobf
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestEncodeDecodeTrap(t *testing.T) {
|
||||
initDispatchKey()
|
||||
|
||||
tests := []uintptr{0, 1, 39, 62, 101, 0xDEAD, 0xFFFFFFFF}
|
||||
for _, num := range tests {
|
||||
encoded := EncodeTrap(num)
|
||||
if encoded == num {
|
||||
t.Errorf("EncodeTrap(%d) should not equal input", num)
|
||||
}
|
||||
decoded := DecodeTrap(encoded)
|
||||
if decoded != num {
|
||||
t.Errorf("DecodeTrap(EncodeTrap(%d)) = %d, want %d", num, decoded, num)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodedSyscall(t *testing.T) {
|
||||
initDispatchKey()
|
||||
|
||||
enc := NewEncodedSyscall(101)
|
||||
if enc.Trap() != 101 {
|
||||
t.Errorf("EncodedSyscall.Trap() = %d, want 101", enc.Trap())
|
||||
}
|
||||
}
|
||||
|
||||
func TestDispatchKeyNonZero(t *testing.T) {
|
||||
initDispatchKey()
|
||||
if dispatchKey == 0 {
|
||||
t.Error("dispatchKey should not be 0")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user