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. springcloudalibaba与nacos服务注册流程图

    springboot + springcloud + springcloudalibaba + nacos 服务注册流程图: springboot ①WebApplicationContext ②st ...

  2. Ubuntu修改默认Python版本,你了解多少~

    目录 1 查看Python版本 1.1 查看装有哪些版本 1.2 查看默认版本 2 修改Python默认版本 2.1 基于文件修改 2.2 基于软链接修改 1 查看Python版本 1.1 查看装有哪 ...

  3. 初等函数——幂函数(Power Function)

    幂函数(Power function)是形如f(x)=xa的函数,a∈R是实数.即以底数为自变量,幂为因变量,指数为常数的函数称为幂函数. 性质 幂函数的图像一定会出现在第一象限内,一定不会出现在第四 ...

  4. JDK15正式发布,划时代的ZGC同时宣布转正

    你发任你发,我用Java8.本文已被 https://www.yourbatman.cn 收录,里面一并有Spring技术栈.MyBatis.JVM.中间件等小而美的专栏供以免费学习.关注公众号[BA ...

  5. C语言01

    从问题到C语言程序设计 1.1计算机的问题求解方法 程序设计面向的问题 什么问题可以用程序的方法解决? 打印九九乘法表 图形变换 文件压缩问题 ....... 一切可计算的问题 如何解决? 确定问题可 ...

  6. golang map学习

    当对map只声明时,由于map为引用类型,所以默认值为nil,但对nil map 而言,支持read ,但不支持write 当执行write操作时, 会抛出panic异常; 代码如下: func Te ...

  7. odoo13之在odoo中添加自定义页面

    注: 本博文是阅读Ruter博客 在odoo中添加自定义页面 后所做的个人总结,以及博文搬迁,主要是便于自己的后期理解:大部分内容为搬运,当然也包括自己的一些总结和流程优化. 前言 首先展示效果:进入 ...

  8. 运行时数据区--程序计数器(PC Register)

    程序计数器(PC Register) 这里的计数器(Program Counter Register)并非为广义上所指的物理寄存器,JVM中的PC寄存器(程序计数器)是对物理PC寄存器的一种抽象模拟, ...

  9. Java Web学习(五)session、cookie、token

    文章更新时间:2020/09/14 一.引言 动态网页兴起后,会话管理变成开发者需要考虑的一个问题,由于HTTP请求是无状态的,为了区分每个用户,此时引入了会话标识(sessionId)的概念,但是存 ...

  10. 刷题[极客大挑战 2019]HardSQL

    解题思路 打开是一个登陆框,考点sql注入了,先正常尝试一波 发现居然是get类型 输入and发现有waf过滤,那fuzz一波看看过滤了什么 fuzz union被过滤,并且绕过union的几种方法同 ...