5.2 磁盘CRC32完整性检测

磁盘,crc32,完整性,检测 · 浏览次数 : 211

小编点评

**CRC 校验技术** CRC 校验技术是一种用于检测数据传输或存储过程中是否出现错误的方法,通过计算数据的循环冗余校验值(CRC)来检测任何数据损坏。 **关键步骤:** 1. 计算数据 CRC 值。 2. 将 CRC 值存储到文件中。 3. 在运行程序之前,读取 CRC 值。 4. 计算实际数据和 CRC 值之间的差异。 5. 如果差异小于阈值,则认为数据完整,否则认为数据损坏。 **代码示例:** ```c++ #include #include #include using namespace std; int CalculateDiskCRC32() { // 获取文件长度 DWORD FileSize = GetFileSize(hFile, 0); // 计算 CRC32 值 DWORD OriginalCRC32 = *(DWORD *)((DWORD)pNtHeader - 4); // 读取文件到内存 DWORD dwNum = 0; ReadFile(hFile, pBuffer, FileSize, &dwNum, NULL); // 计算 CRC32 值 DWORD CheckCRC32 = CRC32((BYTE*)(pBuffer + pDosHeader->e_lfanew), FileSize); // 检查 CRC32 值匹配 if (CheckCRC32 == OriginalCRC32) { return FALSE; } return TRUE; } ``` **使用方法:** 1. 将此代码保存为 .cpp 文件。 2. 在 .cpp 文件中包含 `windows.h` 和 `fstream` 库。 3. 使用 `CalculateDiskCRC32()` 函数检查磁盘完整性。 4. 如果完整,则程序正常运行。 5. 如果数据损坏,则程序将输出错误信息。

正文

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

磁盘CRC(循环冗余校验)用于检测磁盘数据的完整性,一般而言某些木马专杀工具同样会用到磁盘CRC特征校验技术,该技术的实现原理与内存验证原理完全一致,针对磁盘的验证同样很简单,但此处我们需要将计算到的CRC32值存储到PE文件自身中,通常我们可以存储到PE文件的前一个DWORD的位置上,程序运行后对比这个值,来判断程序是否被打过补丁,如果打过直接结束掉。

// 检查磁盘完整性
BOOL CalculateDiskCRC32()
{
    char szFileName[MAX_PATH] = { 0 };

    char *pBuffer;
    DWORD pNumberOfBytesRead;
    int FileSize = 0;

    // 获取自身文件,并打开文件
    GetModuleFileName(0, szFileName, MAX_PATH);
    HANDLE hFile = CreateFile(szFileName, GENERIC_READ, 1, 0, 3, FILE_ATTRIBUTE_NORMAL, 0);
    if (hFile == INVALID_HANDLE_VALUE)
    {
        return TRUE;
    }

    // 取文件长度
    FileSize = GetFileSize(hFile, 0);
    pBuffer = new char[FileSize];

    // 读取文件到内存
    ReadFile(hFile, pBuffer, FileSize, &pNumberOfBytesRead, 0);
    CloseHandle(hFile);

    PIMAGE_DOS_HEADER pDosHeader = NULL;
    PIMAGE_NT_HEADERS32 pNtHeader = NULL;

    pDosHeader = (PIMAGE_DOS_HEADER)pBuffer;

    // 获取到NT头
    pNtHeader = (PIMAGE_NT_HEADERS32)((DWORD)pDosHeader + pDosHeader->e_lfanew);

    // 定位到PE文件头前4字节处
    DWORD OriginalCRC32 = *(DWORD *)((DWORD)pNtHeader - 4);
    printf("[*] 读出节表值 = %x \n", OriginalCRC32);

    // 我们只需要计算PE结构的CRC32值,不需要计算DOS头
    FileSize = FileSize - DWORD(pDosHeader->e_lfanew);
    DWORD CheckCRC32 = CRC32((BYTE*)(pBuffer + pDosHeader->e_lfanew), FileSize);
    printf("[+] 计算CRC32 = %x \n", CheckCRC32);

    if (CheckCRC32 == OriginalCRC32)
    {
        return FALSE;
    }
    else
    {
        return TRUE;
    }
    return TRUE;
}

int main(int argc, char* argv[])
{
    BOOL ref = CalculateDiskCRC32();
    if (ref == TRUE)
    {
        printf("[-] 程序已被修改 \n");
    }
    else
    {
        printf("[+] 程序正常 \n");
    }

    system("pause");
    return 0;
}

首先读者运行上述程序,则程序会输出当前的CRC32值be63ac8b我们记下这个HASH值,如下图所示;

并将此值替换到如下图中的黄色位置,当程序运行后会读取该区域内的数据,并与动态计算的CRC32值进行计算,最终判断是否被修改,如下图所示;

通过CRC32数据对比并遍历磁盘文件,我们可以实现一个简单的特征定位查杀程序,用于专门定位某些特殊的程序,如下是修改后的代码片段;

// 计算文件CRC过程
BOOL CalcCRC32(char *FilePath)
{
    // 打开文件
    HANDLE hFile = CreateFile(FilePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE)
    {
        return FALSE;
    }

    // 获取文件大小
    DWORD dwSize = GetFileSize(hFile, NULL);
    if (dwSize == 0xFFFFFFFF)
    {
        return FALSE;
    }

    // 分配内存
    BYTE *pFile = (BYTE*)malloc(dwSize);
    if (pFile == NULL)
    {
        return FALSE;
    }

    // 读取内存
    DWORD dwNum = 0;
    ReadFile(hFile, pFile, dwSize, &dwNum, NULL);

    // 计算CRC32
    DWORD dwCRC32 = CRC32(pFile, dwSize);
    if (pFile != NULL)
    {
        free(pFile);
        pFile = NULL;
    }

    CloseHandle(hFile);
    return dwCRC32;
}

int main(int argc, char* argv[])
{
    WIN32_FIND_DATA stFindFile;
    HANDLE hFindFile;
    char *szFilter = "*.exe";      // 筛选所有的.exe结尾的文件
    char szFindFile[MAX_PATH];     // 保存欲检测程序的路径
    char szSearch[MAX_PATH];       // 保存完整的筛选路径
    int ret = 0;                   // 搜索状态返回值

    lstrcpy(szFindFile, "D:\\");   // 搜索D盘目录下的所有exe结尾的文件
    lstrcpy(szSearch, "D:\\");
    lstrcat(szSearch, szFilter);
    DWORD dwTmpCRC32;

    hFindFile = FindFirstFile(szSearch, &stFindFile);
    if (hFindFile != INVALID_HANDLE_VALUE)
    {
        do
        {
            lstrcat(szFindFile, stFindFile.cFileName);
            dwTmpCRC32 = CalcCRC32(szFindFile);

            // 比较判断
            if (dwTmpCRC32 == 0xbe63ac8b)
            {
                printf("[*] CRC32 = %x 发现病毒 %s \n", dwTmpCRC32, szFindFile);
            }
            else
            {
                printf("[-] CRC32 = %x 正常程序 %s \n", dwTmpCRC32, szFindFile);
            }
            // 删除程序名称只保留"C:\"
            szFindFile[3] = '\0';
            ret = FindNextFile(hFindFile, &stFindFile);
        } while (ret != 0);
    }

    FindClose(hFindFile);

    system("pause");
    return 0;
}

运行程序输出效果如下图所示;

本文作者: 王瑞
本文链接: https://www.lyshark.com/post/7a9a55f0.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

与5.2 磁盘CRC32完整性检测相似的内容:

5.2 磁盘CRC32完整性检测

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

Centos7下创建centos-home逻辑分区

1备份要挂载的文件夹 查看home文件夹有无文件,如有文件一定要记得备份 2创建逻辑分区 2.1查看已有逻辑分区 2.2查看磁盘分区情况 2.3查看磁盘PV 2.4创建逻辑分区 lvcreate -n home -l 100%FREE centos 2.5查看逻辑分区情况 3初始化文件系统 3.1初

制作KubeVirt镜像

目录制作KubeVirt镜像1. 准备磁盘文件2. 编写Dockerfile3. 构建镜像4. 上传镜像到仓库(可选)5. 导出镜像6. 虚拟机yaml文件7. 启动虚拟机8. 启动虚拟机报错 制作KubeVirt镜像 我们现在已经安装好了Kubevirt并且也运行了第一个虚拟机,但是这个虚拟机并不

[转帖]什么是RAID(独立磁盘冗余阵列)?

目录 什么是RAID(独立磁盘冗余阵列)? 什么是RAID? RAID 0 RAID 1 RAID 2 RAID 3 RAID 4 RAID 5 RAID 6 其他配置 RAID适合您吗? RAID 0,1,5,6,10 RAID级别0 –条带化 RAID 0的优点 RAID 0的缺点 理想用途 R

5.2 基于ROP漏洞挖掘与利用

通常情况下栈溢出可能造成的后果有两种,一类是本地提权另一类则是远程执行任意命令,通常C/C++并没有提供智能化检查用户输入是否合法的功能,同时程序编写人员在编写代码时也很难始终检查栈是否会发生溢出,这就给恶意代码的溢出提供了的条件,利用溢出攻击者可以控制程序的执行流,从而控制程序的执行过程并实施恶意行为,本章内容笔者通过自行编写了一个基于网络的FTP服务器,并特意布置了特定的漏洞,通过本章的学习,

5.2 汇编语言:标志位测试指令

汇编语言是一种面向机器的低级语言,用于编写计算机程序。汇编语言与计算机机器语言非常接近,汇编语言程序可以使用符号、助记符等来代替机器语言的二进制码,但最终会被汇编器编译成计算机可执行的机器码。标志位测试指令是汇编语言中用于测试处理器标志位状态的指令。标志位是位于处理器状态寄存器中的一组特殊标志,用于指示上一个运算的结果是否为零、是否进位/借位、是否溢出等等。可以使用标志位测试指令来检查标志位的状态

TypeScript又出新关键字了?

TypeScript 5.2将引入一个新的关键字:`using`。当它离开作用域时,你可以用`Symbol.dispose`函数来处置任何东西。 ```jsx { const getResource = () => { return { [Symbol.dispose]: () => { conso

.NET周刊【5月第2期 2024-05-12】

国内文章 C#在工业数字孪生中的开发路线实践 https://mp.weixin.qq.com/s/b_Pjt2oii0Xa_sZp_9wYWg 这篇文章探讨了C#在工业数字孪生技术中的应用,介绍了三种基于C#的数字孪生系统实现方案: WPF + Unity:结合WPF技术和Unity引擎,实现客户

[转帖]5.2. 使用HINT

¶ 本章节包含以下内容: 概述 HINT的功能 HINT的使用 配置参数 示例 注意 5.2.1. 概述 ¶ KingbaseES使用的是基于成本的优化器。优化器会估计SQL语句的每个可能的执行计划的成本,然后选择成本最低的执行计划来执行。因为优化器不计算数据的某些属性,比如列之间的相关性,优化器有

「C++」简单模拟

这是一个公式: \[F_n=\dfrac{\left(\frac{1+\sqrt{5}}{2}\right)^n-\left(\frac{1-\sqrt{5}}{2}\right)^n}{\sqrt{5}} \]根据大家的数学经验可以知道这是一个计算斐波那契数列的公式,那么假设我们不知道这是一个斐波