在Go中执行字节数组

Pel*_*eus 5 function-pointers go shellcode

我正在尝试在Go程序中执行shellcode,类似于如何使用其他语言.

例1 - C程序中的Shellcode

示例2 - http://www.debasish.in/2012/04/execute-shellcode-using-python.html

所有方法都有大致相似的技术 - 通过OS特定的分配(mmap,virtualalloc等)将shellcode分配给可执行内存,然后通过在执行之前创建指向该位置的函数指针来执行代码.

这是我在Go中执行相同操作的可怕hacky示例.shellcode在传递给函数之前对它执行了操作,所以它的格式为[]字节是固定的.说mmap期望传递文件描述符,这就是存在可怕的"写入tmp文件"部分的原因.

func osxExec(shellcode []byte) {
    f, err := os.Create("data/shellcode.tmp")
    if err != nil {
        fmt.Println(err)
    }
    defer f.Close()
    _,_ = f.Write(shellcode)
    f.Sync()

    b, err := syscall.Mmap(int(f.Fd()), 0, len(shellcode), syscall.PROT_READ|syscall.PROT_WRITE|syscall.PROT_EXEC, syscall.MAP_SHARED)
    if err != nil {
        fmt.Println(err)
    }

    fmt.Printf("%p", b)
}
Run Code Online (Sandbox Code Playgroud)

在代码的最后,我有一个指针(切片?)代码,我认为是可执行内存 - 但我不知道如何将此地址转换为函数指针执行.我询问了一些IRC频道,但有人认为这可能是不可能的.

任何帮助是极大的赞赏.

干杯.

Jim*_*imB 6

首先,您根本不需要(当前)使用mmap,因为内存是可执行的.如果确实需要mmap,可以使用匿名内存并放弃临时文件:

b, e := syscall.Mmap(0, 0, len(shellcode), syscall.PROT_READ|syscall.PROT_WRITE|syscall.PROT_EXEC, syscall.MAP_ANON)
copy(b, shellcode)
Run Code Online (Sandbox Code Playgroud)

否则,您可以尝试shellcode直接使用,因为它已经由连续数组支持.

至于将字节转换shellcode为函数,来自C的模拟看起来像:

f := *(*func() int)(unsafe.Pointer(&d[0]))
Run Code Online (Sandbox Code Playgroud)

它创建一个名为的函数值f,然后可以像普通函数一样调用它.

如果shell代码不是专门为Go制作的,并且您需要从C堆栈中调用它,那么使用cgo直接在C中执行它会更容易.

/*
call(char *code) {
    int (*ret)() = (int(*)())code;
    ret();
}
*/
import "C"

func main() {
    ...
    // at your call site, you can send the shellcode directly to the C 
    // function by converting it to a pointer of the correct type.
    C.call((*C.char)(unsafe.Pointer(&shellcode[0])))
Run Code Online (Sandbox Code Playgroud)


Did*_*zia 4

有多种方法可以做到这一点,尽管我自己没有测试过。

您可能想看看https://github.com/nelhage/gojit/blob/master/jit.go 它实现了基于 cgo 的解决方案(更安全,但速度较慢),以及基于直接的解决方案称呼。查看所有与构建相关的函数。