mirror of
				https://github.com/go-delve/delve.git
				synced 2025-10-31 02:36:18 +08:00 
			
		
		
		
	proc: replace cgo with syscalls on windows
Unrelated to conversion, I have also changed (*Thread).readMemory to return only first count bytes of memory just as advised by ReadProcessMemory. Fixes #409 Fixes #412 Fixes #416
This commit is contained in:
		| @ -1,7 +1,5 @@ | |||||||
| package proc | package proc | ||||||
|  |  | ||||||
| // #include "windows.h" |  | ||||||
| import "C" |  | ||||||
| import ( | import ( | ||||||
| 	"debug/gosym" | 	"debug/gosym" | ||||||
| 	"debug/pe" | 	"debug/pe" | ||||||
| @ -30,7 +28,7 @@ const ( | |||||||
|  |  | ||||||
| // OSProcessDetails holds Windows specific information. | // OSProcessDetails holds Windows specific information. | ||||||
| type OSProcessDetails struct { | type OSProcessDetails struct { | ||||||
| 	hProcess    sys.Handle | 	hProcess    syscall.Handle | ||||||
| 	breakThread int | 	breakThread int | ||||||
| } | } | ||||||
|  |  | ||||||
| @ -121,17 +119,13 @@ func (dbp *Process) Kill() error { | |||||||
| 	// TODO: Should not have to ignore failures here, | 	// TODO: Should not have to ignore failures here, | ||||||
| 	// but some tests appear to Kill twice causing | 	// but some tests appear to Kill twice causing | ||||||
| 	// this to fail on second attempt. | 	// this to fail on second attempt. | ||||||
| 	_ = C.TerminateProcess(C.HANDLE(dbp.os.hProcess), 1) | 	_ = syscall.TerminateProcess(dbp.os.hProcess, 1) | ||||||
| 	dbp.exited = true | 	dbp.exited = true | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (dbp *Process) requestManualStop() error { | func (dbp *Process) requestManualStop() error { | ||||||
| 	res := C.DebugBreakProcess(C.HANDLE(dbp.os.hProcess)) | 	return _DebugBreakProcess(dbp.os.hProcess) | ||||||
| 	if res == C.FALSE { |  | ||||||
| 		return fmt.Errorf("failed to break process %d", dbp.Pid) |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func (dbp *Process) updateThreadList() error { | func (dbp *Process) updateThreadList() error { | ||||||
| @ -140,7 +134,7 @@ func (dbp *Process) updateThreadList() error { | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (dbp *Process) addThread(hThread sys.Handle, threadID int, attach bool) (*Thread, error) { | func (dbp *Process) addThread(hThread syscall.Handle, threadID int, attach bool) (*Thread, error) { | ||||||
| 	if thread, ok := dbp.Threads[threadID]; ok { | 	if thread, ok := dbp.Threads[threadID]; ok { | ||||||
| 		return thread, nil | 		return thread, nil | ||||||
| 	} | 	} | ||||||
| @ -341,76 +335,76 @@ func dwarfFromPE(f *pe.File) (*dwarf.Data, error) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (dbp *Process) waitForDebugEvent() (threadID, exitCode int, err error) { | func (dbp *Process) waitForDebugEvent() (threadID, exitCode int, err error) { | ||||||
| 	var debugEvent C.DEBUG_EVENT | 	var debugEvent _DEBUG_EVENT | ||||||
| 	shouldExit := false | 	shouldExit := false | ||||||
| 	for { | 	for { | ||||||
| 		// Wait for a debug event... | 		// Wait for a debug event... | ||||||
| 		res := C.WaitForDebugEvent(&debugEvent, C.INFINITE) | 		err := _WaitForDebugEvent(&debugEvent, syscall.INFINITE) | ||||||
| 		if res == C.FALSE { | 		if err != nil { | ||||||
| 			return 0, 0, fmt.Errorf("could not WaitForDebugEvent") | 			return 0, 0, err | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// ... handle each event kind ... | 		// ... handle each event kind ... | ||||||
| 		unionPtr := unsafe.Pointer(&debugEvent.u[0]) | 		unionPtr := unsafe.Pointer(&debugEvent.U[0]) | ||||||
| 		switch debugEvent.dwDebugEventCode { | 		switch debugEvent.DebugEventCode { | ||||||
| 		case C.CREATE_PROCESS_DEBUG_EVENT: | 		case _CREATE_PROCESS_DEBUG_EVENT: | ||||||
| 			debugInfo := (*C.CREATE_PROCESS_DEBUG_INFO)(unionPtr) | 			debugInfo := (*_CREATE_PROCESS_DEBUG_INFO)(unionPtr) | ||||||
| 			hFile := debugInfo.hFile | 			hFile := debugInfo.File | ||||||
| 			if hFile != C.HANDLE(uintptr(0)) /* NULL */ && hFile != C.HANDLE(uintptr(0xFFFFFFFFFFFFFFFF)) /* INVALID_HANDLE_VALUE */ { | 			if hFile != 0 && hFile != syscall.InvalidHandle { | ||||||
| 				res = C.CloseHandle(hFile) | 				err = syscall.CloseHandle(hFile) | ||||||
| 				if res == C.FALSE { | 				if err != nil { | ||||||
| 					return 0, 0, fmt.Errorf("could not close create process file handle") | 					return 0, 0, err | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			dbp.os.hProcess = sys.Handle(debugInfo.hProcess) | 			dbp.os.hProcess = debugInfo.Process | ||||||
| 			_, err = dbp.addThread(sys.Handle(debugInfo.hThread), int(debugEvent.dwThreadId), false) | 			_, err = dbp.addThread(debugInfo.Thread, int(debugEvent.ThreadId), false) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				return 0, 0, err | 				return 0, 0, err | ||||||
| 			} | 			} | ||||||
| 			break | 			break | ||||||
| 		case C.CREATE_THREAD_DEBUG_EVENT: | 		case _CREATE_THREAD_DEBUG_EVENT: | ||||||
| 			debugInfo := (*C.CREATE_THREAD_DEBUG_INFO)(unionPtr) | 			debugInfo := (*_CREATE_THREAD_DEBUG_INFO)(unionPtr) | ||||||
| 			_, err = dbp.addThread(sys.Handle(debugInfo.hThread), int(debugEvent.dwThreadId), false) | 			_, err = dbp.addThread(debugInfo.Thread, int(debugEvent.ThreadId), false) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				return 0, 0, err | 				return 0, 0, err | ||||||
| 			} | 			} | ||||||
| 			break | 			break | ||||||
| 		case C.EXIT_THREAD_DEBUG_EVENT: | 		case _EXIT_THREAD_DEBUG_EVENT: | ||||||
| 			delete(dbp.Threads, int(debugEvent.dwThreadId)) | 			delete(dbp.Threads, int(debugEvent.ThreadId)) | ||||||
| 			break | 			break | ||||||
| 		case C.OUTPUT_DEBUG_STRING_EVENT: | 		case _OUTPUT_DEBUG_STRING_EVENT: | ||||||
| 			//TODO: Handle debug output strings | 			//TODO: Handle debug output strings | ||||||
| 			break | 			break | ||||||
| 		case C.LOAD_DLL_DEBUG_EVENT: | 		case _LOAD_DLL_DEBUG_EVENT: | ||||||
| 			debugInfo := (*C.LOAD_DLL_DEBUG_INFO)(unionPtr) | 			debugInfo := (*_LOAD_DLL_DEBUG_INFO)(unionPtr) | ||||||
| 			hFile := debugInfo.hFile | 			hFile := debugInfo.File | ||||||
| 			if hFile != C.HANDLE(uintptr(0)) /* NULL */ && hFile != C.HANDLE(uintptr(0xFFFFFFFFFFFFFFFF)) /* INVALID_HANDLE_VALUE */ { | 			if hFile != 0 && hFile != syscall.InvalidHandle { | ||||||
| 				res = C.CloseHandle(hFile) | 				err = syscall.CloseHandle(hFile) | ||||||
| 				if res == C.FALSE { | 				if err != nil { | ||||||
| 					return 0, 0, fmt.Errorf("could not close DLL load file handle") | 					return 0, 0, err | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			break | 			break | ||||||
| 		case C.UNLOAD_DLL_DEBUG_EVENT: | 		case _UNLOAD_DLL_DEBUG_EVENT: | ||||||
| 			break | 			break | ||||||
| 		case C.RIP_EVENT: | 		case _RIP_EVENT: | ||||||
| 			break | 			break | ||||||
| 		case C.EXCEPTION_DEBUG_EVENT: | 		case _EXCEPTION_DEBUG_EVENT: | ||||||
| 			tid := int(debugEvent.dwThreadId) | 			tid := int(debugEvent.ThreadId) | ||||||
| 			dbp.os.breakThread = tid | 			dbp.os.breakThread = tid | ||||||
| 			return tid, 0, nil | 			return tid, 0, nil | ||||||
| 		case C.EXIT_PROCESS_DEBUG_EVENT: | 		case _EXIT_PROCESS_DEBUG_EVENT: | ||||||
| 			debugInfo := (*C.EXIT_PROCESS_DEBUG_INFO)(unionPtr) | 			debugInfo := (*_EXIT_PROCESS_DEBUG_INFO)(unionPtr) | ||||||
| 			exitCode = int(debugInfo.dwExitCode) | 			exitCode = int(debugInfo.ExitCode) | ||||||
| 			shouldExit = true | 			shouldExit = true | ||||||
| 		default: | 		default: | ||||||
| 			return 0, 0, fmt.Errorf("unknown debug event code: %d", debugEvent.dwDebugEventCode) | 			return 0, 0, fmt.Errorf("unknown debug event code: %d", debugEvent.DebugEventCode) | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// .. and then continue unless we received an event that indicated we should break into debugger. | 		// .. and then continue unless we received an event that indicated we should break into debugger. | ||||||
| 		res = C.ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, C.DBG_CONTINUE) | 		err = _ContinueDebugEvent(debugEvent.ProcessId, debugEvent.ThreadId, _DBG_CONTINUE) | ||||||
| 		if res == C.WINBOOL(0) { | 		if err != nil { | ||||||
| 			return 0, 0, fmt.Errorf("could not ContinueDebugEvent") | 			return 0, 0, err | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if shouldExit { | 		if shouldExit { | ||||||
|  | |||||||
| @ -1,12 +1,9 @@ | |||||||
| package proc | package proc | ||||||
|  |  | ||||||
| // #include <windows.h> |  | ||||||
| import "C" |  | ||||||
| import ( | import ( | ||||||
| 	"bytes" | 	"bytes" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"rsc.io/x86/x86asm" | 	"rsc.io/x86/x86asm" | ||||||
| 	"syscall" |  | ||||||
| 	"unsafe" | 	"unsafe" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @ -97,22 +94,17 @@ func (r *Regs) TLS() uint64 { | |||||||
|  |  | ||||||
| // SetPC sets the RIP register to the value specified by `pc`. | // SetPC sets the RIP register to the value specified by `pc`. | ||||||
| func (r *Regs) SetPC(thread *Thread, pc uint64) error { | func (r *Regs) SetPC(thread *Thread, pc uint64) error { | ||||||
| 	var context C.CONTEXT | 	context := newCONTEXT() | ||||||
| 	context.ContextFlags = C.CONTEXT_ALL | 	context.ContextFlags = _CONTEXT_ALL | ||||||
|  |  | ||||||
| 	res := C.GetThreadContext(C.HANDLE(thread.os.hThread), &context) | 	err := _GetThreadContext(thread.os.hThread, context) | ||||||
| 	if res == C.FALSE { | 	if err != nil { | ||||||
| 		return fmt.Errorf("could not GetThreadContext") | 		return err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	context.Rip = C.DWORD64(pc) | 	context.Rip = pc | ||||||
|  |  | ||||||
| 	res = C.SetThreadContext(C.HANDLE(thread.os.hThread), &context) | 	return _SetThreadContext(thread.os.hThread, context) | ||||||
| 	if res == C.FALSE { |  | ||||||
| 		return fmt.Errorf("could not SetThreadContext") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func (r *Regs) Get(n int) (uint64, error) { | func (r *Regs) Get(n int) (uint64, error) { | ||||||
| @ -273,18 +265,18 @@ func (r *Regs) Get(n int) (uint64, error) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func registers(thread *Thread) (Registers, error) { | func registers(thread *Thread) (Registers, error) { | ||||||
| 	var context C.CONTEXT | 	context := newCONTEXT() | ||||||
|  |  | ||||||
| 	context.ContextFlags = C.CONTEXT_ALL | 	context.ContextFlags = _CONTEXT_ALL | ||||||
| 	res := C.GetThreadContext(C.HANDLE(thread.os.hThread), &context) | 	err := _GetThreadContext(thread.os.hThread, context) | ||||||
| 	if res == C.FALSE { | 	if err != nil { | ||||||
| 		return nil, fmt.Errorf("failed to read ThreadContext") | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	var threadInfo _THREAD_BASIC_INFORMATION | 	var threadInfo _THREAD_BASIC_INFORMATION | ||||||
| 	status := _NtQueryInformationThread(syscall.Handle(thread.os.hThread), _ThreadBasicInformation, uintptr(unsafe.Pointer(&threadInfo)), uint32(unsafe.Sizeof(threadInfo)), nil) | 	status := _NtQueryInformationThread(thread.os.hThread, _ThreadBasicInformation, uintptr(unsafe.Pointer(&threadInfo)), uint32(unsafe.Sizeof(threadInfo)), nil) | ||||||
| 	if !_NT_SUCCESS(status) { | 	if !_NT_SUCCESS(status) { | ||||||
| 		return nil, fmt.Errorf("failed to get thread_basic_information") | 		return nil, fmt.Errorf("NtQueryInformationThread failed: it returns 0x%x", status) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	regs := &Regs{ | 	regs := &Regs{ | ||||||
|  | |||||||
| @ -22,8 +22,53 @@ type _THREAD_BASIC_INFORMATION struct { | |||||||
| 	BasePriority   int32 | 	BasePriority   int32 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | type _CREATE_PROCESS_DEBUG_INFO struct { | ||||||
|  | 	File                syscall.Handle | ||||||
|  | 	Process             syscall.Handle | ||||||
|  | 	Thread              syscall.Handle | ||||||
|  | 	BaseOfImage         uintptr | ||||||
|  | 	DebugInfoFileOffset uint32 | ||||||
|  | 	DebugInfoSize       uint32 | ||||||
|  | 	ThreadLocalBase     uintptr | ||||||
|  | 	StartAddress        uintptr | ||||||
|  | 	ImageName           uintptr | ||||||
|  | 	Unicode             uint16 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type _CREATE_THREAD_DEBUG_INFO struct { | ||||||
|  | 	Thread          syscall.Handle | ||||||
|  | 	ThreadLocalBase uintptr | ||||||
|  | 	StartAddress    uintptr | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type _EXIT_PROCESS_DEBUG_INFO struct { | ||||||
|  | 	ExitCode uint32 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type _LOAD_DLL_DEBUG_INFO struct { | ||||||
|  | 	File                syscall.Handle | ||||||
|  | 	BaseOfDll           uintptr | ||||||
|  | 	DebugInfoFileOffset uint32 | ||||||
|  | 	DebugInfoSize       uint32 | ||||||
|  | 	ImageName           uintptr | ||||||
|  | 	Unicode             uint16 | ||||||
|  | } | ||||||
|  |  | ||||||
| const ( | const ( | ||||||
| 	_ThreadBasicInformation = 0 | 	_ThreadBasicInformation = 0 | ||||||
|  |  | ||||||
|  | 	_DBG_CONTINUE              = 0x00010002 | ||||||
|  | 	_DBG_EXCEPTION_NOT_HANDLED = 0x80010001 | ||||||
|  |  | ||||||
|  | 	_EXCEPTION_DEBUG_EVENT      = 1 | ||||||
|  | 	_CREATE_THREAD_DEBUG_EVENT  = 2 | ||||||
|  | 	_CREATE_PROCESS_DEBUG_EVENT = 3 | ||||||
|  | 	_EXIT_THREAD_DEBUG_EVENT    = 4 | ||||||
|  | 	_EXIT_PROCESS_DEBUG_EVENT   = 5 | ||||||
|  | 	_LOAD_DLL_DEBUG_EVENT       = 6 | ||||||
|  | 	_UNLOAD_DLL_DEBUG_EVENT     = 7 | ||||||
|  | 	_OUTPUT_DEBUG_STRING_EVENT  = 8 | ||||||
|  | 	_RIP_EVENT                  = 9 | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func _NT_SUCCESS(x _NTSTATUS) bool { | func _NT_SUCCESS(x _NTSTATUS) bool { | ||||||
| @ -31,3 +76,12 @@ func _NT_SUCCESS(x _NTSTATUS) bool { | |||||||
| } | } | ||||||
|  |  | ||||||
| //sys	_NtQueryInformationThread(threadHandle syscall.Handle, infoclass int32, info uintptr, infolen uint32, retlen *uint32) (status _NTSTATUS) = ntdll.NtQueryInformationThread | //sys	_NtQueryInformationThread(threadHandle syscall.Handle, infoclass int32, info uintptr, infolen uint32, retlen *uint32) (status _NTSTATUS) = ntdll.NtQueryInformationThread | ||||||
|  | //sys	_GetThreadContext(thread syscall.Handle, context *_CONTEXT) (err error) = kernel32.GetThreadContext | ||||||
|  | //sys	_SetThreadContext(thread syscall.Handle, context *_CONTEXT) (err error) = kernel32.SetThreadContext | ||||||
|  | //sys	_SuspendThread(threadid syscall.Handle) (prevsuspcount uint32, err error) [failretval==0xffffffff] = kernel32.SuspendThread | ||||||
|  | //sys	_ResumeThread(threadid syscall.Handle) (prevsuspcount uint32, err error) [failretval==0xffffffff] = kernel32.ResumeThread | ||||||
|  | //sys	_ContinueDebugEvent(processid uint32, threadid uint32, continuestatus uint32) (err error) = kernel32.ContinueDebugEvent | ||||||
|  | //sys	_WriteProcessMemory(process syscall.Handle, baseaddr uintptr, buffer *byte, size uintptr, byteswritten *uintptr) (err error) = kernel32.WriteProcessMemory | ||||||
|  | //sys	_ReadProcessMemory(process syscall.Handle, baseaddr uintptr, buffer *byte, size uintptr, bytesread *uintptr) (err error) = kernel32.ReadProcessMemory | ||||||
|  | //sys	_DebugBreakProcess(process syscall.Handle) (err error) = kernel32.DebugBreakProcess | ||||||
|  | //sys	_WaitForDebugEvent(debugevent *_DEBUG_EVENT, milliseconds uint32) (err error) = kernel32.WaitForDebugEvent | ||||||
|  | |||||||
							
								
								
									
										95
									
								
								proc/syscall_windows_amd64.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								proc/syscall_windows_amd64.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,95 @@ | |||||||
|  | package proc | ||||||
|  |  | ||||||
|  | import "unsafe" | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	_CONTEXT_AMD64               = 0x100000 | ||||||
|  | 	_CONTEXT_CONTROL             = (_CONTEXT_AMD64 | 0x1) | ||||||
|  | 	_CONTEXT_INTEGER             = (_CONTEXT_AMD64 | 0x2) | ||||||
|  | 	_CONTEXT_SEGMENTS            = (_CONTEXT_AMD64 | 0x4) | ||||||
|  | 	_CONTEXT_FLOATING_POINT      = (_CONTEXT_AMD64 | 0x8) | ||||||
|  | 	_CONTEXT_DEBUG_REGISTERS     = (_CONTEXT_AMD64 | 0x10) | ||||||
|  | 	_CONTEXT_FULL                = (_CONTEXT_CONTROL | _CONTEXT_INTEGER | _CONTEXT_FLOATING_POINT) | ||||||
|  | 	_CONTEXT_ALL                 = (_CONTEXT_CONTROL | _CONTEXT_INTEGER | _CONTEXT_SEGMENTS | _CONTEXT_FLOATING_POINT | _CONTEXT_DEBUG_REGISTERS) | ||||||
|  | 	_CONTEXT_EXCEPTION_ACTIVE    = 0x8000000 | ||||||
|  | 	_CONTEXT_SERVICE_ACTIVE      = 0x10000000 | ||||||
|  | 	_CONTEXT_EXCEPTION_REQUEST   = 0x40000000 | ||||||
|  | 	_CONTEXT_EXCEPTION_REPORTING = 0x80000000 | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type _M128A struct { | ||||||
|  | 	Low  uint64 | ||||||
|  | 	High int64 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type _CONTEXT struct { | ||||||
|  | 	P1Home uint64 | ||||||
|  | 	P2Home uint64 | ||||||
|  | 	P3Home uint64 | ||||||
|  | 	P4Home uint64 | ||||||
|  | 	P5Home uint64 | ||||||
|  | 	P6Home uint64 | ||||||
|  |  | ||||||
|  | 	ContextFlags uint32 | ||||||
|  | 	MxCsr        uint32 | ||||||
|  |  | ||||||
|  | 	SegCs  uint16 | ||||||
|  | 	SegDs  uint16 | ||||||
|  | 	SegEs  uint16 | ||||||
|  | 	SegFs  uint16 | ||||||
|  | 	SegGs  uint16 | ||||||
|  | 	SegSs  uint16 | ||||||
|  | 	EFlags uint32 | ||||||
|  |  | ||||||
|  | 	Dr0 uint64 | ||||||
|  | 	Dr1 uint64 | ||||||
|  | 	Dr2 uint64 | ||||||
|  | 	Dr3 uint64 | ||||||
|  | 	Dr6 uint64 | ||||||
|  | 	Dr7 uint64 | ||||||
|  |  | ||||||
|  | 	Rax uint64 | ||||||
|  | 	Rcx uint64 | ||||||
|  | 	Rdx uint64 | ||||||
|  | 	Rbx uint64 | ||||||
|  | 	Rsp uint64 | ||||||
|  | 	Rbp uint64 | ||||||
|  | 	Rsi uint64 | ||||||
|  | 	Rdi uint64 | ||||||
|  | 	R8  uint64 | ||||||
|  | 	R9  uint64 | ||||||
|  | 	R10 uint64 | ||||||
|  | 	R11 uint64 | ||||||
|  | 	R12 uint64 | ||||||
|  | 	R13 uint64 | ||||||
|  | 	R14 uint64 | ||||||
|  | 	R15 uint64 | ||||||
|  |  | ||||||
|  | 	Rip uint64 | ||||||
|  |  | ||||||
|  | 	FltSave [512]byte | ||||||
|  |  | ||||||
|  | 	VectorRegister [26]_M128A | ||||||
|  | 	VectorControl  uint64 | ||||||
|  |  | ||||||
|  | 	DebugControl         uint64 | ||||||
|  | 	LastBranchToRip      uint64 | ||||||
|  | 	LastBranchFromRip    uint64 | ||||||
|  | 	LastExceptionToRip   uint64 | ||||||
|  | 	LastExceptionFromRip uint64 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // newCONTEXT allocates Windows CONTEXT structure aligned to 16 bytes. | ||||||
|  | func newCONTEXT() *_CONTEXT { | ||||||
|  | 	var c *_CONTEXT | ||||||
|  | 	buf := make([]byte, unsafe.Sizeof(*c)+15) | ||||||
|  | 	return (*_CONTEXT)(unsafe.Pointer((uintptr(unsafe.Pointer(&buf[15]))) &^ 15)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type _DEBUG_EVENT struct { | ||||||
|  | 	DebugEventCode uint32 | ||||||
|  | 	ProcessId      uint32 | ||||||
|  | 	ThreadId       uint32 | ||||||
|  | 	_              uint32 // to align Union properly | ||||||
|  | 	U              [160]byte | ||||||
|  | } | ||||||
| @ -1,10 +1,8 @@ | |||||||
| package proc | package proc | ||||||
|  |  | ||||||
| // #include <windows.h> |  | ||||||
| import "C" |  | ||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"unsafe" | 	"syscall" | ||||||
|  |  | ||||||
| 	sys "golang.org/x/sys/windows" | 	sys "golang.org/x/sys/windows" | ||||||
| ) | ) | ||||||
| @ -15,7 +13,7 @@ type WaitStatus sys.WaitStatus | |||||||
| // OSSpecificDetails holds information specific to the Windows | // OSSpecificDetails holds information specific to the Windows | ||||||
| // operating system / kernel. | // operating system / kernel. | ||||||
| type OSSpecificDetails struct { | type OSSpecificDetails struct { | ||||||
| 	hThread sys.Handle | 	hThread syscall.Handle | ||||||
| } | } | ||||||
|  |  | ||||||
| func (t *Thread) halt() (err error) { | func (t *Thread) halt() (err error) { | ||||||
| @ -29,20 +27,20 @@ func (t *Thread) halt() (err error) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (t *Thread) singleStep() error { | func (t *Thread) singleStep() error { | ||||||
| 	var context C.CONTEXT | 	context := newCONTEXT() | ||||||
| 	context.ContextFlags = C.CONTEXT_ALL | 	context.ContextFlags = _CONTEXT_ALL | ||||||
|  |  | ||||||
| 	// Set the processor TRAP flag | 	// Set the processor TRAP flag | ||||||
| 	res := C.GetThreadContext(C.HANDLE(t.os.hThread), &context) | 	err := _GetThreadContext(t.os.hThread, context) | ||||||
| 	if res == C.FALSE { | 	if err != nil { | ||||||
| 		return fmt.Errorf("could not GetThreadContext") | 		return err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	context.EFlags |= 0x100 | 	context.EFlags |= 0x100 | ||||||
|  |  | ||||||
| 	res = C.SetThreadContext(C.HANDLE(t.os.hThread), &context) | 	err = _SetThreadContext(t.os.hThread, context) | ||||||
| 	if res == C.FALSE { | 	if err != nil { | ||||||
| 		return fmt.Errorf("could not SetThreadContext") | 		return err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Suspend all threads except this one | 	// Suspend all threads except this one | ||||||
| @ -50,20 +48,21 @@ func (t *Thread) singleStep() error { | |||||||
| 		if thread.ID == t.ID { | 		if thread.ID == t.ID { | ||||||
| 			continue | 			continue | ||||||
| 		} | 		} | ||||||
| 		res := C.SuspendThread(C.HANDLE(thread.os.hThread)) | 		_, err := _SuspendThread(thread.os.hThread) | ||||||
| 		if res == C.DWORD(0xFFFFFFFF) { | 		if err != nil { | ||||||
| 			return fmt.Errorf("could not suspend thread: %d", thread.ID) | 			return fmt.Errorf("could not suspend thread: %d: %v", thread.ID, err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Continue and wait for the step to complete | 	// Continue and wait for the step to complete | ||||||
|  | 	err = nil | ||||||
| 	t.dbp.execPtraceFunc(func() { | 	t.dbp.execPtraceFunc(func() { | ||||||
| 		res = C.ContinueDebugEvent(C.DWORD(t.dbp.Pid), C.DWORD(t.ID), C.DBG_CONTINUE) | 		err = _ContinueDebugEvent(uint32(t.dbp.Pid), uint32(t.ID), _DBG_CONTINUE) | ||||||
| 	}) | 	}) | ||||||
| 	if res == C.FALSE { | 	if err != nil { | ||||||
| 		return fmt.Errorf("could not ContinueDebugEvent.") | 		return err | ||||||
| 	} | 	} | ||||||
| 	_, err := t.dbp.trapWait(0) | 	_, err = t.dbp.trapWait(0) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| @ -73,40 +72,32 @@ func (t *Thread) singleStep() error { | |||||||
| 		if thread.ID == t.ID { | 		if thread.ID == t.ID { | ||||||
| 			continue | 			continue | ||||||
| 		} | 		} | ||||||
| 		res := C.ResumeThread(C.HANDLE(thread.os.hThread)) | 		_, err := _ResumeThread(thread.os.hThread) | ||||||
| 		if res == C.DWORD(0xFFFFFFFF) { | 		if err != nil { | ||||||
| 			return fmt.Errorf("ould not resume thread: %d", thread.ID) | 			return fmt.Errorf("could not resume thread: %d: %v", thread.ID, err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Unset the processor TRAP flag | 	// Unset the processor TRAP flag | ||||||
| 	res = C.GetThreadContext(C.HANDLE(t.os.hThread), &context) | 	err = _GetThreadContext(t.os.hThread, context) | ||||||
| 	if res == C.FALSE { | 	if err != nil { | ||||||
| 		return fmt.Errorf("could not GetThreadContext") | 		return err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	context.EFlags &= ^C.DWORD(0x100) | 	context.EFlags &= ^uint32(0x100) | ||||||
|  |  | ||||||
| 	res = C.SetThreadContext(C.HANDLE(t.os.hThread), &context) | 	return _SetThreadContext(t.os.hThread, context) | ||||||
| 	if res == C.FALSE { |  | ||||||
| 		return fmt.Errorf("could not SetThreadContext") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func (t *Thread) resume() error { | func (t *Thread) resume() error { | ||||||
| 	t.running = true | 	t.running = true | ||||||
| 	var res C.WINBOOL | 	var err error | ||||||
| 	t.dbp.execPtraceFunc(func() { | 	t.dbp.execPtraceFunc(func() { | ||||||
| 		//TODO: Note that we are ignoring the thread we were asked to continue and are continuing the | 		//TODO: Note that we are ignoring the thread we were asked to continue and are continuing the | ||||||
| 		//thread that we last broke on. | 		//thread that we last broke on. | ||||||
| 		res = C.ContinueDebugEvent(C.DWORD(t.dbp.Pid), C.DWORD(t.ID), C.DBG_CONTINUE) | 		err = _ContinueDebugEvent(uint32(t.dbp.Pid), uint32(t.ID), _DBG_CONTINUE) | ||||||
| 	}) | 	}) | ||||||
| 	if res == C.FALSE { | 	return err | ||||||
| 		return fmt.Errorf("could not ContinueDebugEvent.") |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func (t *Thread) blocked() bool { | func (t *Thread) blocked() bool { | ||||||
| @ -135,15 +126,10 @@ func (t *Thread) stopped() bool { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (t *Thread) writeMemory(addr uintptr, data []byte) (int, error) { | func (t *Thread) writeMemory(addr uintptr, data []byte) (int, error) { | ||||||
| 	var ( | 	var count uintptr | ||||||
| 		vmData = C.LPCVOID(unsafe.Pointer(&data[0])) | 	err := _WriteProcessMemory(t.dbp.os.hProcess, addr, &data[0], uintptr(len(data)), &count) | ||||||
| 		vmAddr = C.LPVOID(addr) | 	if err != nil { | ||||||
| 		length = C.SIZE_T(len(data)) | 		return 0, err | ||||||
| 		count  C.SIZE_T |  | ||||||
| 	) |  | ||||||
| 	ret := C.WriteProcessMemory(C.HANDLE(t.dbp.os.hProcess), vmAddr, vmData, length, &count) |  | ||||||
| 	if ret == C.FALSE { |  | ||||||
| 		return int(count), fmt.Errorf("could not write memory") |  | ||||||
| 	} | 	} | ||||||
| 	return int(count), nil | 	return int(count), nil | ||||||
| } | } | ||||||
| @ -152,16 +138,11 @@ func (t *Thread) readMemory(addr uintptr, size int) ([]byte, error) { | |||||||
| 	if size == 0 { | 	if size == 0 { | ||||||
| 		return nil, nil | 		return nil, nil | ||||||
| 	} | 	} | ||||||
| 	var ( | 	var count uintptr | ||||||
| 		buf    = make([]byte, size) | 	buf := make([]byte, size) | ||||||
| 		vmData = C.LPVOID(unsafe.Pointer(&buf[0])) | 	err := _ReadProcessMemory(t.dbp.os.hProcess, addr, &buf[0], uintptr(size), &count) | ||||||
| 		vmAddr = C.LPCVOID(addr) | 	if err != nil { | ||||||
| 		length = C.SIZE_T(size) | 		return nil, err | ||||||
| 		count  C.SIZE_T |  | ||||||
| 	) |  | ||||||
| 	ret := C.ReadProcessMemory(C.HANDLE(t.dbp.os.hProcess), vmAddr, vmData, length, &count) |  | ||||||
| 	if ret == C.FALSE { |  | ||||||
| 		return nil, fmt.Errorf("could not read memory") |  | ||||||
| 	} | 	} | ||||||
| 	return buf, nil | 	return buf[:count], nil | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										120
									
								
								proc/zsyscall_windows.go
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										120
									
								
								proc/zsyscall_windows.go
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							| @ -9,8 +9,18 @@ var _ unsafe.Pointer | |||||||
|  |  | ||||||
| var ( | var ( | ||||||
| 	modntdll    = syscall.NewLazyDLL("ntdll.dll") | 	modntdll    = syscall.NewLazyDLL("ntdll.dll") | ||||||
|  | 	modkernel32 = syscall.NewLazyDLL("kernel32.dll") | ||||||
|  |  | ||||||
| 	procNtQueryInformationThread = modntdll.NewProc("NtQueryInformationThread") | 	procNtQueryInformationThread = modntdll.NewProc("NtQueryInformationThread") | ||||||
|  | 	procGetThreadContext         = modkernel32.NewProc("GetThreadContext") | ||||||
|  | 	procSetThreadContext         = modkernel32.NewProc("SetThreadContext") | ||||||
|  | 	procSuspendThread            = modkernel32.NewProc("SuspendThread") | ||||||
|  | 	procResumeThread             = modkernel32.NewProc("ResumeThread") | ||||||
|  | 	procContinueDebugEvent       = modkernel32.NewProc("ContinueDebugEvent") | ||||||
|  | 	procWriteProcessMemory       = modkernel32.NewProc("WriteProcessMemory") | ||||||
|  | 	procReadProcessMemory        = modkernel32.NewProc("ReadProcessMemory") | ||||||
|  | 	procDebugBreakProcess        = modkernel32.NewProc("DebugBreakProcess") | ||||||
|  | 	procWaitForDebugEvent        = modkernel32.NewProc("WaitForDebugEvent") | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func _NtQueryInformationThread(threadHandle syscall.Handle, infoclass int32, info uintptr, infolen uint32, retlen *uint32) (status _NTSTATUS) { | func _NtQueryInformationThread(threadHandle syscall.Handle, infoclass int32, info uintptr, infolen uint32, retlen *uint32) (status _NTSTATUS) { | ||||||
| @ -18,3 +28,113 @@ func _NtQueryInformationThread(threadHandle syscall.Handle, infoclass int32, inf | |||||||
| 	status = _NTSTATUS(r0) | 	status = _NTSTATUS(r0) | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func _GetThreadContext(thread syscall.Handle, context *_CONTEXT) (err error) { | ||||||
|  | 	r1, _, e1 := syscall.Syscall(procGetThreadContext.Addr(), 2, uintptr(thread), uintptr(unsafe.Pointer(context)), 0) | ||||||
|  | 	if r1 == 0 { | ||||||
|  | 		if e1 != 0 { | ||||||
|  | 			err = error(e1) | ||||||
|  | 		} else { | ||||||
|  | 			err = syscall.EINVAL | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func _SetThreadContext(thread syscall.Handle, context *_CONTEXT) (err error) { | ||||||
|  | 	r1, _, e1 := syscall.Syscall(procSetThreadContext.Addr(), 2, uintptr(thread), uintptr(unsafe.Pointer(context)), 0) | ||||||
|  | 	if r1 == 0 { | ||||||
|  | 		if e1 != 0 { | ||||||
|  | 			err = error(e1) | ||||||
|  | 		} else { | ||||||
|  | 			err = syscall.EINVAL | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func _SuspendThread(threadid syscall.Handle) (prevsuspcount uint32, err error) { | ||||||
|  | 	r0, _, e1 := syscall.Syscall(procSuspendThread.Addr(), 1, uintptr(threadid), 0, 0) | ||||||
|  | 	prevsuspcount = uint32(r0) | ||||||
|  | 	if prevsuspcount == 0xffffffff { | ||||||
|  | 		if e1 != 0 { | ||||||
|  | 			err = error(e1) | ||||||
|  | 		} else { | ||||||
|  | 			err = syscall.EINVAL | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func _ResumeThread(threadid syscall.Handle) (prevsuspcount uint32, err error) { | ||||||
|  | 	r0, _, e1 := syscall.Syscall(procResumeThread.Addr(), 1, uintptr(threadid), 0, 0) | ||||||
|  | 	prevsuspcount = uint32(r0) | ||||||
|  | 	if prevsuspcount == 0xffffffff { | ||||||
|  | 		if e1 != 0 { | ||||||
|  | 			err = error(e1) | ||||||
|  | 		} else { | ||||||
|  | 			err = syscall.EINVAL | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func _ContinueDebugEvent(processid uint32, threadid uint32, continuestatus uint32) (err error) { | ||||||
|  | 	r1, _, e1 := syscall.Syscall(procContinueDebugEvent.Addr(), 3, uintptr(processid), uintptr(threadid), uintptr(continuestatus)) | ||||||
|  | 	if r1 == 0 { | ||||||
|  | 		if e1 != 0 { | ||||||
|  | 			err = error(e1) | ||||||
|  | 		} else { | ||||||
|  | 			err = syscall.EINVAL | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func _WriteProcessMemory(process syscall.Handle, baseaddr uintptr, buffer *byte, size uintptr, byteswritten *uintptr) (err error) { | ||||||
|  | 	r1, _, e1 := syscall.Syscall6(procWriteProcessMemory.Addr(), 5, uintptr(process), uintptr(baseaddr), uintptr(unsafe.Pointer(buffer)), uintptr(size), uintptr(unsafe.Pointer(byteswritten)), 0) | ||||||
|  | 	if r1 == 0 { | ||||||
|  | 		if e1 != 0 { | ||||||
|  | 			err = error(e1) | ||||||
|  | 		} else { | ||||||
|  | 			err = syscall.EINVAL | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func _ReadProcessMemory(process syscall.Handle, baseaddr uintptr, buffer *byte, size uintptr, bytesread *uintptr) (err error) { | ||||||
|  | 	r1, _, e1 := syscall.Syscall6(procReadProcessMemory.Addr(), 5, uintptr(process), uintptr(baseaddr), uintptr(unsafe.Pointer(buffer)), uintptr(size), uintptr(unsafe.Pointer(bytesread)), 0) | ||||||
|  | 	if r1 == 0 { | ||||||
|  | 		if e1 != 0 { | ||||||
|  | 			err = error(e1) | ||||||
|  | 		} else { | ||||||
|  | 			err = syscall.EINVAL | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func _DebugBreakProcess(process syscall.Handle) (err error) { | ||||||
|  | 	r1, _, e1 := syscall.Syscall(procDebugBreakProcess.Addr(), 1, uintptr(process), 0, 0) | ||||||
|  | 	if r1 == 0 { | ||||||
|  | 		if e1 != 0 { | ||||||
|  | 			err = error(e1) | ||||||
|  | 		} else { | ||||||
|  | 			err = syscall.EINVAL | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func _WaitForDebugEvent(debugevent *_DEBUG_EVENT, milliseconds uint32) (err error) { | ||||||
|  | 	r1, _, e1 := syscall.Syscall(procWaitForDebugEvent.Addr(), 2, uintptr(unsafe.Pointer(debugevent)), uintptr(milliseconds), 0) | ||||||
|  | 	if r1 == 0 { | ||||||
|  | 		if e1 != 0 { | ||||||
|  | 			err = error(e1) | ||||||
|  | 		} else { | ||||||
|  | 			err = syscall.EINVAL | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 Alex Brainman
					Alex Brainman