这里假设大家对于mmap都比较熟悉了,不熟悉的可以man 2 mmap来查看相关描述,熟悉了之后往下看,并且通过一个例子,来理解其中参数的含义。
- 首先我们编写一个简单的自增函数
package inc
func inc(n int) int {
return n + 1
}
然后使用如下命令得到编译后代码
go tool compile -S -N inc.go
接着使用转储指令
go tool objdump -S inc.o
在终端可以得到如下:
TEXT "".inc(SB) gofile../home/ai/offer/inc/inc.go
func inc(n int) int {
0x2ba 48c744241000000000 MOVQ $0x0, 0x10(SP)
return n + 1
0x2c3 488b442408 MOVQ 0x8(SP), AX
0x2c8 48ffc0 INCQ AX
0x2cb 4889442410 MOVQ AX, 0x10(SP)
0x2d0 c3 RET
然后我们将后续的地址放入一个字节切片当中:
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,
}
// 其中字节切片中的内容就是上面的地址,用十六进制来表示
至此我们之前的工作已经做完了,然后开始我们的重头戏mmap系统调用,我们在虚拟内存当中分配一段空间,默认是以os.Getpagesize()大小为基本单位。
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,
}
// syscall mmap
f, err := os.OpenFile("content.txt", os.O_RDWR|os.O_CREATE, 0777)
f.Truncate(100)
defer f.Close()
if nil != err {
log.Fatalln(err)
}
memory, err := syscall.Mmap(int(f.Fd()), 0, 100, syscall.PROT_READ|syscall.PROT_EXEC|syscall.PROT_WRITE, syscall.MAP_SHARED)
defer syscall.Munmap(memory)
copy(memory, code)
//syscall.Sync()
if nil != err {
log.Fatalln(err)
}
memPtr := &memory
inc := *(*func(int) int)(unsafe.Pointer(&memPtr))
ret := inc(1)
fmt.Println("ret is", ret)
todo: