parent
c3ade94b86
commit
f09ef23f9e
10
proc/proc.go
10
proc/proc.go
@ -79,6 +79,11 @@ func New(pid int) *Process {
|
|||||||
ptraceChan: make(chan func()),
|
ptraceChan: make(chan func()),
|
||||||
ptraceDoneChan: make(chan interface{}),
|
ptraceDoneChan: make(chan interface{}),
|
||||||
}
|
}
|
||||||
|
// TODO: find better way to determine proc arch (perhaps use executable file info)
|
||||||
|
switch runtime.GOARCH {
|
||||||
|
case "amd64":
|
||||||
|
dbp.arch = AMD64Arch()
|
||||||
|
}
|
||||||
go dbp.handlePtraceFuncs()
|
go dbp.handlePtraceFuncs()
|
||||||
return dbp
|
return dbp
|
||||||
}
|
}
|
||||||
@ -704,11 +709,6 @@ func initializeDebugProcess(dbp *Process, path string, attach bool) (*Process, e
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
switch runtime.GOARCH {
|
|
||||||
case "amd64":
|
|
||||||
dbp.arch = AMD64Arch()
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := dbp.updateThreadList(); err != nil {
|
if err := dbp.updateThreadList(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,21 +8,15 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
sys "golang.org/x/sys/windows"
|
sys "golang.org/x/sys/windows"
|
||||||
|
|
||||||
"golang.org/x/debug/dwarf"
|
|
||||||
"github.com/derekparker/delve/dwarf/frame"
|
"github.com/derekparker/delve/dwarf/frame"
|
||||||
"github.com/derekparker/delve/dwarf/line"
|
"github.com/derekparker/delve/dwarf/line"
|
||||||
)
|
"golang.org/x/debug/dwarf"
|
||||||
|
|
||||||
const (
|
|
||||||
// DEBUGONLYTHISPROCESS tracks https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx
|
|
||||||
DEBUGONLYTHISPROCESS = 0x00000002
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// OSProcessDetails holds Windows specific information.
|
// OSProcessDetails holds Windows specific information.
|
||||||
@ -97,24 +91,25 @@ func Launch(cmd []string) (*Process, error) {
|
|||||||
si.StdOutput = sys.Handle(fd[1])
|
si.StdOutput = sys.Handle(fd[1])
|
||||||
si.StdErr = sys.Handle(fd[2])
|
si.StdErr = sys.Handle(fd[2])
|
||||||
pi := new(sys.ProcessInformation)
|
pi := new(sys.ProcessInformation)
|
||||||
err = sys.CreateProcess(argv0, cmdLine, nil, nil, true, DEBUGONLYTHISPROCESS, nil, nil, si, pi)
|
err = sys.CreateProcess(argv0, cmdLine, nil, nil, true, _DEBUG_ONLY_THIS_PROCESS, nil, nil, si, pi)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
sys.CloseHandle(sys.Handle(pi.Process))
|
sys.CloseHandle(sys.Handle(pi.Process))
|
||||||
sys.CloseHandle(sys.Handle(pi.Thread))
|
sys.CloseHandle(sys.Handle(pi.Thread))
|
||||||
|
|
||||||
dbp := New(int(pi.ProcessId))
|
return newDebugProcess(int(pi.ProcessId), argv0Go)
|
||||||
|
}
|
||||||
|
|
||||||
switch runtime.GOARCH {
|
// newDebugProcess prepares process pid for debugging.
|
||||||
case "amd64":
|
func newDebugProcess(pid int, exepath string) (*Process, error) {
|
||||||
dbp.arch = AMD64Arch()
|
dbp := New(pid)
|
||||||
}
|
// It should not actually be possible for the
|
||||||
|
|
||||||
// Note - it should not actually be possible for the
|
|
||||||
// call to waitForDebugEvent to fail, since Windows
|
// call to waitForDebugEvent to fail, since Windows
|
||||||
// will always fire a CreateProcess event immediately
|
// will always fire a CREATE_PROCESS_DEBUG_EVENT event
|
||||||
// after launching under DEBUGONLYTHISPROCESS.
|
// immediately after launching under DEBUG_ONLY_THIS_PROCESS.
|
||||||
|
// Attaching with DebugActiveProcess has similar effect.
|
||||||
|
var err error
|
||||||
var tid, exitCode int
|
var tid, exitCode int
|
||||||
dbp.execPtraceFunc(func() {
|
dbp.execPtraceFunc(func() {
|
||||||
tid, exitCode, err = dbp.waitForDebugEvent()
|
tid, exitCode, err = dbp.waitForDebugEvent()
|
||||||
@ -126,13 +121,55 @@ func Launch(cmd []string) (*Process, error) {
|
|||||||
dbp.postExit()
|
dbp.postExit()
|
||||||
return nil, ProcessExitedError{Pid: dbp.Pid, Status: exitCode}
|
return nil, ProcessExitedError{Pid: dbp.Pid, Status: exitCode}
|
||||||
}
|
}
|
||||||
|
return initializeDebugProcess(dbp, exepath, false)
|
||||||
|
}
|
||||||
|
|
||||||
return initializeDebugProcess(dbp, argv0Go, false)
|
// findExePath searches for process pid, and returns its executable path.
|
||||||
|
func findExePath(pid int) (string, error) {
|
||||||
|
// Original code suggested different approach (see below).
|
||||||
|
// Maybe it could be useful in the future.
|
||||||
|
//
|
||||||
|
// Find executable path from PID/handle on Windows:
|
||||||
|
// https://msdn.microsoft.com/en-us/library/aa366789(VS.85).aspx
|
||||||
|
|
||||||
|
p, err := syscall.OpenProcess(syscall.PROCESS_QUERY_INFORMATION, false, uint32(pid))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer syscall.CloseHandle(p)
|
||||||
|
|
||||||
|
n := uint32(128)
|
||||||
|
for {
|
||||||
|
buf := make([]uint16, int(n))
|
||||||
|
err = _QueryFullProcessImageName(p, 0, &buf[0], &n)
|
||||||
|
switch err {
|
||||||
|
case syscall.ERROR_INSUFFICIENT_BUFFER:
|
||||||
|
// try bigger buffer
|
||||||
|
n *= 2
|
||||||
|
// but stop if it gets too big
|
||||||
|
if n > 10000 {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
case nil:
|
||||||
|
return syscall.UTF16ToString(buf[:n]), nil
|
||||||
|
default:
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attach to an existing process with the given PID.
|
// Attach to an existing process with the given PID.
|
||||||
func Attach(pid int) (*Process, error) {
|
func Attach(pid int) (*Process, error) {
|
||||||
return nil, fmt.Errorf("not implemented: Attach")
|
// TODO: Probably should have SeDebugPrivilege before starting here.
|
||||||
|
err := _DebugActiveProcess(uint32(pid))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
exepath, err := findExePath(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return newDebugProcess(pid, exepath)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Kill kills the process.
|
// Kill kills the process.
|
||||||
@ -316,11 +353,6 @@ func (dbp *Process) parseDebugLineInfo(exe *pe.File, wg *sync.WaitGroup) {
|
|||||||
var UnsupportedArchErr = errors.New("unsupported architecture of windows/386 - only windows/amd64 is supported")
|
var UnsupportedArchErr = errors.New("unsupported architecture of windows/386 - only windows/amd64 is supported")
|
||||||
|
|
||||||
func (dbp *Process) findExecutable(path string) (*pe.File, error) {
|
func (dbp *Process) findExecutable(path string) (*pe.File, error) {
|
||||||
if path == "" {
|
|
||||||
// TODO: Find executable path from PID/handle on Windows:
|
|
||||||
// https://msdn.microsoft.com/en-us/library/aa366789(VS.85).aspx
|
|
||||||
return nil, fmt.Errorf("not yet implemented")
|
|
||||||
}
|
|
||||||
peFile, err := openExecutablePath(path)
|
peFile, err := openExecutablePath(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@ -69,6 +69,9 @@ const (
|
|||||||
_UNLOAD_DLL_DEBUG_EVENT = 7
|
_UNLOAD_DLL_DEBUG_EVENT = 7
|
||||||
_OUTPUT_DEBUG_STRING_EVENT = 8
|
_OUTPUT_DEBUG_STRING_EVENT = 8
|
||||||
_RIP_EVENT = 9
|
_RIP_EVENT = 9
|
||||||
|
|
||||||
|
// DEBUG_ONLY_THIS_PROCESS tracks https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx
|
||||||
|
_DEBUG_ONLY_THIS_PROCESS = 0x00000002
|
||||||
)
|
)
|
||||||
|
|
||||||
func _NT_SUCCESS(x _NTSTATUS) bool {
|
func _NT_SUCCESS(x _NTSTATUS) bool {
|
||||||
@ -85,3 +88,5 @@ func _NT_SUCCESS(x _NTSTATUS) bool {
|
|||||||
//sys _ReadProcessMemory(process syscall.Handle, baseaddr uintptr, buffer *byte, size uintptr, bytesread *uintptr) (err error) = kernel32.ReadProcessMemory
|
//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 _DebugBreakProcess(process syscall.Handle) (err error) = kernel32.DebugBreakProcess
|
||||||
//sys _WaitForDebugEvent(debugevent *_DEBUG_EVENT, milliseconds uint32) (err error) = kernel32.WaitForDebugEvent
|
//sys _WaitForDebugEvent(debugevent *_DEBUG_EVENT, milliseconds uint32) (err error) = kernel32.WaitForDebugEvent
|
||||||
|
//sys _DebugActiveProcess(processid uint32) (err error) = kernel32.DebugActiveProcess
|
||||||
|
//sys _QueryFullProcessImageName(process syscall.Handle, flags uint32, exename *uint16, size *uint32) (err error) = kernel32.QueryFullProcessImageNameW
|
||||||
|
|||||||
@ -2,8 +2,10 @@
|
|||||||
|
|
||||||
package proc
|
package proc
|
||||||
|
|
||||||
import "unsafe"
|
import (
|
||||||
import "syscall"
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
var _ unsafe.Pointer
|
var _ unsafe.Pointer
|
||||||
|
|
||||||
@ -11,16 +13,18 @@ var (
|
|||||||
modntdll = syscall.NewLazyDLL("ntdll.dll")
|
modntdll = syscall.NewLazyDLL("ntdll.dll")
|
||||||
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
|
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||||
|
|
||||||
procNtQueryInformationThread = modntdll.NewProc("NtQueryInformationThread")
|
procNtQueryInformationThread = modntdll.NewProc("NtQueryInformationThread")
|
||||||
procGetThreadContext = modkernel32.NewProc("GetThreadContext")
|
procGetThreadContext = modkernel32.NewProc("GetThreadContext")
|
||||||
procSetThreadContext = modkernel32.NewProc("SetThreadContext")
|
procSetThreadContext = modkernel32.NewProc("SetThreadContext")
|
||||||
procSuspendThread = modkernel32.NewProc("SuspendThread")
|
procSuspendThread = modkernel32.NewProc("SuspendThread")
|
||||||
procResumeThread = modkernel32.NewProc("ResumeThread")
|
procResumeThread = modkernel32.NewProc("ResumeThread")
|
||||||
procContinueDebugEvent = modkernel32.NewProc("ContinueDebugEvent")
|
procContinueDebugEvent = modkernel32.NewProc("ContinueDebugEvent")
|
||||||
procWriteProcessMemory = modkernel32.NewProc("WriteProcessMemory")
|
procWriteProcessMemory = modkernel32.NewProc("WriteProcessMemory")
|
||||||
procReadProcessMemory = modkernel32.NewProc("ReadProcessMemory")
|
procReadProcessMemory = modkernel32.NewProc("ReadProcessMemory")
|
||||||
procDebugBreakProcess = modkernel32.NewProc("DebugBreakProcess")
|
procDebugBreakProcess = modkernel32.NewProc("DebugBreakProcess")
|
||||||
procWaitForDebugEvent = modkernel32.NewProc("WaitForDebugEvent")
|
procWaitForDebugEvent = modkernel32.NewProc("WaitForDebugEvent")
|
||||||
|
procDebugActiveProcess = modkernel32.NewProc("DebugActiveProcess")
|
||||||
|
procQueryFullProcessImageNameW = modkernel32.NewProc("QueryFullProcessImageNameW")
|
||||||
)
|
)
|
||||||
|
|
||||||
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) {
|
||||||
@ -138,3 +142,27 @@ func _WaitForDebugEvent(debugevent *_DEBUG_EVENT, milliseconds uint32) (err erro
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func _DebugActiveProcess(processid uint32) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall(procDebugActiveProcess.Addr(), 1, uintptr(processid), 0, 0)
|
||||||
|
if r1 == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = error(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func _QueryFullProcessImageName(process syscall.Handle, flags uint32, exename *uint16, size *uint32) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall6(procQueryFullProcessImageNameW.Addr(), 4, uintptr(process), uintptr(flags), uintptr(unsafe.Pointer(exename)), uintptr(unsafe.Pointer(size)), 0, 0)
|
||||||
|
if r1 == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = error(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user