我试图在Go程序中执行shellcode,类似于使用其他语言执行它的方式。
示例1 - Shellcode in C program
示例2 - http://www.debasish.in/2012/04/execute-shellcode-using-python.html
所有方法都有类似的技术 - 通过操作系统特定的分配(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)
}
在代码的最后,我有一个指针(切片?)到我认为是可执行内存的代码 - 但我不知道如何将这个地址转换为函数指针执行。我询问了一些IRC频道,但有人认为这可能是不可能的。
非常感谢任何帮助。
干杯。
答案 0 :(得分:5)
首先,您根本不需要(当前)使用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)
否则,您可以尝试直接使用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])))
答案 1 :(得分:4)
有多种方法可以做到,但我自己没有测试过。
您可能需要查看https://github.com/nelhage/gojit/blob/master/jit.go 它实现了基于cgo的解决方案(更安全,但速度更慢),以及基于直接呼叫的解决方案。查看所有与构建相关的函数。
答案 2 :(得分:0)
我试图了解 mmap
PROT_EXEC
如何在 Go
中工作,但遇到了同样的问题。
我很难将 []byte
正确地转换为函数。这并不像这里的一些答案所说的那么明显。
我想出了一个工作示例,说明如何使用名为 mmap-go 的更高级别的 mmap
库来执行此操作。在这个例子中,我们有一个函数的可执行代码,它为传递的参数加一。
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])