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]\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)
} 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:\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的,但是那太简单了,还是不要献丑了。

win32获取进程树,以及命令行参数的更多相关文章

  1. Delphi 获取进程路径及命令行参数

    Delphi 获取进程路径及命令行参数, 但有的进程获取时会报错,不知为啥 type PVOID64 = UINT64; _UNICODE_STRING = packed record Length ...

  2. C#中如何获取其他进程的命令行参数 ( How to get other processes's command line argument )

    Subject: C#中如何获取其他进程的命令行参数 ( How to get other processes&apos;s command line argument )From: jian ...

  3. Win32程序支持命令行参数的做法(转载)

    转载:http://www.cnblogs.com/lanzhi/p/6470406.html 转载:http://blog.csdn.net/kelsel/article/details/52759 ...

  4. Win32程序支持命令行参数的做法

    作者:朱金灿 来源:http://blog.csdn.net/clever101 首先说说Win 32 API程序如何支持命令行参数.Win 32程序的入口函数为: int APIENTRY _tWi ...

  5. 如何获取PHP命令行参数

    使用 PHP 开发的同学多少都会接触过 CLI 命令行.经常会有一些定时任务或者一些脚本直接使用命令行处理会更加的方便,有些时候我们会需要像网页的 GET . POST 一样为这些命令行脚本提供参数. ...

  6. pytest动态添加命令行参数并获取(钩子函数:pytest_addoption)

    考虑场景: 我们的自动化用例需要支持在不同测试环境运行,有时候在dev环境运行,有时候在test环境运行: 有时候需要根据某个参数不同的参数值,执行不同的业务逻辑: 上面的场景我们都可以通过" ...

  7. Python_sys.argv 命令行参数获取使用方法

    import sys print(sys.argv) """ 获取命令行参数 输入 python3 sys.argv_demo.py 输出: ['argv.py'] 输入 ...

  8. winrar.exe 命令行参数

    ========= 下面是 我写大论文时候的实例(批量压缩.备份文件)================== * 一共三个文件:(1) MyCopy.bat :   (2) UnCopy.txt :   ...

  9. VLC命令行参数详解

    VLC命令行参数详解 2012-11-29 14:00 6859人阅读 评论(0) 收藏 举报 Usage: vlc [options] [stream] ...You can specify mul ...

随机推荐

  1. 将大量数据批量插入Oracle表的类,支持停止续传

    之前用create table select * from XXTable无疑是创建庞大表的最快方案之一,但是数据重复率是个问题,且数据难以操控. 于是我在之前批量插数据的基础上更新了一个类,让它具有 ...

  2. Java高并发系列——检视阅读

    Java高并发系列--检视阅读 参考 java高并发系列 liaoxuefeng Java教程 CompletableFuture AQS原理没讲,需要找资料补充. JUC中常见的集合原来没讲,比如C ...

  3. 第2课 - Hello, DTOS!

    第2课 - Hello, DTOS! 1. 主引导程序 主引导程序是软件还是固件?如果是软件,那么由谁开发?如何开发? (1)上一节说到了固件和软件的区别.由于主引导程序没有在出厂前固化到硬件中,因此 ...

  4. 想写一篇jvm的工具入门

    为什么要写一个jvm的工具入门呢,一是自己也不会,二是因为不会所以想学一下,还有就是这个确实很重要,对学习jvm有很多的用处,对定位问题有很大的便利,以前毕业那会我记得有个笔试,知道JAVA_HOME ...

  5. [LeetCode]11. 盛最多水的容器(双指针)

    题目 给定 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) .在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0).找出其中的两 ...

  6. 腾讯云COS对象存储 Web 端直传实践(JAVA实现)

    使用 腾讯云COS对象存储做第三方存储云服务,把一些文件都放在上面,这里主要有三中实现方式:第一种就是在控制台去设置好,直接上传文件.第二种就是走服务端,上传文件,就是说,上传文件是从服务端去上传上去 ...

  7. Linux下rm操作误删恢复

    1.查看被误删的分区 df /home/Java/...      一直到刚刚被误删的文件的路径下 2.在debugfs打开分区 open /dev/ssl       最好这个分区可能不一样,根据上 ...

  8. 在自己win系统里面给idea配置Git

    这里直接是写好的步骤 下载链接

  9. SVN检出maven项目

    (一)直接单击项目,右键选择configure,选择convert to maven project (二)删除project explorer中的项目,并重新从工作区间导入maven项目.

  10. 通过adrci ips打包incident给oracle

    1.adrci查看incident 2.show home 3.set home adrci> set home diag/rdbms/mesdb/mesdb1 4.show incident ...