为了账号安全,请及时绑定邮箱和手机立即绑定

在 Go 中执行字节数组

在 Go 中执行字节数组

Go
HUWWW 2021-10-04 18:13:14
我正在尝试在 Go 程序中执行 shellcode,类似于使用其他语言执行此操作的方式。所有方法都有大致相似的技术——通过操作系统特定的分配(mmap、virtualalloc 等)将 shellcode 分配给可执行内存,然后通过在执行之前创建一个指向该位置的函数指针来执行代码。这是我在 Go 中执行相同操作的可怕 hacky 示例。shellcode 在传递给函数之前对其进行了操作,因此它的格式为 []byte 是固定的。说 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)}在代码的末尾,我有一个指向代码的指针(切片?),我认为是可执行内存 - 但我不知道如何将此地址转换为函数指针以供执行。我在一些 IRC 频道上询问过,但有人建议这可能是不可能的。任何帮助是极大的赞赏。
查看完整描述

3 回答

?
桃花长相依

TA贡献1860条经验 获得超8个赞

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


b, e := syscall.Mmap(0, 0, len(shellcode), syscall.PROT_READ|syscall.PROT_WRITE|syscall.PROT_EXEC, syscall.MAP_ANON)

copy(b, shellcode)

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


至于将字节转换shellcode为函数,C 中的模拟将如下所示:


f := *(*func() int)(unsafe.Pointer(&d[0]))

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


如果 shellcode 不是专门为 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])))


查看完整回答
反对 回复 2021-10-04
?
Smart猫小萌

TA贡献1911条经验 获得超7个赞

我试图了解如何mmap PROT_EXEC在 中工作Go,并提出了同样的问题。


我很难[]byte将 正确转换为函数。它并不像这里的一些答案所说的那么明显。


我想出了一个工作示例,说明如何使用mmap名为mmap-go的更高级别的库来执行此操作。在这个例子中,我们有一个函数的可执行代码,它为传递的参数增加 1。


code := []byte{

    0x48, 0xc7, 0x44, 0x24, 0x10, 0x00, 0x00, 0x00, 0x00,

    0x48, 0x8b, 0x44, 0x24, 0x08,

    0x48, 0xff, 0xc0,

    0x48, 0x89, 0x44, 0x24, 0x10,

    0xc3,

}


memory, err := mmap.MapRegion(nil, len(code), mmap.EXEC|mmap.RDWR, mmap.ANON, 0)

if err != nil {

    panic(err)

}


copy(memory, code)


memory_ptr := &memory

ptr := unsafe.Pointer(&memory_ptr)

f := *(*func(int) int)(ptr)


fmt.Println(f(10)) // Prints 11

我认为unsafe.Pointer(&memory[0])会像答案之一所暗示的那样解决我的问题。但是通过这样做,您无法将地址转换为正确地址中的可调用函数。诀窍是更进一步,做到这一点


memory_ptr := &memory

ptr := unsafe.Pointer(&memory_ptr)

代替


f := *(*func(int) int)(&memory[0])


查看完整回答
反对 回复 2021-10-04
  • 3 回答
  • 0 关注
  • 294 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信