Ejemplo n.º 1
0
func munmap(b []byte) (err error) {
	m := memoryMap(b)
	dh := m.header()

	addr := dh.Data
	length := uintptr(dh.Len)

	flush(addr, length)
	err = windows.UnmapViewOfFile(addr)
	if err != nil {
		return err
	}

	handleLock.Lock()
	defer handleLock.Unlock()
	handle, ok := handleMap[addr]
	if !ok {
		// should be impossible; we would've errored above
		return errors.New("unknown base address")
	}
	delete(handleMap, addr)

	e := windows.CloseHandle(windows.Handle(handle))
	return os.NewSyscallError("CloseHandle", e)
}
Ejemplo n.º 2
0
func (s *service) run() {
	s.goWaits.Wait()
	s.h = windows.Handle(ssHandle)
	argv := (*[100]*int16)(unsafe.Pointer(sArgv))[:sArgc]
	args := make([]string, len(argv))
	for i, a := range argv {
		args[i] = syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(a))[:])
	}

	cmdsToHandler := make(chan ChangeRequest)
	changesFromHandler := make(chan Status)
	exitFromHandler := make(chan exitCode)

	go func() {
		ss, errno := s.handler.Execute(args, cmdsToHandler, changesFromHandler)
		exitFromHandler <- exitCode{ss, errno}
	}()

	status := Status{State: Stopped}
	ec := exitCode{isSvcSpecific: true, errno: 0}
	var outch chan ChangeRequest
	inch := s.c
	var cmd Cmd
loop:
	for {
		select {
		case r := <-inch:
			if r.errno != 0 {
				ec.errno = r.errno
				break loop
			}
			inch = nil
			outch = cmdsToHandler
			cmd = r.cmd
		case outch <- ChangeRequest{cmd, status}:
			inch = s.c
			outch = nil
		case c := <-changesFromHandler:
			err := s.updateStatus(&c, &ec)
			if err != nil {
				// best suitable error number
				ec.errno = sysErrSetServiceStatusFailed
				if err2, ok := err.(syscall.Errno); ok {
					ec.errno = uint32(err2)
				}
				break loop
			}
			status = c
		case ec = <-exitFromHandler:
			break loop
		}
	}

	s.updateStatus(&Status{State: Stopped}, &ec)
	s.cWaits.Set()
}
Ejemplo n.º 3
0
func rdat(fd int, p []byte, off int64) (n int, err error) {
	// hi := int32(off >> 32)
	// lo := int32(off)
	// _, err = windows.SetFilePointer(windows.Handle(fd), lo, &hi, windows.FILE_BEGIN)
	// if err != nil {
	// 	return 0, err
	// }
	ol := windows.Overlapped{Offset: uint32(off), OffsetHigh: uint32(off >> 32), HEvent: windows.Handle(0)}
	var done uint32
	err = windows.ReadFile(windows.Handle(fd), p, &done, &ol)
	if err != nil {
		return 0, err
	}
	return int(done), nil
}
Ejemplo n.º 4
0
func mmap(fd int, length int) (data []byte, err error) {
	h, errno := windows.CreateFileMapping(windows.Handle(fd), nil,
		uint32(windows.PAGE_READONLY), 0, uint32(length), nil)
	if h == 0 {
		return nil, os.NewSyscallError("CreateFileMapping", errno)
	}

	addr, errno := windows.MapViewOfFile(h, uint32(windows.FILE_MAP_READ), 0,
		0, uintptr(length))
	if addr == 0 {
		return nil, os.NewSyscallError("MapViewOfFile", errno)
	}
	handleLock.Lock()
	handleMap[addr] = h
	handleLock.Unlock()

	m := memoryMap{}
	dh := m.header()
	dh.Data = addr
	dh.Len = length
	dh.Cap = dh.Len

	return m, nil
}
Ejemplo n.º 5
0
// Launch creates and begins debugging a new process.
func Launch(cmd []string) (*Process, error) {
	argv0Go, err := filepath.Abs(cmd[0])
	if err != nil {
		return nil, err
	}
	// Make sure the binary exists.
	if filepath.Base(cmd[0]) == cmd[0] {
		if _, err := exec.LookPath(cmd[0]); err != nil {
			return nil, err
		}
	}
	if _, err := os.Stat(argv0Go); err != nil {
		return nil, err
	}
	// Duplicate the stdin/stdout/stderr handles
	files := []uintptr{uintptr(syscall.Stdin), uintptr(syscall.Stdout), uintptr(syscall.Stderr)}
	p, _ := syscall.GetCurrentProcess()
	fd := make([]syscall.Handle, len(files))
	for i := range files {
		err := syscall.DuplicateHandle(p, syscall.Handle(files[i]), p, &fd[i], 0, true, syscall.DUPLICATE_SAME_ACCESS)
		if err != nil {
			return nil, err
		}
		defer syscall.CloseHandle(syscall.Handle(fd[i]))
	}

	argv0, err := syscall.UTF16PtrFromString(argv0Go)
	if err != nil {
		return nil, err
	}

	// create suitable command line for CreateProcess
	// see https://github.com/golang/go/blob/master/src/syscall/exec_windows.go#L326
	// adapted from standard library makeCmdLine
	// see https://github.com/golang/go/blob/master/src/syscall/exec_windows.go#L86
	var cmdLineGo string
	if len(cmd) >= 1 {
		for _, v := range cmd {
			if cmdLineGo != "" {
				cmdLineGo += " "
			}
			cmdLineGo += syscall.EscapeArg(v)
		}
	}

	var cmdLine *uint16
	if cmdLineGo != "" {
		if cmdLine, err = syscall.UTF16PtrFromString(cmdLineGo); err != nil {
			return nil, err
		}
	}

	// Initialize the startup info and create process
	si := new(sys.StartupInfo)
	si.Cb = uint32(unsafe.Sizeof(*si))
	si.Flags = syscall.STARTF_USESTDHANDLES
	si.StdInput = sys.Handle(fd[0])
	si.StdOutput = sys.Handle(fd[1])
	si.StdErr = sys.Handle(fd[2])
	pi := new(sys.ProcessInformation)
	err = sys.CreateProcess(argv0, cmdLine, nil, nil, true, DEBUGONLYTHISPROCESS, nil, nil, si, pi)
	if err != nil {
		return nil, err
	}
	sys.CloseHandle(sys.Handle(pi.Process))
	sys.CloseHandle(sys.Handle(pi.Thread))

	dbp := New(int(pi.ProcessId))

	switch runtime.GOARCH {
	case "amd64":
		dbp.arch = AMD64Arch()
	}

	// Note - it should not actually be possible for the
	// call to waitForDebugEvent to fail, since Windows
	// will always fire a CreateProcess event immediately
	// after launching under DEBUGONLYTHISPROCESS.
	var tid, exitCode int
	dbp.execPtraceFunc(func() {
		tid, exitCode, err = dbp.waitForDebugEvent()
	})
	if err != nil {
		return nil, err
	}
	if tid == 0 {
		dbp.postExit()
		return nil, ProcessExitedError{Pid: dbp.Pid, Status: exitCode}
	}

	return initializeDebugProcess(dbp, argv0Go, false)
}
Ejemplo n.º 6
0
func (dbp *Process) waitForDebugEvent() (threadID, exitCode int, err error) {
	var debugEvent C.DEBUG_EVENT
	for {
		// Wait for a debug event...
		res := C.WaitForDebugEvent(&debugEvent, C.INFINITE)
		if res == C.FALSE {
			return 0, 0, fmt.Errorf("could not WaitForDebugEvent")
		}

		// ... handle each event kind ...
		unionPtr := unsafe.Pointer(&debugEvent.u[0])
		switch debugEvent.dwDebugEventCode {
		case C.CREATE_PROCESS_DEBUG_EVENT:
			debugInfo := (*C.CREATE_PROCESS_DEBUG_INFO)(unionPtr)
			hFile := debugInfo.hFile
			if hFile != C.HANDLE(uintptr(0)) /* NULL */ && hFile != C.HANDLE(uintptr(0xFFFFFFFFFFFFFFFF)) /* INVALID_HANDLE_VALUE */ {
				res = C.CloseHandle(hFile)
				if res == C.FALSE {
					return 0, 0, fmt.Errorf("could not close create process file handle")
				}
			}
			dbp.os.hProcess = sys.Handle(debugInfo.hProcess)
			_, err = dbp.addThread(sys.Handle(debugInfo.hThread), int(debugEvent.dwThreadId), false)
			if err != nil {
				return 0, 0, err
			}
			break
		case C.CREATE_THREAD_DEBUG_EVENT:
			debugInfo := (*C.CREATE_THREAD_DEBUG_INFO)(unionPtr)
			_, err = dbp.addThread(sys.Handle(debugInfo.hThread), int(debugEvent.dwThreadId), false)
			if err != nil {
				return 0, 0, err
			}
			break
		case C.EXIT_THREAD_DEBUG_EVENT:
			delete(dbp.Threads, int(debugEvent.dwThreadId))
			break
		case C.OUTPUT_DEBUG_STRING_EVENT:
			//TODO: Handle debug output strings
			break
		case C.LOAD_DLL_DEBUG_EVENT:
			debugInfo := (*C.LOAD_DLL_DEBUG_INFO)(unionPtr)
			hFile := debugInfo.hFile
			if hFile != C.HANDLE(uintptr(0)) /* NULL */ && hFile != C.HANDLE(uintptr(0xFFFFFFFFFFFFFFFF)) /* INVALID_HANDLE_VALUE */ {
				res = C.CloseHandle(hFile)
				if res == C.FALSE {
					return 0, 0, fmt.Errorf("could not close DLL load file handle")
				}
			}
			break
		case C.UNLOAD_DLL_DEBUG_EVENT:
			break
		case C.RIP_EVENT:
			break
		case C.EXCEPTION_DEBUG_EVENT:
			tid := int(debugEvent.dwThreadId)
			dbp.os.breakThread = tid
			return tid, 0, nil
		case C.EXIT_PROCESS_DEBUG_EVENT:
			debugInfo := (*C.EXIT_PROCESS_DEBUG_INFO)(unionPtr)
			return 0, int(debugInfo.dwExitCode), nil
		default:
			return 0, 0, fmt.Errorf("unknown debug event code: %d", debugEvent.dwDebugEventCode)
		}

		// .. 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)
		if res == C.WINBOOL(0) {
			return 0, 0, fmt.Errorf("could not ContinueDebugEvent")
		}
	}
}
Ejemplo n.º 7
0
// Frees the loaded dynamic-link library (DLL) module and, if necessary,
// decrements its reference count. When the reference count reaches zero, the
// module is unloaded from the address space of the calling process and the
// handle is no longer valid.
func freeLibrary(handle Handle) error {
	// Wrap the method so that we can stub it out and use our own Handle type.
	return windows.FreeLibrary(windows.Handle(handle))
}
Ejemplo n.º 8
0
func rlck(fd, from, ln int) (err error) {

	// f, err = os.OpenFile(fn, os.O_RDONLY, os.FileMode(0600))
	// if err != nil {
	// 	return nil, err
	// }
	// type Overlapped struct {
	// 	Internal     uintptr
	// 	InternalHigh uintptr
	// 	Offset       uint32
	// 	OffsetHigh   uint32
	// 	HEvent       Handle
	// }
	// fdh, err := windows.Open(fn, os.O_RDONLY, 0)
	// if err != nil {
	// 	return 0, err
	// }
	// fd = int(fdh)
	// ol := windows.Overlapped{HEvent: windows.Handle(0)}
	// var ol windows.Overlapped
	// ln := int64(to - from)
	// hi := int32(ln >> 32)
	// lo := int32(ln)
	ol := windows.Overlapped{Offset: uint32(from), OffsetHigh: uint32(from >> 32), HEvent: windows.Handle(0)}
	r1, _, err := procLockFileEx.Call(uintptr(fd), uintptr(LOCKFILE_FAIL_IMMEDIATELY), uintptr(0), uintptr(int32(ln)), uintptr(int32(ln>>32)), uintptr(unsafe.Pointer(&ol)))
	// fmt.Printf("rlck %v %v %v %v = %v %v\n", fd, uintptr(int32(ln)), uintptr(int32(ln >> 32)), ol, r1, err)
	if r1 != 1 {
		return err
	}

	//r1, _, e1 := syscall.Syscall6(procLockFileEx.Addr(), 6, uintptr(h), uintptr(flags), uintptr(reserved), uintptr(locklow), uintptr(lockhigh), uintptr(unsafe.Pointer(ol)))
	return nil
	// wait := true
	// st := time.Now()
	// for wait {
	// 	f, err := os.Open(fn)
	// 	if err == nil {
	// 		return f, err
	// 	} else if !os.IsNotExist(err) {
	// 		return nil, err
	// 	}
	// 	time.Sleep(10 * time.Millisecond)
	// 	if time.Since(st) > timeout {
	// 		wait = false
	// 	}
	// }
	// return nil, errTimeout
}
Ejemplo n.º 9
0
func cl(fd int) (err error) {
	return windows.CloseHandle(windows.Handle(fd))
}
Ejemplo n.º 10
0
func unlck(fd, from, ln int) (err error) {
	// fmt.Println(fd, from, to)
	// ln := int64(to - from)
	// hi := int32(ln >> 32)
	// lo := int32(ln)
	ol := windows.Overlapped{Offset: uint32(from), OffsetHigh: uint32(from >> 32), HEvent: windows.Handle(0)}
	// ol := windows.Overlapped{Offset: uint32(from), HEvent: windows.Handle(0)}

	// ol := windows.Overlapped{HEvent: windows.Handle(0)}
	r1, _, err := procUnlockFileEx.Call(uintptr(fd), uintptr(0), uintptr(int32(ln)), uintptr(int32(ln>>32)), uintptr(unsafe.Pointer(&ol)))
	// fmt.Printf("unlck %v %v %v %v = %v %v\n", fd, uintptr(int32(ln)), uintptr(int32(ln >> 32)), ol, r1, err)
	if r1 != 1 {
		return err
	}
	return nil //windows.CloseHandle(windows.Handle(fd))
}
Ejemplo n.º 11
0
// Launch creates and begins debugging a new process.
func Launch(cmd []string) (*Process, error) {
	argv0Go, err := filepath.Abs(cmd[0])
	if err != nil {
		return nil, err
	}

	// Make sure the binary exists and is an executable file
	if filepath.Base(cmd[0]) == cmd[0] {
		if _, err := exec.LookPath(cmd[0]); err != nil {
			return nil, err
		}
	}

	peFile, err := openExecutablePath(argv0Go)
	if err != nil {
		return nil, NotExecutableErr
	}
	peFile.Close()

	// Duplicate the stdin/stdout/stderr handles
	files := []uintptr{uintptr(syscall.Stdin), uintptr(syscall.Stdout), uintptr(syscall.Stderr)}
	p, _ := syscall.GetCurrentProcess()
	fd := make([]syscall.Handle, len(files))
	for i := range files {
		err := syscall.DuplicateHandle(p, syscall.Handle(files[i]), p, &fd[i], 0, true, syscall.DUPLICATE_SAME_ACCESS)
		if err != nil {
			return nil, err
		}
		defer syscall.CloseHandle(syscall.Handle(fd[i]))
	}

	argv0, err := syscall.UTF16PtrFromString(argv0Go)
	if err != nil {
		return nil, err
	}

	// create suitable command line for CreateProcess
	// see https://github.com/golang/go/blob/master/src/syscall/exec_windows.go#L326
	// adapted from standard library makeCmdLine
	// see https://github.com/golang/go/blob/master/src/syscall/exec_windows.go#L86
	var cmdLineGo string
	if len(cmd) >= 1 {
		for _, v := range cmd {
			if cmdLineGo != "" {
				cmdLineGo += " "
			}
			cmdLineGo += syscall.EscapeArg(v)
		}
	}

	var cmdLine *uint16
	if cmdLineGo != "" {
		if cmdLine, err = syscall.UTF16PtrFromString(cmdLineGo); err != nil {
			return nil, err
		}
	}

	// Initialize the startup info and create process
	si := new(sys.StartupInfo)
	si.Cb = uint32(unsafe.Sizeof(*si))
	si.Flags = syscall.STARTF_USESTDHANDLES
	si.StdInput = sys.Handle(fd[0])
	si.StdOutput = sys.Handle(fd[1])
	si.StdErr = sys.Handle(fd[2])
	pi := new(sys.ProcessInformation)
	err = sys.CreateProcess(argv0, cmdLine, nil, nil, true, _DEBUG_ONLY_THIS_PROCESS, nil, nil, si, pi)
	if err != nil {
		return nil, err
	}
	sys.CloseHandle(sys.Handle(pi.Process))
	sys.CloseHandle(sys.Handle(pi.Thread))

	return newDebugProcess(int(pi.ProcessId), argv0Go)
}