欲买桂花同载酒,荒泷天下第一斗。|

janbar

园龄:4年6个月 粉丝:29 关注:10

2020-09-17 21:16 阅读 378 评论 0 推荐

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

1.先上代码

copy
package main import ( "bytes" "flag" "fmt" "io" "os" "reflect" "sort" "unsafe" "golang.org/x/sys/windows" ) func main() { out := flag.String("o", "-", "write result to file, - eq stdout") flag.Parse() procMap := make(map[uint32]*Process, 32) err := ForEachProcessEntry(func(entry *windows.ProcessEntry32) error { cmdline, err := GetCmdline(entry.ProcessID) if err != nil { return err } procMap[entry.ProcessID] = &Process{ Pid: entry.ProcessID, Ppid: entry.ParentProcessID, Name: windows.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]\n", 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]\n") 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) } func GetCmdline(pid uint32) (string, error) { /* 翻译这个C++代码: https://stackoverflow.com/a/42341811/11844632 */ if pid == 0 { // 系统进程,无法读取 return "", nil } h, err := windows.OpenProcess(windows.PROCESS_QUERY_INFORMATION|windows.PROCESS_VM_READ, false, pid) if err != nil { if e, ok := err.(windows.Errno); ok && e == windows.ERROR_ACCESS_DENIED { return "", nil // 没权限,忽略这个进程 } return "", err } defer windows.CloseHandle(h) var pbi struct { ExitStatus uint32 PebBaseAddress uintptr AffinityMask uintptr BasePriority int32 UniqueProcessId uintptr InheritedFromUniqueProcessId uintptr } pbiLen := uint32(unsafe.Sizeof(pbi)) err = windows.NtQueryInformationProcess(h, windows.ProcessBasicInformation, unsafe.Pointer(&pbi), pbiLen, &pbiLen) if err != nil { return "", err } var addr uint64 d := *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{ Data: uintptr(unsafe.Pointer(&addr)), Len: 8, Cap: 8})) err = windows.ReadProcessMemory(h, pbi.PebBaseAddress+32, // ntddk.h,ProcessParameters偏移32字节 &d[0], uintptr(len(d)), nil) if err != nil { return "", err } var commandLine windows.NTUnicodeString Len := unsafe.Sizeof(commandLine) d = *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{ Data: uintptr(unsafe.Pointer(&commandLine)), Len: int(Len), Cap: int(Len)})) err = windows.ReadProcessMemory(h, uintptr(addr+112), // winternl.h,分析文件偏移 &d[0], Len, nil) if err != nil { return "", err } cmdData := make([]uint16, commandLine.Length/2) d = *(*[]byte)(unsafe.Pointer(&cmdData)) err = windows.ReadProcessMemory(h, uintptr(unsafe.Pointer(commandLine.Buffer)), &d[0], uintptr(commandLine.Length), nil) if err != nil { return "", err } return windows.UTF16ToString(cmdData), nil } func ForEachProcessEntry(f func(*windows.ProcessEntry32) error) error { snapshot, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, 0) if err != nil { return err } defer windows.CloseHandle(snapshot) var procEntry windows.ProcessEntry32 procEntry.Size = uint32(unsafe.Sizeof(procEntry)) if err = windows.Process32First(snapshot, &procEntry); err != nil { return err } for { if err = f(&procEntry); err != nil { return err } if windows.Process32Next(snapshot, &procEntry) != nil { return nil } } }

2.再上结果

copy
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:\WINDOWS\system32\svchost.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:\WINDOWS\system32\svchost.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:\WINDOWS\system32\svchost.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:\WINDOWS\system32\svchost.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的,但是那太简单了,还是不要献丑了。

posted @   janbar  阅读(379)  评论(0编辑  收藏  举报
编辑推荐:
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
阅读排行:
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· spring官宣接入deepseek,真的太香了~

FAVOURITE

点击右上角即可分享
微信分享提示
*✧⁺˚⁺ପ(๑・ω・)੭ु⁾⁾ 好好学习天天向上
进入亮色模式
进入亮色模式

FAVOURITE