• win32获取进程树,以及命令行参数


    1.先上代码

    package main
    
    import (
    	"bytes"
    	"errors"
    	"flag"
    	"fmt"
    	"io"
    	"os"
    	"sort"
    	"syscall"
    	"unsafe"
    )
    
    func main() {
    	out := flag.String("o", "-", "write result to file, - eq stdout")
    	flag.Parse()
    
    	procMap := make(map[uint32]*Process, 32)
    	err := ForEachProcessEntry(func(entry *syscall.ProcessEntry32) error {
    		cmdline, err := GetCmdline(entry.ProcessID)
    		if err != nil {
    			return err
    		}
    		procMap[entry.ProcessID] = &Process{
    			Pid:      entry.ProcessID,
    			Ppid:     entry.ParentProcessID,
    			Name:     syscall.UTF16ToString(entry.ExeFile[:]),
    			Cmdline:  cmdline,
    			Children: make(map[uint32]*Process),
    		}
    		return nil
    	})
    	if err != nil {
    		fmt.Println("ForEachProcessEntry:", err)
    		return
    	}
    	proc := make(ProcessSlice, 0, 32)
    	for _, v := range procMap {
    		if v.Pid == 0 {
    			proc = append(proc, v)
    			continue // 系统进程
    		}
    		tmp, ok := procMap[v.Ppid]
    		if ok {
    			tmp.Children[v.Pid] = v
    		} else {
    			proc = append(proc, v)
    		}
    	}
    	sort.Sort(proc)
    
    	var fmtOut *os.File
    	if *out == "-" {
    		fmtOut = os.Stdout
    	} else {
    		fmtOut, err = os.Create(*out)
    		if err != nil {
    			fmt.Println("os.Create:", *out, ",error:", err)
    			return
    		}
    		defer fmtOut.Close()
    	}
    
    	str := bytes.NewBufferString("%10d,%10d:")
    	for _, v := range proc {
    		fmt.Fprintf(fmtOut, "%10d,%10d: name:[%s], cmdline:[%s]
    ", v.Pid, v.Ppid, v.Name, v.Cmdline)
    		WriteChildren(fmtOut, v.Children, str, 1)
    	}
    }
    
    func WriteChildren(w io.Writer, children map[uint32]*Process, strFmt *bytes.Buffer, layer int) {
    	if len(children) == 0 {
    		return
    	}
    	strFmt.Truncate(10 /* len("%10d,%10d:") */)
    	for i := 0; i < layer*4; i++ {
    		if i > 0 && i%4 == 0 {
    			strFmt.WriteByte('|')
    		}
    		strFmt.WriteByte(' ')
    	}
    	strFmt.WriteString("\_ name:[%s], cmdline:[%s]
    ")
    	fmtStr := strFmt.String()
    	layer++
    	for _, v := range children {
    		fmt.Fprintf(w, fmtStr, v.Pid, v.Ppid, v.Name, v.Cmdline)
    		WriteChildren(w, v.Children, strFmt, layer) // 递归打印子进程
    	}
    }
    
    type (
    	Process struct {
    		Pid, Ppid uint32
    		Name      string
    		Cmdline   string
    		Children  map[uint32]*Process
    	}
    	ProcessSlice []*Process
    )
    
    func (d ProcessSlice) Less(i, j int) bool {
    	return d[i].Pid < d[j].Pid
    }
    
    func (d ProcessSlice) Swap(i, j int) {
    	d[i], d[j] = d[j], d[i]
    }
    
    func (d ProcessSlice) Len() int {
    	return len(d)
    }
    
    var (
    	ntQueryInformationProcess = syscall.MustLoadDLL("ntdll.dll").MustFindProc("NtQueryInformationProcess")
    	readProcessMemory         = syscall.MustLoadDLL("kernel32.dll").MustFindProc("ReadProcessMemory")
    )
    
    func GetCmdline(pid uint32) (string, error) {
    	/* 翻译这个C++代码: https://stackoverflow.com/a/42341811/11844632 */
    	if pid == 0 { // 系统进程,无法读取
    		return "", nil
    	}
    	const (
    		PROCESS_QUERY_INFORMATION = 0x0400 // 定义在winnt.h
    		PROCESS_VM_READ           = 0x0010 // 定义在winnt.h
    		ProcessParameters         = 32     // ntddk.h的头文件分析的指针偏移
    		CommandLine               = 112    // winternl.h的头文件分析的指针偏移
    	)
    	h, err := syscall.OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, false, pid)
    	if err != nil {
    		sysErr, ok := err.(syscall.Errno)
    		if ok && sysErr == syscall.ERROR_ACCESS_DENIED {
    			return "", nil // 没权限,忽略这个进程
    		}
    		return "", err
    	}
    	defer syscall.CloseHandle(h)
    
    	var pbi struct {
    		ExitStatus                   int
    		PebBaseAddress               int64
    		AffinityMask                 int64
    		BasePriority                 int
    		UniqueProcessId              int64
    		InheritedFromUniqueProcessId int64
    	}
    	r0, _, _ := ntQueryInformationProcess.Call(uintptr(h), 0,
    		uintptr(unsafe.Pointer(&pbi)), unsafe.Sizeof(pbi), 0)
    	if r0 != 0 {
    		return "", errors.New("ntQueryInformationProcess")
    	}
    
    	var rtlUserProcParamsAddress int64
    	r0, _, _ = readProcessMemory.Call(uintptr(h),
    		uintptr(pbi.PebBaseAddress+ProcessParameters),
    		uintptr(unsafe.Pointer(&rtlUserProcParamsAddress)),
    		unsafe.Sizeof(rtlUserProcParamsAddress), 0, 0)
    	if r0 == 0 {
    		return "", errors.New("readProcessMemory rtlUserProcParamsAddress")
    	}
    
    	var commandLine struct {
    		Length        uint16
    		MaximumLength uint16
    		Buffer        int64
    	}
    	r0, _, _ = readProcessMemory.Call(uintptr(h),
    		uintptr(rtlUserProcParamsAddress+CommandLine),
    		uintptr(unsafe.Pointer(&commandLine)),
    		unsafe.Sizeof(commandLine), 0, 0)
    	if r0 == 0 {
    		return "", errors.New("readProcessMemory commandLine")
    	}
    
    	commandLineContents := make([]uint16, commandLine.Length/2)
    	r0, _, _ = readProcessMemory.Call(uintptr(h),
    		uintptr(commandLine.Buffer),
    		uintptr(unsafe.Pointer(&commandLineContents[0])),
    		uintptr(commandLine.Length), 0, 0)
    	if r0 == 0 {
    		return "", errors.New("readProcessMemory commandLineContents")
    	}
    	return syscall.UTF16ToString(commandLineContents), nil
    }
    
    func ForEachProcessEntry(f func(*syscall.ProcessEntry32) error) error {
    	snapshot, err := syscall.CreateToolhelp32Snapshot(syscall.TH32CS_SNAPPROCESS, 0)
    	if err != nil {
    		return err
    	}
    	defer syscall.CloseHandle(snapshot)
    	var procEntry syscall.ProcessEntry32
    	procEntry.Size = uint32(unsafe.Sizeof(procEntry))
    	if err = syscall.Process32First(snapshot, &procEntry); err != nil {
    		return err
    	}
    	for {
    		if err = f(&procEntry); err != nil {
    			return err
    		}
    		if syscall.Process32Next(snapshot, &procEntry) != nil {
    			return nil
    		}
    	}
    }
    

    2.再上结果

    1.下面是输出的部分结果,更下面的进程树有点私密,就不放了
             0,         0: name:[[System Process]], cmdline:[]
             4,         0:    \_ name:[System], cmdline:[]
            88,         4:    |    \_ name:[Registry], cmdline:[]
           412,         4:    |    \_ name:[smss.exe], cmdline:[]
           624,       616: name:[csrss.exe], cmdline:[]
           716,       708: name:[csrss.exe], cmdline:[]
           736,       616: name:[wininit.exe], cmdline:[]
           864,       736:    \_ name:[services.exe], cmdline:[]
          3232,       864:    |    \_ name:[svchost.exe], cmdline:[]
          1328,       864:    |    \_ name:[svchost.exe], cmdline:[]
          3308,       864:    |    \_ name:[AutoUpdate.exe], cmdline:[]
          4184,       864:    |    \_ name:[svchost.exe], cmdline:[]
          1128,       864:    |    \_ name:[svchost.exe], cmdline:[]
          7660,       864:    |    \_ name:[svchost.exe], cmdline:[C:WINDOWSsystem32svchost.exe -k UnistackSvcGroup]
          2952,       864:    |    \_ name:[svchost.exe], cmdline:[]
          2368,       864:    |    \_ name:[svchost.exe], cmdline:[]
          2172,       864:    |    \_ name:[svchost.exe], cmdline:[]
          2652,       864:    |    \_ name:[svchost.exe], cmdline:[]
          2920,       864:    |    \_ name:[svchost.exe], cmdline:[]
          2700,       864:    |    \_ name:[svchost.exe], cmdline:[]
          1796,       864:    |    \_ name:[svchost.exe], cmdline:[]
          2236,       864:    |    \_ name:[svchost.exe], cmdline:[]
          2328,       864:    |    \_ name:[svchost.exe], cmdline:[]
          3180,       864:    |    \_ name:[svchost.exe], cmdline:[]
          7500,       864:    |    \_ name:[svchost.exe], cmdline:[]
          1924,       864:    |    \_ name:[svchost.exe], cmdline:[]
          3152,       864:    |    \_ name:[svchost.exe], cmdline:[]
          1624,       864:    |    \_ name:[nvvsvc.exe], cmdline:[]
          8228,       864:    |    \_ name:[svchost.exe], cmdline:[]
         13480,       864:    |    \_ name:[svchost.exe], cmdline:[]
          1028,       864:    |    \_ name:[svchost.exe], cmdline:[]
          2052,       864:    |    \_ name:[svchost.exe], cmdline:[C:WINDOWSsystem32svchost.exe -k UnistackSvcGroup -s WpnUserService]
          3128,       864:    |    \_ name:[svchost.exe], cmdline:[]
          1468,       864:    |    \_ name:[svchost.exe], cmdline:[]
          1680,       864:    |    \_ name:[svchost.exe], cmdline:[]
          1044,      1680:    |    |    \_ name:[sihost.exe], cmdline:[sihost.exe]
          3856,       864:    |    \_ name:[svchost.exe], cmdline:[]
          2960,       864:    |    \_ name:[svchost.exe], cmdline:[]
          8136,       864:    |    \_ name:[SecurityHealthService.exe], cmdline:[]
          5668,       864:    |    \_ name:[PresentationFontCache.exe], cmdline:[]
          3008,       864:    |    \_ name:[svchost.exe], cmdline:[]
          3028,       864:    |    \_ name:[svchost.exe], cmdline:[]
          3108,       864:    |    \_ name:[svchost.exe], cmdline:[]
          3400,       864:    |    \_ name:[svchost.exe], cmdline:[]
          1424,       864:    |    \_ name:[svchost.exe], cmdline:[]
          1808,      1424:    |    |    \_ name:[ctfmon.exe], cmdline:[]
          6100,       864:    |    \_ name:[svchost.exe], cmdline:[]
          5688,       864:    |    \_ name:[svchost.exe], cmdline:[]
          5372,       864:    |    \_ name:[svchost.exe], cmdline:[]
          3144,       864:    |    \_ name:[svchost.exe], cmdline:[]
          1444,       864:    |    \_ name:[svchost.exe], cmdline:[]
          4036,       864:    |    \_ name:[svchost.exe], cmdline:[]
          7880,       864:    |    \_ name:[SgrmBroker.exe], cmdline:[]
          1528,       864:    |    \_ name:[svchost.exe], cmdline:[]
          4296,       864:    |    \_ name:[svchost.exe], cmdline:[C:WINDOWSsystem32svchost.exe -k UnistackSvcGroup -s CDPUserSvc]
          3352,       864:    |    \_ name:[SUService.exe], cmdline:[]
          2624,       864:    |    \_ name:[svchost.exe], cmdline:[]
          2308,       864:    |    \_ name:[svchost.exe], cmdline:[]
          5728,       864:    |    \_ name:[svchost.exe], cmdline:[]
          2672,       864:    |    \_ name:[svchost.exe], cmdline:[]
          1672,       864:    |    \_ name:[svchost.exe], cmdline:[]
          2376,       864:    |    \_ name:[svchost.exe], cmdline:[]
          8488,       864:    |    \_ name:[SunloginClient.exe], cmdline:[]
          2224,      8488:    |    |    \_ name:[SunloginClient.exe], cmdline:[]
          2228,       864:    |    \_ name:[svchost.exe], cmdline:[]
          2416,       864:    |    \_ name:[svchost.exe], cmdline:[]
          1412,       864:    |    \_ name:[svchost.exe], cmdline:[]
           948,       864:    |    \_ name:[svchost.exe], cmdline:[]
          2804,       864:    |    \_ name:[svchost.exe], cmdline:[]
          9128,       864:    |    \_ name:[svchost.exe], cmdline:[]
          1916,       864:    |    \_ name:[svchost.exe], cmdline:[]
          1484,       864:    |    \_ name:[svchost.exe], cmdline:[]
          1192,      1484:    |    |    \_ name:[taskhostw.exe], cmdline:[taskhostw.exe {222A245B-E637-4AE9-A93F-A59CA119A75E}]
          7476,      1484:    |    |    \_ name:[taskhostw.exe], cmdline:[]
           968,       864:    |    \_ name:[svchost.exe], cmdline:[]
          6600,       864:    |    \_ name:[svchost.exe], cmdline:[C:WINDOWSsystem32svchost.exe -k ClipboardSvcGroup -p -s cbdhsvc]
          1648,       864:    |    \_ name:[nvSCPAPISvr.exe], cmdline:[]
          1404,       864:    |    \_ name:[svchost.exe], cmdline:[]
          1724,       864:    |    \_ name:[svchost.exe], cmdline:[]
          1228,       864:    |    \_ name:[svchost.exe], cmdline:[]
           988,       864:    |    \_ name:[svchost.exe], cmdline:[]
          5056,       864:    |    \_ name:[svchost.exe], cmdline:[]
          3640,       864:    |    \_ name:[svchost.exe], cmdline:[]
          2096,       864:    |    \_ name:[svchost.exe], cmdline:[]
          2536,       864:    |    \_ name:[svchost.exe], cmdline:[]
          2332,       864:    |    \_ name:[igfxCUIService.exe], cmdline:[]
          4740,       864:    |    \_ name:[svchost.exe], cmdline:[]
          3880,       864:    |    \_ name:[svchost.exe], cmdline:[]
          3136,       864:    |    \_ name:[svchost.exe], cmdline:[]
          1584,       864:    |    \_ name:[svchost.exe], cmdline:[]
          2692,       864:    |    \_ name:[svchost.exe], cmdline:[]
          1008,       864:    |    \_ name:[svchost.exe], cmdline:[]
    
    2.为了验证结果正确性,检查了结果进程数量,完全正确,tasklist会把自己算进去,所以会多一个
    # tasklist /nh | find /v /c ""
    187
    # .proc /nh | find /v /c ""
    186
    

    3.做个总结

    偶尔看到一个帖子,有人问这个,就研究了一下下。发现其实也不难,不过方法确实是百度搜不到的。但还是被我搜到了。所有就做了个例子供大家参考。
    也想过做个Linux的,但是那太简单了,还是不要献丑了。

  • 相关阅读:
    RE最全面的正则表达式----字符验证
    Ajax tips(my_jquery_function.js)
    Python 分布式执行测试用例
    Python black + flake8 自动化规范代码
    JavaScript学习笔记-ES5
    pytest-assume 测试用例某一断言失败继续执行后面的代码
    pytest常用命令行
    [pretty_errors] Prettifies Python exception output to make it legible
    requests-html
    Python 类 继承与重写
  • 原文地址:https://www.cnblogs.com/janbar/p/13698974.html
Copyright © 2020-2023  润新知