-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathasm.go
138 lines (113 loc) · 2.99 KB
/
asm.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package gopwn
import (
"errors"
"fmt"
"github.com/keystone-engine/keystone/bindings/go/keystone"
"github.com/knightsc/gapstone"
)
type Assembler struct {
ks *keystone.Keystone
}
func NewAssembler(arch Arch) (*Assembler, error) {
var ks *keystone.Keystone
var err error
switch arch {
case ARCH_AMD64:
ks, err = keystone.New(keystone.ARCH_X86, keystone.MODE_64)
case ARCH_I386:
ks, err = keystone.New(keystone.ARCH_X86, keystone.MODE_32)
case ARCH_AARCH64:
ks, err = keystone.New(keystone.ARCH_ARM, keystone.MODE_64)
case ARCH_ARM:
ks, err = keystone.New(keystone.ARCH_ARM, keystone.MODE_32)
default:
return nil, errors.New("unsupported machine type")
}
if err != nil {
return nil, err
}
if err := ks.Option(keystone.OPT_SYNTAX, keystone.OPT_SYNTAX_INTEL); err != nil {
return nil, err
}
return &Assembler{ks: ks}, nil
}
func (a *Assembler) Assemble(assembly string) ([]byte, error) {
insn, _, ok := a.ks.Assemble(assembly, 0)
if !ok {
return nil, errors.New("could not assemble instruction")
}
return insn, nil
}
func (a *Assembler) Close() error {
return a.ks.Close()
}
func Assemble(assembly string, arch Arch) ([]byte, error) {
ks, err := NewAssembler(arch)
if err != nil {
return nil, err
}
defer ks.Close()
return ks.Assemble(assembly)
}
func AssembleAMD64(assembly string) ([]byte, error) {
return Assemble(assembly, ARCH_AMD64)
}
func AssembleI386(assembly string) ([]byte, error) {
return Assemble(assembly, ARCH_I386)
}
type Disassembler struct {
engine gapstone.Engine
}
func NewDisassembler(arch Arch) (*Disassembler, error) {
archs := map[Arch]int{
ARCH_AMD64: gapstone.CS_ARCH_X86,
ARCH_I386: gapstone.CS_ARCH_X86,
ARCH_ARM: gapstone.CS_ARCH_ARM,
ARCH_AARCH64: gapstone.CS_ARCH_ARM64,
}
modes := map[Arch]int{
ARCH_AMD64: gapstone.CS_MODE_64,
ARCH_I386: gapstone.CS_MODE_32,
ARCH_ARM: gapstone.CS_MODE_ARM,
ARCH_AARCH64: gapstone.CS_MODE_ARM,
}
engine, err := gapstone.New(archs[arch], modes[arch])
if err != nil {
return nil, err
}
if err := engine.SetOption(gapstone.CS_OPT_SYNTAX, gapstone.CS_OPT_SYNTAX_INTEL); err != nil {
return nil, err
}
return &Disassembler{engine: engine}, nil
}
func (d *Disassembler) Disam(data []byte, vma uint64) (string, error) {
insns, err := d.engine.Disasm(data, vma, 0)
if err != nil {
return "", err
}
var output string
for i, insn := range insns {
output += fmt.Sprintf("0x%-12x% -30x%s %s", insn.Address, insn.Bytes, insn.Mnemonic, insn.OpStr)
if i < (len(insns) - 1) {
output += "\n"
}
}
return output, nil
}
func (d *Disassembler) Close() error {
return d.engine.Close()
}
func Disam(data []byte, vma uint64, arch Arch) (string, error) {
engine, err := NewDisassembler(arch)
if err != nil {
return "", err
}
defer engine.Close()
return engine.Disam(data, vma)
}
func DisamAMD64(data []byte, vma uint64) (string, error) {
return Disam(data, vma, ARCH_AMD64)
}
func DisamI386(data []byte, vma uint64) (string, error) {
return Disam(data, vma, ARCH_I386)
}