gitlab.com/Raven-IO/raven-delve@v1.22.4/pkg/proc/native/proc_windows.go (about) 1 package native 2 3 import ( 4 "fmt" 5 "os" 6 "strings" 7 "syscall" 8 "unicode/utf16" 9 "unsafe" 10 11 sys "golang.org/x/sys/windows" 12 13 "gitlab.com/Raven-IO/raven-delve/pkg/logflags" 14 "gitlab.com/Raven-IO/raven-delve/pkg/proc" 15 "gitlab.com/Raven-IO/raven-delve/pkg/proc/internal/ebpf" 16 ) 17 18 // osProcessDetails holds Windows specific information. 19 type osProcessDetails struct { 20 hProcess syscall.Handle 21 breakThread int 22 entryPoint uint64 23 running bool 24 } 25 26 func (os *osProcessDetails) Close() {} 27 28 // Launch creates and begins debugging a new process. 29 func Launch(cmd []string, wd string, flags proc.LaunchFlags, _ []string, _ string, stdinPath string, stdoutOR proc.OutputRedirect, stderrOR proc.OutputRedirect) (*proc.TargetGroup, error) { 30 argv0Go := cmd[0] 31 32 env := proc.DisableAsyncPreemptEnv() 33 34 stdin, stdout, stderr, closefn, err := openRedirects(stdinPath, stdoutOR, stderrOR, true) 35 if err != nil { 36 return nil, err 37 } 38 39 creationFlags := uint32(_DEBUG_PROCESS) 40 if flags&proc.LaunchForeground == 0 { 41 creationFlags |= syscall.CREATE_NEW_PROCESS_GROUP 42 } 43 44 var p *os.Process 45 dbp := newProcess(0) 46 dbp.execPtraceFunc(func() { 47 attr := &os.ProcAttr{ 48 Dir: wd, 49 Files: []*os.File{stdin, stdout, stderr}, 50 Sys: &syscall.SysProcAttr{ 51 CreationFlags: creationFlags, 52 }, 53 Env: env, 54 } 55 p, err = os.StartProcess(argv0Go, cmd, attr) 56 }) 57 closefn() 58 if err != nil { 59 return nil, err 60 } 61 defer p.Release() 62 63 dbp.pid = p.Pid 64 dbp.childProcess = true 65 66 tgt, err := dbp.initialize(argv0Go, []string{}) 67 if err != nil { 68 detachWithoutGroup(dbp, true) 69 return nil, err 70 } 71 return tgt, nil 72 } 73 74 func initialize(dbp *nativeProcess) (string, error) { 75 // we need a fake procgrp to call waitForDebugEvent 76 procgrp := &processGroup{procs: []*nativeProcess{dbp}} 77 // It should not actually be possible for the 78 // call to waitForDebugEvent to fail, since Windows 79 // will always fire a CREATE_PROCESS_DEBUG_EVENT event 80 // immediately after launching under DEBUG_ONLY_THIS_PROCESS. 81 // Attaching with DebugActiveProcess has similar effect. 82 var err error 83 dbp.execPtraceFunc(func() { 84 _, err = procgrp.waitForDebugEvent(waitBlocking) 85 }) 86 if err != nil { 87 return "", err 88 } 89 90 cmdline := getCmdLine(dbp.os.hProcess) 91 92 // Suspend all threads so that the call to _ContinueDebugEvent will 93 // not resume the target. 94 for _, thread := range dbp.threads { 95 if !thread.os.dbgUiRemoteBreakIn { 96 _, err := _SuspendThread(thread.os.hThread) 97 if err != nil { 98 return "", err 99 } 100 } 101 } 102 103 dbp.execPtraceFunc(func() { 104 err = _ContinueDebugEvent(uint32(dbp.pid), uint32(dbp.os.breakThread), _DBG_CONTINUE) 105 }) 106 return cmdline, err 107 } 108 109 // findExePath searches for process pid, and returns its executable path 110 func findExePath(pid int) (string, error) { 111 // Original code suggested different approach (see below). 112 // Maybe it could be useful in the future. 113 // 114 // Find executable path from PID/handle on Windows: 115 // https://msdn.microsoft.com/en-us/library/aa366789(VS.85).aspx 116 117 p, err := syscall.OpenProcess(syscall.PROCESS_QUERY_INFORMATION, false, uint32(pid)) 118 if err != nil { 119 return "", err 120 } 121 defer syscall.CloseHandle(p) 122 123 n := uint32(128) 124 for { 125 buf := make([]uint16, int(n)) 126 err = _QueryFullProcessImageName(p, 0, &buf[0], &n) 127 switch err { 128 case syscall.ERROR_INSUFFICIENT_BUFFER: 129 // try bigger buffer 130 n *= 2 131 // but stop if it gets too big 132 if n > 10000 { 133 return "", err 134 } 135 case nil: 136 return syscall.UTF16ToString(buf[:n]), nil 137 default: 138 return "", err 139 } 140 } 141 } 142 143 var debugPrivilegeRequested = false 144 145 // Attach to an existing process with the given PID. 146 func Attach(pid int, waitFor *proc.WaitFor, _ []string) (*proc.TargetGroup, error) { 147 var aperr error 148 if !debugPrivilegeRequested { 149 debugPrivilegeRequested = true 150 // The following call will only work if the user is an administrator 151 // has the "Debug Programs" privilege in Local security settings. 152 // Since this privilege is not needed to debug processes owned by the 153 // current user, do not complain about this unless attach actually fails. 154 aperr = acquireDebugPrivilege() 155 } 156 157 if waitFor.Valid() { 158 var err error 159 pid, err = WaitFor(waitFor) 160 if err != nil { 161 return nil, err 162 } 163 } 164 165 dbp := newProcess(pid) 166 var err error 167 dbp.execPtraceFunc(func() { 168 // TODO: Probably should have SeDebugPrivilege before starting here. 169 err = _DebugActiveProcess(uint32(pid)) 170 }) 171 if err != nil { 172 if aperr != nil { 173 return nil, fmt.Errorf("%v also %v", err, aperr) 174 } 175 return nil, err 176 } 177 exepath, err := findExePath(pid) 178 if err != nil { 179 return nil, err 180 } 181 tgt, err := dbp.initialize(exepath, []string{}) 182 if err != nil { 183 detachWithoutGroup(dbp, true) 184 return nil, err 185 } 186 return tgt, nil 187 } 188 189 // acquireDebugPrivilege acquires the debug privilege which is needed to 190 // debug other user's processes. 191 // See: 192 // 193 // - https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/debug-privilege 194 // - https://gitlab.com/Raven-IO/raven-delve/issues/3136 195 func acquireDebugPrivilege() error { 196 var token sys.Token 197 err := sys.OpenProcessToken(sys.CurrentProcess(), sys.TOKEN_QUERY|sys.TOKEN_ADJUST_PRIVILEGES, &token) 198 if err != nil { 199 return fmt.Errorf("could not acquire debug privilege (OpenCurrentProcessToken): %v", err) 200 } 201 defer token.Close() 202 203 privName, _ := sys.UTF16FromString("SeDebugPrivilege") 204 var luid sys.LUID 205 err = sys.LookupPrivilegeValue(nil, &privName[0], &luid) 206 if err != nil { 207 return fmt.Errorf("could not acquire debug privilege (LookupPrivilegeValue): %v", err) 208 } 209 210 var tp sys.Tokenprivileges 211 tp.PrivilegeCount = 1 212 tp.Privileges[0].Luid = luid 213 tp.Privileges[0].Attributes = sys.SE_PRIVILEGE_ENABLED 214 215 err = sys.AdjustTokenPrivileges(token, false, &tp, 0, nil, nil) 216 if err != nil { 217 return fmt.Errorf("could not acquire debug privilege (AdjustTokenPrivileges): %v", err) 218 } 219 220 return nil 221 } 222 223 func waitForSearchProcess(pfx string, seen map[int]struct{}) (int, error) { 224 log := logflags.DebuggerLogger() 225 handle, err := sys.CreateToolhelp32Snapshot(sys.TH32CS_SNAPPROCESS, 0) 226 if err != nil { 227 return 0, fmt.Errorf("could not get process list: %v", err) 228 } 229 defer sys.CloseHandle(handle) 230 231 var entry sys.ProcessEntry32 232 entry.Size = uint32(unsafe.Sizeof(entry)) 233 err = sys.Process32First(handle, &entry) 234 if err != nil { 235 return 0, fmt.Errorf("could not get process list: %v", err) 236 } 237 238 for err = sys.Process32First(handle, &entry); err == nil; err = sys.Process32Next(handle, &entry) { 239 if _, isseen := seen[int(entry.ProcessID)]; isseen { 240 continue 241 } 242 seen[int(entry.ProcessID)] = struct{}{} 243 244 hProcess, err := sys.OpenProcess(sys.PROCESS_QUERY_INFORMATION|sys.PROCESS_VM_READ, false, entry.ProcessID) 245 if err != nil { 246 continue 247 } 248 cmdline := getCmdLine(syscall.Handle(hProcess)) 249 sys.CloseHandle(hProcess) 250 251 log.Debugf("waitfor: new process %q", cmdline) 252 if strings.HasPrefix(cmdline, pfx) { 253 return int(entry.ProcessID), nil 254 } 255 } 256 257 return 0, nil 258 } 259 260 // kill kills the process. 261 func (procgrp *processGroup) kill(dbp *nativeProcess) error { 262 if ok, _ := dbp.Valid(); !ok { 263 return nil 264 } 265 266 p, err := os.FindProcess(dbp.pid) 267 if err != nil { 268 return err 269 } 270 defer p.Release() 271 272 // TODO: Should not have to ignore failures here, 273 // but some tests appear to Kill twice causing 274 // this to fail on second attempt. 275 _ = syscall.TerminateProcess(dbp.os.hProcess, 1) 276 277 dbp.execPtraceFunc(func() { 278 procgrp.waitForDebugEvent(waitBlocking | waitDontHandleExceptions) 279 }) 280 281 p.Wait() 282 283 dbp.postExit() 284 return nil 285 } 286 287 func (dbp *nativeProcess) requestManualStop() error { 288 if !dbp.os.running { 289 return nil 290 } 291 dbp.os.running = false 292 return _DebugBreakProcess(dbp.os.hProcess) 293 } 294 295 func (dbp *nativeProcess) updateThreadList() error { 296 // We ignore this request since threads are being 297 // tracked as they are created/killed in waitForDebugEvent. 298 return nil 299 } 300 301 func (dbp *nativeProcess) addThread(hThread syscall.Handle, threadID int, attach, suspendNewThreads bool, dbgUiRemoteBreakIn bool) (*nativeThread, error) { 302 if thread, ok := dbp.threads[threadID]; ok { 303 return thread, nil 304 } 305 thread := &nativeThread{ 306 ID: threadID, 307 dbp: dbp, 308 os: new(osSpecificDetails), 309 } 310 thread.os.dbgUiRemoteBreakIn = dbgUiRemoteBreakIn 311 thread.os.hThread = hThread 312 dbp.threads[threadID] = thread 313 if dbp.memthread == nil { 314 dbp.memthread = dbp.threads[threadID] 315 } 316 if suspendNewThreads && !dbgUiRemoteBreakIn { 317 _, err := _SuspendThread(thread.os.hThread) 318 if err != nil { 319 return nil, err 320 } 321 } 322 323 for _, bp := range dbp.Breakpoints().M { 324 if bp.WatchType != 0 { 325 err := thread.writeHardwareBreakpoint(bp.Addr, bp.WatchType, bp.HWBreakIndex) 326 if err != nil { 327 return nil, err 328 } 329 } 330 } 331 332 return thread, nil 333 } 334 335 type waitForDebugEventFlags int 336 337 const ( 338 waitBlocking waitForDebugEventFlags = 1 << iota 339 waitSuspendNewThreads 340 waitDontHandleExceptions 341 ) 342 343 const _MS_VC_EXCEPTION = 0x406D1388 // part of VisualC protocol to set thread names 344 345 func (procgrp *processGroup) waitForDebugEvent(flags waitForDebugEventFlags) (threadID int, err error) { 346 var debugEvent _DEBUG_EVENT 347 for { 348 continueStatus := uint32(_DBG_CONTINUE) 349 var milliseconds uint32 = 0 350 if flags&waitBlocking != 0 { 351 milliseconds = syscall.INFINITE 352 } 353 // Wait for a debug event... 354 err := _WaitForDebugEvent(&debugEvent, milliseconds) 355 if err != nil { 356 return 0, err 357 } 358 359 // ... handle each event kind ... 360 unionPtr := unsafe.Pointer(&debugEvent.U[0]) 361 switch debugEvent.DebugEventCode { 362 case _CREATE_PROCESS_DEBUG_EVENT: 363 debugInfo := (*_CREATE_PROCESS_DEBUG_INFO)(unionPtr) 364 hFile := debugInfo.File 365 if hFile != 0 && hFile != syscall.InvalidHandle { 366 err = syscall.CloseHandle(hFile) 367 if err != nil { 368 return 0, err 369 } 370 } 371 var dbp *nativeProcess 372 if procgrp.addTarget == nil { 373 // This is a fake process group and waitForDebugEvent has been called 374 // just after attach/launch, finish configuring the root process. 375 dbp = procgrp.procs[0] 376 } else { 377 // Add new child process 378 dbp = newChildProcess(procgrp.procs[0], int(debugEvent.ProcessId)) 379 } 380 381 dbp.os.entryPoint = uint64(debugInfo.BaseOfImage) 382 dbp.os.hProcess = debugInfo.Process 383 _, err = dbp.addThread(debugInfo.Thread, int(debugEvent.ThreadId), false, 384 flags&waitSuspendNewThreads != 0, debugInfo.StartAddress == dbgUiRemoteBreakin.Addr()) 385 if err != nil { 386 return 0, err 387 } 388 389 if procgrp.addTarget != nil { 390 exe, err := findExePath(dbp.pid) 391 if err != nil { 392 return 0, err 393 } 394 tgt, err := procgrp.add(dbp, dbp.pid, dbp.memthread, exe, proc.StopLaunched, getCmdLine(dbp.os.hProcess)) 395 if err != nil { 396 return 0, err 397 } 398 if tgt == nil { 399 continue 400 } 401 } 402 break 403 case _CREATE_THREAD_DEBUG_EVENT: 404 debugInfo := (*_CREATE_THREAD_DEBUG_INFO)(unionPtr) 405 dbp := procgrp.procForPid(int(debugEvent.ProcessId)) 406 _, err = dbp.addThread(debugInfo.Thread, int(debugEvent.ThreadId), false, 407 flags&waitSuspendNewThreads != 0, debugInfo.StartAddress == dbgUiRemoteBreakin.Addr()) 408 if err != nil { 409 return 0, err 410 } 411 break 412 case _EXIT_THREAD_DEBUG_EVENT: 413 dbp := procgrp.procForPid(int(debugEvent.ProcessId)) 414 delete(dbp.threads, int(debugEvent.ThreadId)) 415 break 416 case _OUTPUT_DEBUG_STRING_EVENT: 417 //TODO: Handle debug output strings 418 break 419 case _LOAD_DLL_DEBUG_EVENT: 420 debugInfo := (*_LOAD_DLL_DEBUG_INFO)(unionPtr) 421 hFile := debugInfo.File 422 if hFile != 0 && hFile != syscall.InvalidHandle { 423 err = syscall.CloseHandle(hFile) 424 if err != nil { 425 return 0, err 426 } 427 } 428 break 429 case _UNLOAD_DLL_DEBUG_EVENT: 430 break 431 case _RIP_EVENT: 432 break 433 case _EXCEPTION_DEBUG_EVENT: 434 if flags&waitDontHandleExceptions != 0 { 435 continueStatus = _DBG_EXCEPTION_NOT_HANDLED 436 break 437 } 438 exception := (*_EXCEPTION_DEBUG_INFO)(unionPtr) 439 tid := int(debugEvent.ThreadId) 440 dbp := procgrp.procForPid(int(debugEvent.ProcessId)) 441 442 switch code := exception.ExceptionRecord.ExceptionCode; code { 443 case _EXCEPTION_BREAKPOINT: 444 445 // check if the exception address really is a breakpoint instruction, if 446 // it isn't we already removed that breakpoint and we can't deal with 447 // this exception anymore. 448 atbp := true 449 if thread, found := dbp.threads[tid]; found { 450 data := make([]byte, dbp.bi.Arch.BreakpointSize()) 451 if _, err := thread.ReadMemory(data, uint64(exception.ExceptionRecord.ExceptionAddress)); err == nil { 452 instr := dbp.bi.Arch.BreakpointInstruction() 453 for i := range instr { 454 if data[i] != instr[i] { 455 atbp = false 456 break 457 } 458 } 459 } 460 if !atbp { 461 thread.setPC(uint64(exception.ExceptionRecord.ExceptionAddress)) 462 } 463 } 464 465 if atbp { 466 dbp.os.breakThread = tid 467 if th := dbp.threads[tid]; th != nil { 468 th.os.setbp = true 469 } 470 return tid, nil 471 } else { 472 continueStatus = _DBG_CONTINUE 473 } 474 case _EXCEPTION_SINGLE_STEP: 475 dbp.os.breakThread = tid 476 return tid, nil 477 case _MS_VC_EXCEPTION: 478 // This exception is sent to set the thread name in VisualC, we should 479 // mask it or it might crash the program. 480 continueStatus = _DBG_CONTINUE 481 default: 482 continueStatus = _DBG_EXCEPTION_NOT_HANDLED 483 } 484 case _EXIT_PROCESS_DEBUG_EVENT: 485 debugInfo := (*_EXIT_PROCESS_DEBUG_INFO)(unionPtr) 486 dbp := procgrp.procForPid(int(debugEvent.ProcessId)) 487 dbp.postExit() 488 if procgrp.numValid() == 0 { 489 err = _ContinueDebugEvent(debugEvent.ProcessId, debugEvent.ThreadId, continueStatus) 490 if err != nil { 491 return 0, err 492 } 493 return 0, proc.ErrProcessExited{Pid: dbp.pid, Status: int(debugInfo.ExitCode)} 494 } 495 default: 496 return 0, fmt.Errorf("unknown debug event code: %d", debugEvent.DebugEventCode) 497 } 498 499 // .. and then continue unless we received an event that indicated we should break into debugger. 500 err = _ContinueDebugEvent(debugEvent.ProcessId, debugEvent.ThreadId, continueStatus) 501 if err != nil { 502 return 0, err 503 } 504 } 505 } 506 507 func trapWait(procgrp *processGroup, pid int) (*nativeThread, error) { 508 var err error 509 var tid int 510 procgrp.procs[0].execPtraceFunc(func() { 511 tid, err = procgrp.waitForDebugEvent(waitBlocking) 512 }) 513 if err != nil { 514 return nil, err 515 } 516 th := procgrp.procForThread(tid).threads[tid] 517 return th, nil 518 } 519 520 func (dbp *nativeProcess) exitGuard(err error) error { 521 return err 522 } 523 524 func (procgrp *processGroup) resume() error { 525 for _, dbp := range procgrp.procs { 526 if valid, _ := dbp.Valid(); !valid { 527 continue 528 } 529 for _, thread := range dbp.threads { 530 if thread.CurrentBreakpoint.Breakpoint != nil { 531 if err := procgrp.stepInstruction(thread); err != nil { 532 return err 533 } 534 thread.CurrentBreakpoint.Clear() 535 } 536 } 537 } 538 539 for _, dbp := range procgrp.procs { 540 if valid, _ := dbp.Valid(); !valid { 541 continue 542 } 543 for _, thread := range dbp.threads { 544 _, err := _ResumeThread(thread.os.hThread) 545 if err != nil { 546 return err 547 } 548 } 549 dbp.os.running = true 550 } 551 552 return nil 553 } 554 555 // stop stops all running threads threads and sets breakpoints 556 func (procgrp *processGroup) stop(cctx *proc.ContinueOnceContext, trapthread *nativeThread) (*nativeThread, error) { 557 if procgrp.numValid() == 0 { 558 return nil, proc.ErrProcessExited{Pid: procgrp.procs[0].pid} 559 } 560 561 trapproc := procgrp.procForThread(trapthread.ID) 562 trapproc.os.running = false 563 564 for _, dbp := range procgrp.procs { 565 for _, th := range dbp.threads { 566 th.os.setbp = false 567 } 568 } 569 570 trapthread.os.setbp = true 571 572 // While the debug event that stopped the target was being propagated 573 // other target threads could generate other debug events. 574 // After this function we need to know about all the threads 575 // stopped on a breakpoint. To do that we first suspend all target 576 // threads and then repeatedly call _ContinueDebugEvent followed by 577 // waitForDebugEvent in non-blocking mode. 578 // We need to explicitly call SuspendThread because otherwise the 579 // call to _ContinueDebugEvent will resume execution of some of the 580 // target threads. 581 582 err := trapthread.SetCurrentBreakpoint(true) 583 if err != nil { 584 return nil, err 585 } 586 587 for _, dbp := range procgrp.procs { 588 if valid, _ := dbp.Valid(); !valid { 589 continue 590 } 591 dbp.suspendAllThreads() 592 } 593 594 lastEventProc := trapproc 595 for { 596 var err error 597 var tid int 598 lastEventProc.execPtraceFunc(func() { 599 err = _ContinueDebugEvent(uint32(lastEventProc.pid), uint32(lastEventProc.os.breakThread), _DBG_CONTINUE) 600 if err == nil { 601 tid, _ = procgrp.waitForDebugEvent(waitSuspendNewThreads) 602 } 603 }) 604 if err != nil { 605 return nil, err 606 } 607 if tid == 0 { 608 break 609 } 610 dbp := procgrp.procForThread(tid) 611 err = dbp.threads[tid].SetCurrentBreakpoint(true) 612 if err != nil { 613 return nil, err 614 } 615 lastEventProc = dbp 616 } 617 618 // Check if trapthread still exist, if the process is dying it could have 619 // been removed while we were stopping the other threads. 620 trapthreadFound := false 621 for _, thread := range trapproc.threads { 622 if thread.ID == trapthread.ID { 623 trapthreadFound = true 624 } 625 if thread.os.delayErr != nil && thread.os.delayErr != syscall.Errno(0x5) { 626 // Do not report Access is denied error, it is caused by the thread 627 // having already died but we haven't been notified about it yet. 628 return nil, thread.os.delayErr 629 } 630 } 631 632 if !trapthreadFound { 633 wasDbgUiRemoteBreakIn := trapthread.os.dbgUiRemoteBreakIn 634 // trapthread exited during stop, pick another one 635 trapthread = nil 636 for _, thread := range trapproc.threads { 637 if thread.CurrentBreakpoint.Breakpoint != nil && thread.os.delayErr == nil { 638 trapthread = thread 639 break 640 } 641 } 642 if trapthread == nil && wasDbgUiRemoteBreakIn { 643 // If this was triggered by a manual stop request we should stop 644 // regardless, pick a thread. 645 for _, thread := range trapproc.threads { 646 return thread, nil 647 } 648 } 649 } 650 651 return trapthread, nil 652 } 653 654 func (dbp *nativeProcess) suspendAllThreads() { 655 context := newContext() 656 for _, thread := range dbp.threads { 657 thread.os.delayErr = nil 658 if !thread.os.dbgUiRemoteBreakIn { 659 // Wait before reporting the error, the thread could be removed when we 660 // call waitForDebugEvent in the next loop. 661 _, thread.os.delayErr = _SuspendThread(thread.os.hThread) 662 if thread.os.delayErr == nil { 663 // This call will block until the thread has stopped. 664 _ = thread.getContext(context) 665 } 666 } 667 } 668 } 669 670 func (procgrp *processGroup) detachChild(dbp *nativeProcess) error { 671 for _, thread := range dbp.threads { 672 _, err := _ResumeThread(thread.os.hThread) 673 if err != nil { 674 return err 675 } 676 } 677 err := _DebugActiveProcessStop(uint32(dbp.pid)) 678 dbp.detached = true 679 dbp.postExit() 680 return err 681 } 682 683 func (dbp *nativeProcess) detach(kill bool) error { 684 if !kill { 685 //TODO(aarzilli): when debug.Target exist Detach should be moved to 686 // debug.Target and the call to RestoreAsyncPreempt should be moved there. 687 for _, thread := range dbp.threads { 688 _, err := _ResumeThread(thread.os.hThread) 689 if err != nil { 690 return err 691 } 692 } 693 } 694 return _DebugActiveProcessStop(uint32(dbp.pid)) 695 } 696 697 func (dbp *nativeProcess) EntryPoint() (uint64, error) { 698 return dbp.os.entryPoint, nil 699 } 700 701 func (dbp *nativeProcess) SupportsBPF() bool { 702 return false 703 } 704 705 func (dbp *nativeProcess) SetUProbe(fnName string, goidOffset int64, args []ebpf.UProbeArgMap) error { 706 return nil 707 } 708 709 func (dbp *nativeProcess) GetBufferedTracepoints() []ebpf.RawUProbeParams { 710 return nil 711 } 712 713 type _PROCESS_BASIC_INFORMATION struct { 714 ExitStatus sys.NTStatus 715 PebBaseAddress uintptr 716 AffinityMask uintptr 717 BasePriority int32 718 UniqueProcessId uintptr 719 InheritedFromUniqueProcessId uintptr 720 } 721 722 type _PEB struct { 723 reserved1 [2]byte 724 BeingDebugged byte 725 BitField byte 726 reserved3 uintptr 727 ImageBaseAddress uintptr 728 Ldr uintptr 729 ProcessParameters uintptr 730 reserved4 [3]uintptr 731 AtlThunkSListPtr uintptr 732 reserved5 uintptr 733 reserved6 uint32 734 reserved7 uintptr 735 reserved8 uint32 736 AtlThunkSListPtr32 uint32 737 reserved9 [45]uintptr 738 reserved10 [96]byte 739 PostProcessInitRoutine uintptr 740 reserved11 [128]byte 741 reserved12 [1]uintptr 742 SessionId uint32 743 } 744 745 type _RTL_USER_PROCESS_PARAMETERS struct { 746 MaximumLength, Length uint32 747 748 Flags, DebugFlags uint32 749 750 ConsoleHandle sys.Handle 751 ConsoleFlags uint32 752 StandardInput, StandardOutput, StandardError sys.Handle 753 754 CurrentDirectory struct { 755 DosPath _NTUnicodeString 756 Handle sys.Handle 757 } 758 759 DllPath _NTUnicodeString 760 ImagePathName _NTUnicodeString 761 CommandLine _NTUnicodeString 762 Environment unsafe.Pointer 763 764 StartingX, StartingY, CountX, CountY, CountCharsX, CountCharsY, FillAttribute uint32 765 766 WindowFlags, ShowWindowFlags uint32 767 WindowTitle, DesktopInfo, ShellInfo, RuntimeData _NTUnicodeString 768 CurrentDirectories [32]struct { 769 Flags uint16 770 Length uint16 771 TimeStamp uint32 772 DosPath _NTString 773 } 774 775 EnvironmentSize, EnvironmentVersion uintptr 776 777 PackageDependencyData uintptr 778 ProcessGroupId uint32 779 LoaderThreads uint32 780 781 RedirectionDllName _NTUnicodeString 782 HeapPartitionName _NTUnicodeString 783 DefaultThreadpoolCpuSetMasks uintptr 784 DefaultThreadpoolCpuSetMaskCount uint32 785 } 786 787 type _NTString struct { 788 Length uint16 789 MaximumLength uint16 790 Buffer uintptr 791 } 792 793 type _NTUnicodeString struct { 794 Length uint16 795 MaximumLength uint16 796 Buffer uintptr 797 } 798 799 func getCmdLine(hProcess syscall.Handle) string { 800 logger := logflags.DebuggerLogger() 801 var info _PROCESS_BASIC_INFORMATION 802 err := sys.NtQueryInformationProcess(sys.Handle(hProcess), sys.ProcessBasicInformation, unsafe.Pointer(&info), uint32(unsafe.Sizeof(info)), nil) 803 if err != nil { 804 logger.Errorf("NtQueryInformationProcess: %v", err) 805 return "" 806 } 807 var peb _PEB 808 err = _ReadProcessMemory(hProcess, info.PebBaseAddress, (*byte)(unsafe.Pointer(&peb)), unsafe.Sizeof(peb), nil) 809 if err != nil { 810 logger.Errorf("Reading PEB: %v", err) 811 return "" 812 } 813 var upp _RTL_USER_PROCESS_PARAMETERS 814 err = _ReadProcessMemory(hProcess, peb.ProcessParameters, (*byte)(unsafe.Pointer(&upp)), unsafe.Sizeof(upp), nil) 815 if err != nil { 816 logger.Errorf("Reading ProcessParameters: %v", err) 817 return "" 818 } 819 if upp.CommandLine.Length%2 != 0 { 820 logger.Errorf("CommandLine length not a multiple of 2") 821 return "" 822 } 823 buf := make([]byte, upp.CommandLine.Length) 824 err = _ReadProcessMemory(hProcess, upp.CommandLine.Buffer, &buf[0], uintptr(len(buf)), nil) 825 if err != nil { 826 logger.Errorf("Reading CommandLine: %v", err) 827 return "" 828 } 829 utf16buf := make([]uint16, len(buf)/2) 830 for i := 0; i < len(buf); i += 2 { 831 utf16buf[i/2] = uint16(buf[i+1])<<8 + uint16(buf[i]) 832 } 833 return string(utf16.Decode(utf16buf)) 834 } 835 836 // FollowExec enables (or disables) follow exec mode 837 func (dbp *nativeProcess) FollowExec(v bool) error { 838 dbp.followExec = v 839 return nil 840 } 841 842 func killProcess(pid int) error { 843 p, err := os.FindProcess(pid) 844 if err != nil { 845 return err 846 } 847 defer p.Release() 848 849 return p.Kill() 850 }