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. leetcode刷题-79单词搜索

    题目 给定一个二维网格和一个单词,找出该单词是否存在于网格中. 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格.同一个单元格内的字母不允许被重复 ...

  2. c++基础 写二进制文件

    问题描述 有许多数据待拟合,需要从 root 中提取出来,写成文本文件数据量过大,想转成二进制文件. 解决 #include "TString.h" #include " ...

  3. python日志模块配置

    import logging logging.basicConfig(filename= 'out.log',filemode= 'w+', level= logging.DEBUG, format= ...

  4. LC算法技巧总结(二):双指针和滑动窗口技巧

    我把双指针技巧再分为两类,一类是「快慢指针」,一类是「左右指针」.前者解决主要解决链表中的问题,比如典型的判定链表中是否包含环:后者主要解决数组(或者字符串)中的问题,比如二分查找. 一.快慢指针的常 ...

  5. Python 面试题 字符串 删除多少个字符使得出现做多的字符数量大于等于字符串长度的一半.

    str1 = input() num = {} for i in set(str1): num[i]=str1.count(i) max_value = max(num.values()) n=abs ...

  6. Java枚举解读

    Java枚举 枚举类概念的理解与定义 一个类的对象是有限个,确定的,我们称此为枚举类. 当需要定义和维护一组常量时,强烈建议使用枚举类. 如果一个枚举类中只有一个对象,则可以作为单例模式的实现方式. ...

  7. Minimizing maximizer(POJ 1769)

    原题如下: Minimizing maximizer Time Limit: 5000MS   Memory Limit: 30000K Total Submissions: 5104   Accep ...

  8. mysql1045问题解决

    输入mysql -u root -P 1202 -h localhost -p时报错mysql1045 解决方法:my.ini中加上skip-grant-tables后重启mysql服务即可解决

  9. C#类库推荐 拼多多.Net SDK,开源免费!

    背景介绍 近两年拼多多的发展非常迅速,即便口碑一般,也没有网页端,奈何我们已经全面小康,6亿月收入1000以下,9亿月收入2000以下,所以因为价格原因使用拼多多的用户也越来越多了.同样的,拼多多也开 ...

  10. Git使用教程与基本原理和Sourcetree基本使用探微

    什么是GIT Git是一个强调速度的分布式版本控制软件和源代码管理系统(SCM,source code management).Git最初是由Linus Torvalds为内核开发而设计的管理软件.自 ...