4、进程数据提取:进程创建与终止事件、进程树构建、命令行参数提取、进程哈希计算

进程,是操作系统里最活跃的实体。你想想看,每一次点击、每一次命令执行,背后都是进程在干活。但对我们做安全的人来说,进程也是攻击者最常用的“马甲”。恶意代码总要运行起来才能搞破坏,对吧?所以,把进程数据提取干净、分析透彻,是EDR取证的核心基本功。

我个人习惯,拿到一份终端日志,第一件事就是看进程列表。不是随便扫一眼,而是要把进程的“前世今生”都扒出来。这一章,我们就来聊聊怎么干这活。

4.1 进程创建与终止事件

进程的一生,无非就是“生”和“死”。但这两个瞬间,恰恰是证据最集中的地方。

进程创建事件,EDR通常会在操作系统内核层面挂钩子。比如Windows上,会用PsSetCreateProcessNotifyRoutine来注册回调。一旦有新进程诞生,EDR就能抓到以下关键信息:

  • 进程ID(PID):唯一标识,但会复用,要注意时间戳。
  • 父进程ID(PPID):谁生了它?这是溯源的关键。
  • 映像路径:可执行文件在磁盘上的位置。
  • 命令行:启动时带了什么参数。
  • 时间戳:创建时间(精确到微秒最好)。
  • 用户SID:以哪个用户身份运行的。
  • 会话ID:属于哪个登录会话。

重点:进程创建事件是“白名单”思路的基石。你只要知道正常系统里有哪些进程会启动,异常的就很容易露馅。

进程终止事件,很多人觉得不重要——进程都死了,还查什么?其实不然。我在项目中遇到过好几次,恶意进程执行完就自毁,但终止事件里会留下退出码和运行时长。有些攻击者会利用“自杀”来逃避检测,但终止事件告诉我们:它曾经来过,而且走得可能并不安详。

终止事件通常包含:

  • 进程ID
  • 退出码(0通常表示正常退出,非0可能有异常)
  • 终止时间
  • CPU总时间、内存峰值(侧面反映它干了多少活)

小技巧:把进程创建和终止事件配对,可以算出进程的“存活时间”。如果一个进程只活了0.1秒就结束了,嗯,这很可疑——正常程序不会这么“短命”。

4.2 进程树构建

单个进程的数据,就像拼图里的一块。你得把它们拼起来,才能看清全貌。进程树,就是那张拼图。

进程树的核心逻辑很简单:通过PPID把进程串起来。根节点通常是systemd(Linux)或winlogon.exe(Windows),然后一层层往下长。

我一般会这样构建:

  1. 收集所有进程创建事件,建立PID -> 进程信息的字典。
  2. 遍历字典,对每个进程,找到它的PPID对应的父进程。
  3. 把子进程挂到父进程的“孩子列表”里。
  4. 从根节点开始,递归打印或可视化。

这里有个坑,我吃过亏——进程ID复用。操作系统会回收PID,如果日志跨度时间长,同一个PID可能对应不同的进程。所以,构建进程树时,一定要用(PID, 创建时间戳)作为唯一键,而不是只用PID。

注意:有些恶意软件会“借壳生蛋”,比如通过explorer.exe启动,但父进程其实是cmd.exe。这时候,只看PPID可能会被误导。我建议结合命令行参数和用户行为一起分析。

下面是我用Python写的一个简单进程树构建示例:

def build_process_tree(events):
    # events: list of dict, each with pid, ppid, cmdline, timestamp
    tree = {}
    for ev in events:
        pid = ev['pid']
        ppid = ev['ppid']
        node = {
            'pid': pid,
            'ppid': ppid,
            'cmdline': ev['cmdline'],
            'children': []
        }
        tree[pid] = node
    
    # 挂载子节点
    root = None
    for pid, node in tree.items():
        ppid = node['ppid']
        if ppid == 0 or ppid not in tree:
            root = node
        else:
            tree[ppid]['children'].append(node)
    
    return root

def print_tree(node, indent=0):
    print(' ' * indent + f"PID:{node['pid']} Cmd:{node['cmdline']}")
    for child in node['children']:
        print_tree(child, indent + 2)

你看,代码其实不复杂。但真正落地时,要考虑事件乱序、丢失、重复等问题。我一般会先按时间戳排序,再用滑动窗口去重。

4.3 命令行参数提取

命令行参数,是攻击者最常“做手脚”的地方。你想想看,一个正常的notepad.exe,命令行就是notepad.exe。但如果变成notepad.exe /c "powershell -enc ...",那就有问题了。

提取命令行参数,有几种方式:

  • Windows:通过WMIWin32_Process类,或者ETW(Event Tracing for Windows)的Microsoft-Windows-Kernel-Process提供程序。ETW能拿到完整的命令行,包括空格和引号。
  • Linux:读取/proc/[pid]/cmdline文件,注意里面用\0分隔参数。也可以用auditdSYSCALL事件来捕获execve的参数。
  • macOS:通过sysctlproc_info API获取。

关键点:命令行参数里经常藏着IP地址、域名、Base64编码的Payload、甚至是明文密码。我建议提取后,立刻做一次简单的敏感信息扫描。

我曾经处理过一个案例,攻击者把恶意DLL的路径藏在命令行参数里,用rundll32.exe加载。命令行长这样:

rundll32.exe C:\Users\Public\cache.dll,EntryPoint

如果不提取命令行,只看进程名rundll32.exe,你根本发现不了异常。所以,命令行参数提取,是EDR数据提取里绝对不能省的一步。

4.4 进程哈希计算

哈希,说白了就是给文件办个“身份证”。MD5、SHA1、SHA256,都是常用的算法。进程哈希计算,就是计算可执行文件的哈希值,然后去威胁情报平台查一查——这个文件是白名单里的,还是已知恶意软件?

计算哈希,有两点要注意:

  1. 算哪个文件? 当然是进程映像路径指向的那个文件。但要注意,有些进程会自解压或动态生成代码,这时候映像路径可能只是个“壳”。我建议同时计算内存中进程的哈希(通过读取进程内存),但那个开销比较大,一般只在深度调查时做。
  2. 什么时候算? 最好在进程创建时就算,因为文件可能很快被删除或修改。有些恶意软件会“下载-执行-自删除”,如果你等进程跑完了再去算,文件已经没了。

下面是一个用Python计算文件哈希的示例:

import hashlib

def calculate_file_hash(filepath, algorithm='sha256'):
    h = hashlib.new(algorithm)
    try:
        with open(filepath, 'rb') as f:
            for chunk in iter(lambda: f.read(4096), b''):
                h.update(chunk)
        return h.hexdigest()
    except FileNotFoundError:
        return None
    except PermissionError:
        return None  # 权限不够,常见于系统进程

建议:不要只算一种哈希。我一般会同时算SHA256和SHA1。SHA256用于精确匹配,SHA1用于兼容老旧的情报系统。MD5虽然快,但已经不安全了,不建议作为唯一依据。

哈希计算的结果,通常会跟威胁情报联动。比如,把SHA256丢给VirusTotal,看看有多少家引擎报毒。但要注意,哈希匹配不是万能的。攻击者稍微改一个字节,哈希就变了。所以,哈希只是线索之一,不能作为定罪的全部证据。

知识体系总览

为了让你更直观地理解这一章的内容,我画了一张图。它展示了进程数据提取的四个核心模块,以及它们之间的关系。

进程数据提取与初步分析 - 知识体系 进程数据提取 进程创建与终止事件 PID/PPID/时间戳/退出码 内核回调/ETW/Auditd 进程树构建 PPID串联/父子关系 PID复用处理/可视化 命令行参数提取 WMI/ETW/proc/cmdline 敏感信息扫描/参数还原 进程哈希计算 SHA256/SHA1/MD5 威胁情报联动/文件完整性 四个模块相互独立,但组合使用才能还原完整的进程行为

这张图里,四个模块是并列的,但实际分析时,我通常会先看进程创建事件,然后构建进程树,再提取命令行参数,最后算哈希。这个顺序,能帮你最快地发现异常。

好了,这一章的内容就到这里。进程数据提取,是EDR分析的地基。地基打不牢,后面盖什么楼都容易塌。希望你能把这些方法用到实际工作中,多动手,多踩坑,慢慢就有感觉了。


专注资料整理