twitchyliquid64/golang-asm
GitHub: twitchyliquid64/golang-asm
将 Go 编译器内部的汇编器封装为独立库,支持在 Go 程序中以编程方式构建和汇编 x86-64 指令。
Stars: 210 | Forks: 15
# golang-asm
这是 Go 编译器汇编器的一个镜像,其导入路径已被重写,使其能够作为独立的库来使用。
许可证遵循 Go 项目。
# 状态
可以使用,但你需要深入研究汇编器的 godoc,才能弄清楚该如何设置 `obj.Prog` 的不同参数来生成特定的指令。
# 示例
演示了在 x86-64 上汇编 NOP 和 ADD 指令。
```
package main
import (
"fmt"
asm "github.com/twitchyliquid64/golang-asm"
"github.com/twitchyliquid64/golang-asm/obj"
"github.com/twitchyliquid64/golang-asm/obj/x86"
)
func noop(builder *asm.Builder) *obj.Prog {
prog := builder.NewProg()
prog.As = x86.ANOPL
prog.From.Type = obj.TYPE_REG
prog.From.Reg = x86.REG_AX
return prog
}
func addImmediateByte(builder *asm.Builder, in int32) *obj.Prog {
prog := builder.NewProg()
prog.As = x86.AADDB
prog.To.Type = obj.TYPE_REG
prog.To.Reg = x86.REG_AL
prog.From.Type = obj.TYPE_CONST
prog.From.Offset = int64(in)
return prog
}
func movImmediateByte(builder *asm.Builder, reg int16, in int32) *obj.Prog {
prog := builder.NewProg()
prog.As = x86.AMOVB
prog.To.Type = obj.TYPE_REG
prog.To.Reg = reg
prog.From.Type = obj.TYPE_CONST
prog.From.Offset = int64(in)
return prog
}
func main() {
b, _ := asm.NewBuilder("amd64", 64)
b.AddInstruction(noop(b))
b.AddInstruction(movImmediateByte(b, x86.REG_AL, 16))
b.AddInstruction(addImmediateByte(b, 16))
fmt.Printf("Bin: %x\n", b.Assemble())
}
```
# 研究 `obj.Prog` 的参数
我花了一些时间才弄清楚这些,所以我在这里记录一下。
## 使用这些参考资料
* `obj.Prog` - [godoc](https://godoc.org/github.com/golang/go/src/cmd/internal/obj#Prog)
* 一些指令(如 NOP、JMP)是跨平台抽象的,可以在[这里](https://godoc.org/github.com/golang/go/src/cmd/internal/obj#As)找到
* (针对 amd64)`x86 pkg-constants` - [寄存器和指令](https://godoc.org/github.com/golang/go/src/cmd/internal/obj/x86#pkg-constant)
## 指令常量具有命名规则
指令在相关架构的包中被定义为常量,它们带有 'A' 前缀和表示大小的后缀。
例如,用于传输 64 位数据的 MOV 指令是 `AMOVQ`(至少在 amd64 中是这样)。
## 在 go 源码中搜索特定指令的使用方式
例如,如果我想弄清楚如何生成 64 位的 MOV 指令,我会在 GitHub 上搜索 go 源码中的 `AMOVQ` 或 `x86.AMOVQ`。通常,你会找到几个编译器后端填充 `obj.Prog` 结构体的示例,然后你就可以照着它们做了。
标签:EVTX分析, Golang, 代码生成, 安全编程, 底层开发, 日志审计, 汇编器, 渗透测试工具, 编译器组件