cmdline 存的是原始字节
/proc/<pid>/cmdline 保存进程启动时的参数原始内容,各参数之间用 NUL 字节分隔,文件末尾也有一个 NUL,所以直接 cat 会看到挤成一行的内容,需要用 tr 把 NUL 换成空格再读。它与 ps 显示的命令行来自同一份数据,但 ps 会做格式化处理,两者对照能发现 argv 被改写、参数超长截断或命令行整体被清空的情况。
不一致本身就是线索
进程可以在运行期间改写自己的命令行,把这个区域伪装成无害的样子,也可以在启动后把整段内容清零,让 ps 只显示一个方括号包裹的名称——这种形态原本是内核线程的特征,被人为模仿就值得深查。遇到 cmdline 为空时,先看 exe 链接指向哪个可执行文件,再结合进程树与打开的文件描述符判断。
基本信息
| 适用平台 | Linux(/proc 文件系统) |
|---|---|
| 路径 | /proc/<pid>/cmdline |
| 分隔符 | NUL 字节(0x00),需转换后才能正常阅读 |
| 对照来源 | ps -o args、/proc/<pid>/comm、/proc/<pid>/exe |
| 权限 | 普通用户只能读自己可访问的进程,完整采集需 root |
典型使用场景
- 可疑进程的命令行异常:确认是否被改写或清空
- 参数超长导致 ps 截断:直接从 cmdline 读原始字节补齐
- 确认进程真实意图:有些工具把目标地址写在参数里
- 采集易失性数据:把全部进程的 cmdline 批量导出留档
- 与父进程对照:看是谁拉起了这个进程以及传了什么参数
读取与对照
读取与对照
# NUL 转换为空格后阅读,末尾补一个换行
tr '\0' ' ' < /proc/1234/cmdline; echo
# 与 ps 的显示对照,两者不一致说明 argv 被改写
ps -p 1234 -o pid,ppid,args=
# 命令行空时,看可执行文件与进程状态
ls -l /proc/1234/exe
cat /proc/1234/comm
# 批量导出全部进程的命令行,作为易失性数据留存
for p in /proc/[0-9]*; do printf '%s | ' "${p##*/}"; tr '\0' ' ' < "$p/cmdline"; echo; done > /mnt/ev/cmdline-all.txt相关文件对照
| 来源 | 内容 | 分析用法 |
|---|---|---|
| /proc/<pid>/cmdline | 启动参数原始字节 | 与 ps 对照发现改写或清空 |
| /proc/<pid>/comm | 进程名(15 字符上限) | 常被用于伪装成内核线程形态 |
| /proc/<pid>/exe | 可执行文件链接 | 命令行不可信时的定位依据 |
| /proc/<pid>/status | 进程状态与内存信息 | 补充进程来源与运行状态 |
| /proc/<pid>/environ | 环境变量 | 常包含可执行文件所在目录与配置路径 |
cmdline 与 ps 一致并不等于可信:两者读的是同一份数据,被改写后会同时失真,需要结合 exe 链接、文件描述符与进程树交叉判断。
内核线程的 cmdline 本来就为空,且通常带方括号显示;判定为伪装前要先看 ppid 是否为 2(kthreadd)以及进程状态特征。