-
Notifications
You must be signed in to change notification settings - Fork 15
/
shellcode.go
197 lines (170 loc) · 4.95 KB
/
shellcode.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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
package api
import (
"bufio"
"bytes"
"encoding/binary"
"log"
"net"
)
// Os - Operating System Options Flag
type Os string
// Arch - Architecture Options Flag
type Arch string
// Bits - Bit Width Options Flag
type Bits string
const (
// Operating System Options
// Windows flag for Windows OS
Windows Os = "windows"
// Linux flag for Linux OS
Linux Os = "linux"
// FreeBSD flag for FreeBSD OS
FreeBSD Os = "freebsd"
// Darwin flag for Darwin / Mac OS
Darwin Os = "darwin"
// Architecture Options
// Intel32 flag for Intel/AMD 32 bit architectures
Intel32 Arch = "x32"
// Intel64 flag for Intel/AMD 64 bit architectures
Intel64 Arch = "x64"
// Intel32y64 flag for Intel/AMD 32+64 bit combo shellcodes
Intel32y64 Arch = "x32x64"
// Arm flag for Arm 32 bit shellcodes
Arm Arch = "arm"
)
var (
// Arches - list of human readable architecture names
Arches []string = []string{"x32", "x64", "x32x64", "arm"}
// Oses - list of human readable OS names
Oses []string = []string{"windows", "linux", "darwin"}
)
// Generator - type for a shellcode generator
type Generator struct {
Os Os
Arch Arch
Bit Bits
Name string
Function func(Parameters) ([]byte, error)
}
var generators []Generator
// RegisterShellCode - registers a shellcode generating function with the registry
func RegisterShellCode(
os Os,
arch Arch,
name string,
fx func(Parameters) ([]byte, error)) {
generators = append(generators, Generator{Os: os, Arch: arch, Name: name, Function: fx})
}
// LookupShellCode - looks up shellcode by OS and architecture
func LookupShellCode(os Os, arch Arch) []Generator {
var ret []Generator
for _, g := range generators {
if g.Os == os && g.Arch == arch {
ret = append(ret, g)
}
}
return ret
}
// PrintShellCodes - looks up shellcode by OS and architecture and prints the output
func PrintShellCodes(os Os, arch Arch) {
gens := LookupShellCode(os, arch)
for _, g := range gens {
log.Printf("%+v\n", g)
}
}
// PackUint16 - packs a jump address
func PackUint16(addr uint16) (string, error) {
buf := new(bytes.Buffer)
err := binary.Write(buf, binary.LittleEndian, addr)
if err != nil {
return "", err
}
return string(buf.Bytes()), nil
}
// PackUint32 - packs a jump address
func PackUint32(addr uint32) (string, error) {
buf := new(bytes.Buffer)
err := binary.Write(buf, binary.LittleEndian, addr)
if err != nil {
return "", err
}
return string(buf.Bytes()), nil
}
// PackUint64 - packs a jump address
func PackUint64(addr uint64) (string, error) {
buf := new(bytes.Buffer)
err := binary.Write(buf, binary.LittleEndian, addr)
if err != nil {
return "", err
}
return string(buf.Bytes()), nil
}
// PackPort - packs a port
func PackPort(port uint16) (string, error) {
buf := new(bytes.Buffer)
err := binary.Write(buf, binary.BigEndian, port)
if err != nil {
return "", err
}
return string(buf.Bytes()), nil
}
// PackIP - packs an IP
func PackIP(ip string) string {
ipaddr := net.ParseIP(ip).To4()
return string(ipaddr)
}
// ApplyPrefixForkIntel64 - Prepends instructions to fork and have the parent jump to a relative 32-bit address (the entryJump argument)
// Intel x64 Linux version
//
// Returns the resulting shellcode
func ApplyPrefixForkIntel64(shellcode []byte, entryJump uint32, byteOrder binary.ByteOrder) []byte {
/*
Disassembly:
0: b8 02 00 00 00 mov eax,0x2
5: cd 80 int 0x80
7: 83 f8 00 cmp eax,0x0
a: 0f 85 xx xx xx xx jne <entryJump>
*/
prefix := bytes.NewBuffer([]byte{0xB8, 0x02, 0x00, 0x00, 0x00, 0xCD, 0x80, 0x83, 0xF8,
0x00, 0x0F, 0x85})
w := bufio.NewWriter(prefix)
binary.Write(w, byteOrder, entryJump)
binary.Write(w, byteOrder, shellcode)
w.Flush()
return prefix.Bytes()
}
// ApplySuffixJmpIntel64 - Appends instructions to jump to the original entryPoint (the parameter)
// Intel x64 Linux version
//
// Returns the resulting shellcode
func ApplySuffixJmpIntel64(shellcode []byte, shellcodeVaddr uint32, entryPoint uint32, byteOrder binary.ByteOrder) []byte {
/*
Disassembly:
0: e9 00 00 00 00 jmp <entryJump>
*/
retval := append(shellcode, 0xe9)
buf := bytes.NewBuffer(retval)
w := bufio.NewWriter(buf)
entryJump := entryPoint - (shellcodeVaddr + 5) - uint32(len(shellcode))
binary.Write(w, byteOrder, entryJump)
w.Flush()
return buf.Bytes()
}
// ApplySuffixJmpIntel32 - Appends instructions to jump to the original entryPoint (the parameter)
// Intel x32 Windows version
//
// Returns the resulting shellcode
func ApplySuffixJmpIntel32(shellcode []byte, shellcodeVaddr uint32, entryPoint uint32, byteOrder binary.ByteOrder) []byte {
/*
Disassembly:
0: 68 push
1: xx xx xx xx original entry point (make sure to add the imageBase)
5: ff 24 24 jmp [esp]
*/
retval := append(shellcode, 0x68)
buf := bytes.NewBuffer(retval)
w := bufio.NewWriter(buf)
binary.Write(w, byteOrder, entryPoint)
w.Flush()
return append(buf.Bytes(), 0xff, 0x24, 0x24)
}