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]\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获取进程树,以及命令行参数的更多相关文章
- Delphi 获取进程路径及命令行参数
Delphi 获取进程路径及命令行参数, 但有的进程获取时会报错,不知为啥 type PVOID64 = UINT64; _UNICODE_STRING = packed record Length ...
- C#中如何获取其他进程的命令行参数 ( How to get other processes's command line argument )
Subject: C#中如何获取其他进程的命令行参数 ( How to get other processes's command line argument )From: jian ...
- Win32程序支持命令行参数的做法(转载)
转载:http://www.cnblogs.com/lanzhi/p/6470406.html 转载:http://blog.csdn.net/kelsel/article/details/52759 ...
- Win32程序支持命令行参数的做法
作者:朱金灿 来源:http://blog.csdn.net/clever101 首先说说Win 32 API程序如何支持命令行参数.Win 32程序的入口函数为: int APIENTRY _tWi ...
- 如何获取PHP命令行参数
使用 PHP 开发的同学多少都会接触过 CLI 命令行.经常会有一些定时任务或者一些脚本直接使用命令行处理会更加的方便,有些时候我们会需要像网页的 GET . POST 一样为这些命令行脚本提供参数. ...
- pytest动态添加命令行参数并获取(钩子函数:pytest_addoption)
考虑场景: 我们的自动化用例需要支持在不同测试环境运行,有时候在dev环境运行,有时候在test环境运行: 有时候需要根据某个参数不同的参数值,执行不同的业务逻辑: 上面的场景我们都可以通过" ...
- Python_sys.argv 命令行参数获取使用方法
import sys print(sys.argv) """ 获取命令行参数 输入 python3 sys.argv_demo.py 输出: ['argv.py'] 输入 ...
- winrar.exe 命令行参数
========= 下面是 我写大论文时候的实例(批量压缩.备份文件)================== * 一共三个文件:(1) MyCopy.bat : (2) UnCopy.txt : ...
- VLC命令行参数详解
VLC命令行参数详解 2012-11-29 14:00 6859人阅读 评论(0) 收藏 举报 Usage: vlc [options] [stream] ...You can specify mul ...
随机推荐
- 转载:MySQL万字总结篇
转载自:https://database.51cto.com/art/202001/609409.htm 开局一张图 这张图是重点!!!咱要先对 MySQL 有一个宏观的了解,知道他的执行流程. 一条 ...
- Python算法题:有100只大、中、小骆驼,100框土豆,一只大骆驼可以背3框,中骆驼可以背俩框,小骆驼两只背一筐,问大中小各有多少只骆驼?
1 for x in range(0,100): 2 for y in range(0,100): 3 for z in range(0, 100): 4 if x*3+y*2+0.5*z == 10 ...
- 别再眼高手低了! 这些Linq方法都清楚地掌握了吗?
不要再眼高手低了,这些Enumerable之常见Linq扩展方法都清楚掌握了吗?其实这是对我自己来说的! 例如:一个人这个技术掌握了一点那个技术也懂一点,其他的好像也了解一些,感觉自己啥都会一点,又觉 ...
- Jack Straws(POJ 1127)
原题如下: Jack Straws Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 5555 Accepted: 2536 ...
- unserialize3 攻防世界
序列化是将对象转换为便于保存的字符串, 而反序列化是将便于保存的字符串转换为字符串. _wakeup()魔法方法 如果直接传参给code会被__wakeup()函数再次序列化,所以要绕过他, 利用__ ...
- 蓝桥杯校内模拟赛Python解答
@ 目录 1. 15.125GB 2. 约数个数 3. 叶结点数 4. 数字9 5. 数位递增的数 6. 递增三元组 7. 音节判断 8. 长草 9. 序列计数 10. 晚会节目单 1. 15.125 ...
- 使用Excel设计fastreport报表
最近做项目遇到一些报表设计的问题.项目的报表使用 Fast Report,然而该控件调整报表格式比较繁琐,有时候调整某一栏的宽度,整个标题栏都需要调整,且调整以后 还不一定能对齐.客户的很多报表都是基 ...
- 10月1日之后,你新建的GitHub库默认分支不叫「master」了
从 2020 年 10 月 1 日开始,GitHub 上的所有新库都将用中性词「main」命名,取代原来的「master」,因为后者是一个容易让人联想到奴隶制的术语. 这个决定并不是最近才做出的.今年 ...
- 关于windows服务器wsus客户端配置的修改
本文环境如下: 服务器:Windows Server 2012 R2 Standard 由于公司服务器是加了域环境的,又需要将wsus客户端指向另一台wsus服务器,修改本地组策略.可能会被域控给修改 ...
- Python3基础数据类型(数字、字符串、元组、列表、集合、字典)
笔记参考了菜鸟教程 Python 中的变量不需要声明,赋值才创建.赋值给变量的是什么类型变量就是什么类型 多个变量赋值 1 a, b, c = 1, 2, "runoob" 标准数 ...