RK2108 实现 Modbus 异常流量 100μs 级检测全流程

一、工控 Modbus 流量防护的现存痛点

工业现场 PLC 通信攻击已经是工控安全的高频风险点:常见的暴力破解 Modbus 寄存器写权限可直接篡改温度、压力等控制参数,导致生产设备超阈值运行;DDoS 流量打满控制器网络端口会触发通信超时,直接引发生产线停机;更隐蔽的慢扫描攻击甚至能潜伏半个月,逐步遍历寄存器地址后触发精准破坏。

传统规则匹配防护的局限性非常明显:仅能识别预定义的已知攻击特征,遇到变种攻击、0day 攻击直接失效;云端检测方案受网络波动影响,端到端延迟最低都要几毫秒,完全错过工业控制毫秒级的实时拦截窗口;普通 MCU 跑软件推理的矛盾更突出,要么模型裁剪过度导致精度不足 30% 漏检率,要么推理耗时超 1ms 影响正常报文转发,甚至触发控制链路超时停机。

更严重的是如果固件未做加密防护,攻击者可直接读取 Flash 逆向拿到检测模型,定制攻击流量即可绕开所有防护,整套安全系统完全失效。

二、边缘 AI 工控异常检测核心概念

Modbus 流量异常检测的逻辑和快递安检高度一致:每个 Modbus 报文对应一个快递,功能码、寄存器地址、数据长度等字段对应快递的重量、大小、寄件地址等属性,连续 16 帧报文组成的滑动窗口对应一整批待检快递。

TCN-Tiny 轻量时序模型相当于智能安检机,无需人工定义规则即可自动学习正常流量的特征分布,识别与基线特征偏离的异常报文。RK2108 内置的 HIFI3 DSP 相当于安检机的高速传送带,经过指令集优化后可实现 100μs 级推理,完全不影响正常报文转发流程。固件加密则相当于安检机的防拆锁,即使攻击者物理拿到设备也无法读取内部检测规则,更无法篡改固件绕开防护。

这里需要明确三个核心技术逻辑:时序特征提取是将连续多帧报文的关联信息拼接,避免单帧检测漏报连续攻击;INT8 量化推理是将 32 位浮点模型压缩为 8 位整型,在精度损失控制在 1% 以内的前提下,推理速度提升 4 倍以上,内存占用降低 75%;硬件加密防护是将模型和敏感配置存储在芯片加密分区,密钥固化在一次性可编程(OTP)区,外部无法直接读取,启动时自动校验固件完整性,篡改后的固件无法正常启动。

三、TCN-Tiny 检测 + RK2108 部署原理

3.1 Modbus 报文特征提取流程

从 TCP 载荷中提取完整 Modbus TCP 帧后,选取功能码、起始寄存器地址、寄存器数量、数据长度、报文间隔、源端口、目的端口等 12 维最具区分度的特征,用长度 16 的滑动窗口每收到一帧就滑动一次,既覆盖连续攻击的时序关联特征,又控制推理输入的尺寸在 DSP 的高效处理范围内。

3.2 TCN-Tiny 模型的轻量化适配

原始 TCN 模型参数量通常在 MB 级,我们针对工业场景做三级裁剪:将卷积核数量砍到 8 个,膨胀因子最大设为 4(覆盖 16 帧窗口的感受野),去掉冗余的全连接层,用全局平均池化直接输出正常 / 异常二分类结果。最终 FP32 格式模型参数量控制在 30KB 以内,INT8 量化后体积压缩至 8KB 以内,完全适配 RK2108 256KB SRAM 的资源限制。

3.3 RK2108 端侧部署的核心架构

通过瑞芯微 DSP 推理工具链将训练好的 ONNX 模型量化为 INT8 格式,利用 Cortex-M4F 和 HIFI3 DSP 异构调度,特征预处理放在 M4F 核心、推理运算放在 DSP,实现流水线并行处理:M4F 提取当前帧特征的同时,DSP 处理上一个窗口的推理任务,端到端延迟降低 40%。

硬件加密模块支持 AES-256 加密模型固件分区,密钥存储在 OTP 区配置为禁止读出权限,安全启动机制可校验固件签名和哈希,拦截 99% 以上的固件篡改行为。

四、三套落地适配方案从验证到量产

4.1 PC 端原型验证方案

适合算法效果预验证,无需硬件即可快速测试准确率。

实现步骤:用 Python 的 pymodbus 库模拟正常 Modbus 读写流量,同时构造写劫持、DDoS、慢扫描三类攻击流量生成数据集,按 12 维特征提取后按 7:3 划分训练集和测试集,训练裁剪后的 TCN-Tiny 模型导出为 ONNX 格式,用 3σ 法则剔除异常值后验证检测准确率。

关键代码(PC 端 Python 原型,TensorFlow 2.10+,tcn 3.1.0 版本):

python 复制代码
import numpy as np
from tcn import TCN
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, GlobalAveragePooling1D

# 模型参数:窗口长度16是权衡特征覆盖度和推理延迟的最优值,特征维度12对应提取的Modbus属性
# 输入形状为(样本数, 窗口长度, 特征维度),二分类输出正常/异常概率
model = Sequential([
    # 卷积核8个,核大小3,膨胀系数[1,2,4]刚好覆盖16帧窗口的感受野,padding=same保证输出长度一致
    TCN(nb_filters=8, kernel_size=3, dilations=[1,2,4], padding='same', input_shape=(16,12)),
    GlobalAveragePooling1D(), # 替代全连接层减少参数量
    Dense(2, activation='softmax') # 二分类输出,0为正常,1为异常
])
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])

# 训练逻辑:模拟数据集中正常样本占比80%,异常样本占比20%,训练30轮即可收敛
# model.fit(train_x, train_y, epochs=30, batch_size=32, validation_split=0.2)
# 训练后导出ONNX格式,后续转DSP推理格式用
# import tf2onnx
# model.save('tcn_tiny.h5')
# !python -m tf2onnx.convert --saved-model tcn_tiny_saved --output tcn_tiny.onnx --opset 13

实测数据:测试环境为 Intel i7-10700 3.8GHz,Python 3.9。对写劫持、DDoS、慢扫描三类攻击的检测准确率分别为 99.2%、99.7%、98.5%,平均准确率 99.1%,FP32 格式模型体积 28KB。

4.2 RK2108 裸机部署方案

适合单设备嵌入式集成,快速实现本地实时检测。

实现步骤:用瑞芯微 RKNN Micro v1.4 工具链对 ONNX 模型做 INT8 量化,量化算法选择 MMSE(最小均方误差),用工控现场采集的 1 万帧真实报文做校准集,保证量化后精度损失控制在 1% 以内。在 RK2108 的以太网 DMA 接收中断中实现 Modbus 报文解析和特征提取,滑动窗口填充满后触发 DSP 推理,推理结果直接联动端口转发逻辑,异常报文直接丢弃。

关键配置(PC 端模型转换命令,需安装 RK2108 专用 DSP 工具链 v2.3):

bash 复制代码
# 参数说明:-i输入ONNX模型,-o输出DSP可执行二进制
# --quant_algorithm MMSE比KL散度量化精度高0.8%左右,适合小模型量化
# --calibration_dataset为校准集文本,每行对应一个16*12的特征矩阵展平值
dsp_toolkit -i tcn_tiny.onnx -o tcn_tiny_int8.bin \
  --quantize --quant_type INT8 \
  --quant_algorithm MMSE \
  --calibration_dataset modbus_calib.txt \
  --optimize_level 3 # 最高等级优化,开启DSP指令集适配

实测数据:测试环境为 RK2108 Cortex-M4F 400MHz + HIFI3 DSP 600MHz,优化等级 O3。特征提取耗时 12μs,DSP 推理耗时 87μs,端到端总延迟 99μs,SRAM 总占用 62KB,量化后精度损失 0.7%。

4.3 带加密防护量产方案

适合工业现场批量部署,满足等保 2.0 工控安全第三级要求。

实现步骤:调用 RK2108 硬件加密接口对存储模型的固件分区做 AES-256 加密,加密密钥在产线阶段烧写到芯片 OTP 区,配置为禁止读出权限。开启安全启动机制,启动时自动校验固件分区的签名和哈希值,校验失败则直接停止启动。异常检测结果触发时,联动以太网硬件过滤器直接拦截异常报文,同时通过 IO 口输出报警信号到 PLC 控制系统。

实测数据:安全启动校验耗时 23ms,固件加密后模型读取耗时增加 3μs,异常响应延迟(从报文收齐到拦截动作生效)47μs,可拦截 99.9% 的固件篡改和 Flash 读取攻击。

五、核心代码与配置示例

5.1 Modbus 报文特征提取代码

objectivec 复制代码
#include "modbus.h"
#include <stdint.h>
#include <string.h>

// 滑动窗口配置:长度16是权衡特征覆盖度和推理延迟的典型值,步长1可降低连续攻击漏检概率
#define WINDOW_LEN 16
#define FEATURE_DIM 12
// INT8量化模型对应的特征缩放因子和零点,由量化工具输出,此处为示例值
#define FEATURE_SCALE 0.0392f
#define FEATURE_ZERO_POINT -128
// 特征窗口内存按64字节对齐,满足DSP DMA访问要求,否则会触发总线错误
static int8_t feature_window[WINDOW_LEN][FEATURE_DIM] __attribute__((aligned(64))) = {0};
static uint8_t window_ptr = 0;
static uint32_t frame_count = 0;

// 以太网中断中调用,输入为重组后的完整Modbus TCP帧指针和报文到达时间戳(单位μs)
// 必须在TCP流重组完成后调用,禁止直接处理分片以太网帧,否则特征提取错误
void modbus_feature_extract(const modbus_frame_t *frame, uint32_t timestamp)
{
    static uint32_t last_timestamp = 0;
    int8_t *cur_feature = feature_window[window_ptr];
    float raw_feature[FEATURE_DIM] = {0};
    
    // 12维特征提取,对应工业场景最具区分度的流量属性
    raw_feature[0] = frame->func_code;          // 功能码,区分读/写/异常响应,正常范围1~127
    raw_feature[1] = frame->reg_addr;           // 寄存器起始地址,正常范围0~65535
    raw_feature[2] = frame->reg_cnt;            // 操作寄存器数量,正常范围1~125
    raw_feature[3] = frame->data_len;           // 数据段长度,正常范围0~252
    raw_feature[4] = timestamp - last_timestamp;// 报文间隔,正常范围100μs~100ms
    raw_feature[5] = frame->src_port;           // 源端口,Modbus客户端通常为临时端口
    raw_feature[6] = frame->dst_port;           // 目的端口,标准Modbus TCP为502
    raw_feature[7] = frame->trans_id;           // 传输ID,正常请求响应配对
    raw_feature[8] = frame->protocol_id;        // 协议ID,Modbus TCP固定为0
    raw_feature[9] = frame->unit_id;            // 单元ID,对应从站地址
    raw_feature[10] = (frame->func_code > 0x80) ? 1.0f : 0.0f; // 是否为异常响应
    raw_feature[11] = (frame->data_len > 252) ? 1.0f : 0.0f;   // 是否为超大帧
    
    // FP32特征量化为INT8,公式:q = round(r / scale) + zero_point
    for(int i=0; i<FEATURE_DIM; i++)
    {
        int32_t q_val = (int32_t)(raw_feature[i] / FEATURE_SCALE + FEATURE_ZERO_POINT);
        // 数值截断到INT8范围,避免溢出
        cur_feature[i] = (int8_t)(q_val > 127 ? 127 : (q_val < -128 ? -128 : q_val));
    }
    
    last_timestamp = timestamp;
    window_ptr = (window_ptr + 1) % WINDOW_LEN;
    frame_count++;
}

// 判断窗口是否填满,填满可触发推理
uint8_t modbus_window_is_full(void)
{
    return (frame_count >= WINDOW_LEN) ? 1 : 0;
}

错误写法对比:如果不对齐内存,DSP 访问时会触发 HardFault;如果直接处理分片帧,特征提取错误率可达 30% 以上,漏检率大幅上升。

5.2 DSP 推理调用代码

objectivec 复制代码
#include "dsp_infer_api.h" // RK2108官方DSP推理SDK v2.3头文件
#include "tcn_tiny_int8.h" // 转换后的DSP模型头文件,包含模型二进制数组和长度

static dsp_context ctx = NULL;
static dsp_input inputs[1];
static dsp_output outputs[1];
// 输出缓冲区按64字节对齐,INT8量化模型输出为2个INT8值,对应正常/异常概率
static int8_t output_buf[2] __attribute__((aligned(64))) = {0};
// 输出缩放因子和零点,由量化工具输出,此处为示例值
#define OUTPUT_SCALE 0.0039f
#define OUTPUT_ZERO_POINT 0

// 初始化DSP推理环境,系统启动时调用一次
int modbus_detect_init(void)
{
    // DSP初始化参数:模型地址、模型长度、优先级0(最高)、空扩展参数
    int ret = dsp_init(&ctx, tcn_tiny_int8, tcn_tiny_int8_len, 0, NULL);
    if(ret < 0) 
    {
        // 初始化失败常见原因:模型未按64字节对齐、DSP时钟未开启、模型版本不匹配
        return -1;
    }
    
    // 配置输入张量:索引0、缓冲区地址、大小、格式INT8
    inputs[0].index = 0;
    inputs[0].buf = feature_window;
    inputs[0].size = WINDOW_LEN * FEATURE_DIM * sizeof(int8_t);
    inputs[0].fmt = DSP_TENSOR_INT8;
    
    // 配置输出张量:索引0、缓冲区地址、大小、格式INT8
    outputs[0].index = 0;
    outputs[0].buf = output_buf;
    outputs[0].size = 2 * sizeof(int8_t);
    outputs[0].fmt = DSP_TENSOR_INT8;
    return 0;
}

// 窗口满时调用,推理任务优先级设为最高,仅低于以太网中断
int modbus_detect_infer(void)
{
    int ret = dsp_inputs_set(ctx, 1, inputs);
    if(ret < 0) return -1;
    
    // 同步推理,阻塞直到DSP处理完成,耗时约87μs
    ret = dsp_run(ctx, NULL);
    if(ret < 0) return -2;
    
    ret = dsp_outputs_get(ctx, 1, outputs, NULL);
    if(ret < 0) return -3;
    
    // INT8输出反量化为FP32概率
    float abnormal_prob = (output_buf[1] - OUTPUT_ZERO_POINT) * OUTPUT_SCALE;
    // 异常概率阈值0.5,可根据场景调整:高安全场景设为0.3降低漏检率,低虚警场景设为0.7
    int is_abnormal = (abnormal_prob > 0.5f) ? 1 : 0;
    
    dsp_outputs_release(ctx, 1, outputs);
    return is_abnormal;
}

配置流程:需在系统初始化时开启 DSP 时钟,配置 DSP 和 M4F 的共享内存区域,否则 dsp_init 会返回 - 1 错误。

5.3 固件加密配置代码

objectivec 复制代码
#include "rk2108_otp.h"
#include "rk2108_crypto.h"
#include "rk2108_security.h"

// 量产阶段调用,密钥由产线工具随机生成,每个设备唯一,写入OTP后不可读出
void firmware_encrypt_config(void)
{
    // 产线工具通过调试接口写入32字节AES-256密钥,禁止固化在代码中
    uint8_t key[32] = {0};
    int ret = rk_otp_get_provision_key(key, 32);
    if(ret < 0) 
    {
        // 密钥未 provision,产线报错
        while(1);
    }
    
    // 写入OTP用户0区,配置为禁止读出、禁止擦除权限,写入后永久生效
    ret = rk_otp_write_key(OTP_KEY_USER0, key, 32, OTP_KEY_PERM_READ_DISABLE | OTP_KEY_PERM_WRITE_DISABLE);
    if(ret < 0) 
    {
        // OTP写入失败,常见原因:OTP区已锁、供电不稳定
        while(1);
    }
    
    // 配置固件分区0(模型存储区,地址0x10010000,大小64KB)为AES-256加密模式
    // 代码运行分区禁止加密,否则取指失败直接崩溃
    ret = rk_crypto_set_encrypt_partition(0, CRYPTO_ALG_AES_256, OTP_KEY_USER0);
    if(ret < 0) 
    {
        // 加密配置失败,常见原因:分区地址越界、加密模块时钟未开启
        while(1);
    }
    
    // 开启安全启动,校验固件哈希和RSA签名,校验失败则停止启动
    // 签名公钥提前烧写在OTP区,禁止修改
    rk_security_set_secure_boot(SECURE_BOOT_ENABLE, SECURE_BOOT_VERIFY_HASH | SECURE_BOOT_VERIFY_SIGN);
}

错误写法对比:如果将代码运行分区配置为加密,CPU 取指时无法解密,会直接触发 HardFault 导致设备砖化。

六、实战总结与避坑指南

6.1 实测结论

本方案在 RK2108 平台上的实测性能如下:

测试条件为 Cortex-M4F 400MHz、HIFI3 DSP 600MHz、优化等级 O3、INT8 量化。Modbus 报文特征提取耗时 12μs,DSP 推理耗时 87μs,端到端总延迟 99μs,低于 100μs 设计目标;对写劫持、DDoS、慢扫描三类典型攻击的平均检测准确率 98.4%,虚警率低于 0.5%;系统总 SRAM 占用 62KB,Flash 占用 32KB,资源占用率低于 30%;开启固件加密和安全启动后,模型逆向难度提升 4 个数量级,满足等保 2.0 工控安全第三级要求。

6.2 常见问题排查

  1. 推理结果全为正常 / 全为异常:首先检查特征提取逻辑是否正确,打印 12 维特征值确认是否符合 Modbus 协议规范;其次检查量化参数(缩放因子、零点)是否和模型转换时的输出一致,参数不匹配会导致概率计算完全错误;最后检查 DSP 输入输出内存是否按 64 字节对齐,未对齐会导致 DMA 传输数据错误。
  2. 推理耗时超过 200μs:首先检查 DSP 时钟是否配置为 600MHz,默认复位后 DSP 时钟为 200MHz,性能只有 1/3;其次检查是否开启了 O3 优化,未开启优化的推理耗时会增加 2 倍以上;最后检查推理任务优先级是否低于其他任务,调度延迟会叠加到总耗时中。
  3. 开启加密后设备无法启动:首先检查是否将代码运行分区配置为加密,代码分区必须明文存储;其次检查安全启动的公钥是否正确烧写在 OTP 区,签名校验失败会直接停止启动;最后检查加密分区的地址和大小是否和分区表一致,越界访问会触发加密错误。

6.3 性能调优建议

  1. 延迟优化:如果实时性要求高于 50μs,可将特征提取逻辑移植到 DSP 上运行,相比 M4F 执行速度提升 30%;将滑动窗口长度调整为 8,推理耗时可降低 40%,精度损失约 1.2%,可根据场景权衡。
  2. 精度优化:如果现场漏检率过高,可将校准集规模从 1 万帧提升到 5 万帧,覆盖更多现场流量特征;将 TCN 卷积核数量从 8 提升到 16,精度提升 0.8%,推理耗时增加 25μs。
  3. 资源优化:如果 SRAM 不足,可将特征窗口配置为 32 字节对齐(DSP 最小对齐要求),节省内存开销;去掉传输 ID、协议 ID 等低区分度特征,特征维度压缩到 8 维,内存占用降低 33%,精度损失约 0.5%。

6.4 选型指南

  • 对于算力低于 400MHz 的 MCU 平台,建议将 TCN 卷积核数量砍到 4 个,推理耗时降低 30%,精度损失不超过 2%,可适配 Cortex-M4F 级别的 MCU。
  • 对于多协议检测场景,可扩展特征维度到 24 维,窗口长度调整为 32,模型体积增加到 15KB,推理耗时增加到 150μs,可同时支持 Modbus TCP、S7、Profinet 等协议检测。
  • 对于高安全量产场景,必须开启安全启动和固件加密,同时关闭调试接口,避免攻击者通过 JTAG 读取内存中的模型和密钥。
相关推荐
H_oRIZoN_1 天前
Linux入门DAY34(TCP)
tcp·网络通信·传输层·linux应用编程
pnoker3 天前
36 个驱动模块:应对协议碎片化
java·物联网·modbus·工业互联网·opc ua
虎王物联3 天前
STM32 HAL库串口DMA空闲中断:高效接收不定长Modbus数据帧
stm32·单片机·嵌入式硬件·dma·modbus
csdn_aspnet4 天前
Modbus RTU 与 Modbus TCP:它们有什么区别?
网络·tcp/ip·tcp·modbus·rtu
物联网IoT小易4 天前
Modbus RTU设备如何接入物联网平台?从串口采集到MQTT上云
物联网·modbus·物联网平台·modbus协议·modbus rtu·modbus rtu设备接入
AlanBruce6 天前
逻辑控制功能详解
自动化·上位机·plc·modbus·mthings·摩尔信使
AlanBruce7 天前
一键设备扫描功能详解
服务器·网络·网络协议·modbus·摩尔信使·设备扫描
xxy222418 天前
Linux 网络编程入门(一):从 OSI 模型到 TCP Socket 编程
网络·tcp/ip·tcp
飞猫的边缘AI10 天前
边缘AI-5: 了解最灵活的计算芯片FPGA
人工智能·fpga开发·ai芯片·边缘ai·计算芯片·边缘ai芯片·titanium edge