5.0 CRC32校验技术概述

本文介绍了CRC校验技术,它可检测数据传输或存储中的错误。通过该技术能对内存和磁盘文件进行完整性检测,防止非法篡改。还阐述了内存和磁盘中CRC校验的具体应用,以及自行实现CRC32算法的步骤和核心代码,不过要注意它并非加密算法。

CRC校验技术是用于检测数据传输或存储过程中是否出现了错误的一种方法,校验算法可以通过计算应用与数据的循环冗余校验(CRC)检验值来检测任何数据损坏。通过运用本校验技术我们可以实现对特定内存区域以及磁盘文件进行完整性检测,并以此来判定特定程序内存是否发生了变化,如果发生变化则拒绝执行,通过此种方法来保护内存或磁盘文件不会被非法篡改。总之,内存和磁盘中的校验技术都是用于确保数据和程序的完整性和安全性的重要技术。

以下是一些关于内存和磁盘中的CRC校验技术的详细信息:

  • 内存中的CRC校验技术

    • 在内存中使用CRC校验技术可用于防止缓冲区溢出攻击。内存中的CRC校验技术将根据程序的特定部分计算数据的CRC值并存储在内存中。当程序运行时,它会自动计算相同的部分的CRC值,以确保没有被篡改。如果发现CRC值不匹配,则此可能是攻击发生的异常,程序可以终止。
  • 磁盘中的CRC校验技术

    • 使用CRC校验技术可用于检测磁盘文件是否被篡改。磁盘文件的CRC值将在文件中的特定位置处存储。在运行程序之前,程序将读取此CRC值并使用相同的算法计算自己的CRC值以检查文件是否被篡改。如果发现两个CRC值不匹配,则应用程序可能已被篡改或病毒感染。

首先我们需要自行实现一个CRC算法,通常情况下CRC算法需要经历三个步骤,生成CRC表格,读取数据并计算CRC,计算最终的CRC值,这个实现原理可细化为如下三步;

  • 生成CRC表格

    • 首先,需要生成一个长度为256CRC表格。该表格包含了用于生成32CRC值所需的所有信息。CRC32表通常是固定的,可作为算法的参数,也可以根据所需的多项式动态生成。
  • 读取数据并计算CRC

    • 计算CRC值的过程是将指定块的数据视为位流,并将位流分成32位的块。这些块按顺序处理,每次使用CRC表格中的值对32位值进行XOR和位移操作。该操作迭代执行,以依次处理每个块。
  • 计算最终的CRC值

    • 处理所有块后,可以计算最终的CRC值。大多数实现都反转了这个值的位,以进行优化,并将计算出的值与0xFFFFFFFF(32位的所有位都是1)进行XOR运算以得到最终值。

根据上述描述读者应该可以理解CRC32的工作原理,如下代码是实现CRC32的核心算法。该算法生成一个256个元素的CRC表,在输入数据块上执行一系列按位运算。CRC32算法将输入的数据块视为位串,并产生一个唯一的32位输出,该输出可以用于验证数据的完整性和一致性等方面。

在该代码中,CRC表是动态生成的,采用了多项式0xEDB88320L。然后,该算法使用crcTmp2变量来存储中间CRC值,对每个字节进行一系列运算,以生成最终的CRC32值。返回值为计算出的CRC32值。

// 定义一个指向字节缓冲区的指针ptr和字节缓冲区的大小Size,计算并返回CRC32值
DWORD CRC32(BYTE* ptr, DWORD Size)
{
  DWORD crcTable[256], crcTmp1;

  // 动态生成CRC-32表
  // 生成一个长度为256的CRC表格,共含有256个元素
  for (int i = 0; i<256; i++)
  {
    crcTmp1 = i;
    // 每个元素计算8个字节
    for (int j = 8; j>0; j--)
    {
      if (crcTmp1 & 1) crcTmp1 = (crcTmp1 >> 1) ^ 0xEDB88320L; // 判断是否需要异或 0xEDB88320L
      else crcTmp1 >>= 1;                                      // 如果不需要异或,则每次将该数右移一位
    }
    // 将得到的结果存放在CRC表格中
    crcTable[i] = crcTmp1;
  }
  
  // 计算CRC32值
  // 使用while循环来逐步处理字节块
  DWORD crcTmp2 = 0xFFFFFFFF;
  while (Size--)
  {
    // 将crcTmp2右移8位,并将最高8位数据清零
    crcTmp2 = ((crcTmp2 >> 8) & 0x00FFFFFF) ^ crcTable[(crcTmp2 ^ (*ptr)) & 0xFF];
    ptr++; // 处理下一个字节
  }
  // 将最终的crcTmp2值反转位顺序,并执行XOR运算,返回最终的CRC32值
  return (crcTmp2 ^ 0xFFFFFFFF);
}

上述代码则是CRC32生成的核心实现流程,读者在使用时只需要调用封装好的CRC32()函数并依次传入字符串及字符串长度,即可完成流程调用。但此处读者需要注意,CRC32不是加密算法,不能保证数据的安全性。其只能作为较小数据块的简单完整性检查和错误检测的一种手段。

int main(int argc, char *argv[])
{
    char* ptr = "hello lyshark";
    DWORD size = sizeof("hello lyshark");

    printf("原始字符串: %s \n", ptr);

    DWORD ret = CRC32((BYTE *)ptr, size);
    printf("CRC32 = %x \n", ret);

    system("pause");
    return 0;
}

当调用上述代码时读者应该可以看到hello lyshark字符串的CRC32码,输出效果如下图所示;

上述代码片段仅用于验证内存字符串,如果读者需要验证磁盘文件的特征码则首先需要通过CreateFile打开文件得到文件句柄,接着通过ReadFile将整个文件读入到内存,最后再次调用CRC32(pFile, dwSize)实现验证文件的CRC数据,但此方法仅用于验证小文件,如果文件过大则可能会耗费大量的内存。

int main(int argc, char* argv[])
{
    char *FileName = "d://lyshark.exe";

    // 验证文件是否存在
    if (GetFileAttributes(FileName) == 0xFFFFFFFF)
    {
        return 0;
    }

    // 打开文件
    HANDLE hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);

    // 得到文件长度
    DWORD dwSize = GetFileSize(hFile, NULL);

    // 开辟一段内存空间
    BYTE *pFile = (BYTE*)malloc(dwSize);

    // 将数据读入文件
    DWORD dwNum = 0;
    ReadFile(hFile, pFile, dwSize, &dwNum, 0);

    // 计算CRC32
    DWORD dwCrc32 = CRC32(pFile, dwSize);
    if (pFile != NULL)
    {
        printf("文件名 = %s \n", FileName);
        printf("文件长度 = %d \n", dwSize);
        printf("分配内存 = 0x%x \n", pFile);
        printf("CRC32 = 0x%x \n", dwCrc32);
        free(pFile);
        pFile = NULL;
    }

    system("pause");
    return 0;
}

上述代码运行后则可输出d://lyshark.exe文件的CRC32值,输出效果如下图所示;

### STM32 控制闭环步进电机张大头 V5.0 的实现 #### 实现概述 为了通过 STM32 控制张大头 Emm42_V5.0 闭环步进电机,可以利用其支持的多种通信接口(如串口、CAN 总线等)。以下是基于串口通信的一个典型实现方法。 --- #### 硬件连接配置 根据提供的信息[^2],对于 STM32 和闭环步进电机之间的串口通信,需注意以下接线方式: - **STM32 TTL 接口与闭环电机**: - RX (STM32) → TX (闭环电机) - TX (STM32) → RX (闭环电机) - GND (STM32) → GND (闭环电机) - 如果使用 RS232 或 RS485 转换模块,则还需额外连接电源端子(如 3V3/VCC),并按照对应的协议标准完成接线。 --- #### 示例代码:STM32 发送 Modbus RTU 命令控制电机 下面是一个简单的 STM32 示例程序,用于向闭环步进电机发送 Modbus RTU 协议命令来设置目标转速和检测堵转状态。假设已启用 UART 外设作为串口通信工具。 ```c #include "stm32f1xx_hal.h" // 定义波特率及寄存器地址 #define BAUD_RATE 9600 #define TARGET_SPEED_REGISTER 0x01 // 设置目标转速的目标寄存器地址 #define BLOCK_TIME_MS 10 // 防止堵转的时间间隔 UART_HandleTypeDef huart1; void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_USART1_UART_Init(void); /** * @brief 初始化串口外设 */ void init_uart() { MX_USART1_UART_Init(); } /** * @brief 构造Modbus RTU帧数据包 * * @param address 设备地址 * @param function_code 功能码 * @param register_address 寄存器地址 * @param value 数据值 * @return uint8_t* 返回完整的Modbus帧数组指针 */ uint8_t* build_modbus_frame(uint8_t address, uint8_t function_code, uint16_t register_address, int16_t value) { static uint8_t frame[8]; uint16_t crc = 0xFFFF; frame[0] = address; // 地址域 frame[1] = function_code; // 功能码 frame[2] = (register_address >> 8); // 寄存器高字节 frame[3] = (register_address & 0xFF); // 寄存器低字节 frame[4] = ((value >> 8) & 0xFF); // 数据高字节 frame[5] = (value & 0xFF); // 数据低字节 // 计算CRC校验 for(int i=0;i<6;i++) { // 只计算前六个字节的数据部分 crc ^= frame[i]; // XOR当前字节到CRC中 for(int j=0;j<8;j++) { if(crc & 0x0001){ crc >>= 1; crc ^= 0xA001; }else{ crc >>= 1; } } } frame[6] = (crc & 0xFF); // CRC低位放入第7字节 frame[7] = (crc >> 8); // CRC高位放入第8字节 return frame; } int main(void) { HAL_Init(); // 初始化HAL库 SystemClock_Config(); // 配置系统时钟 MX_GPIO_Init(); // GPIO初始化 init_uart(); // 初始化串口 while(1) { // 创建一个写入目标转速的Modbus请求帧 uint8_t modbus_frame[8]; memcpy(modbus_frame, build_modbus_frame(0x01, 0x06, TARGET_SPEED_REGISTER, 100), sizeof(modbus_frame)); // 将构建好的帧发送给闭环步进电机 HAL_UART_Transmit(&huart1, modbus_frame, sizeof(modbus_frame), HAL_MAX_DELAY); // 模拟阻塞时间以防止频繁调用引起堵转保护触发 HAL_Delay(BLOCK_TIME_MS); // 进一步扩展逻辑可加入读取反馈数据的功能... } } ``` 上述代码实现了基本的 Modbus RTU 请求构造以及通过 UART 向闭环步进电机发送指令的过程。其中 `build_modbus_frame` 函数负责生成符合 Modbus RTU 格式的帧结构,并附带 CRC 校验机制以保障传输可靠性。 --- #### 关于堵转保护 依据描述[^3],当电机的实际运行参数超出设定阈值范围一定时间内未恢复正常工作状态时,驱动器会自动判断发生堵转现象而切断动力供应。因此,在实际应用过程中应合理规划任务周期避免因过短操作频率引发误判。 --- ### 注意事项 - 在调试阶段建议先验证单条简单命令的成功执行情况再逐步增加复杂度。 - 若采用其他类型的物理层介质(比如 CAN 总线代替传统串行链路),则需要调整底层驱动函数适配相应硬件特性。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

微软技术分享

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值