5.2 磁盘CRC32完整性检测

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

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

c 复制代码
// 检查磁盘完整性
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数据对比并遍历磁盘文件,我们可以实现一个简单的特征定位查杀程序,用于专门定位某些特殊的程序,如下是修改后的代码片段;

c 复制代码
// 计算文件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 许可协议。转载请注明出处!

相关推荐
神仙别闹11 分钟前
基于MFC实现的赛车游戏
c++·游戏·mfc
小c君tt18 分钟前
MFC中 error C2440错误分析及解决方法
c++·mfc
木向1 小时前
leetcode92:反转链表||
数据结构·c++·算法·leetcode·链表
阿阿越1 小时前
算法每日练 -- 双指针篇(持续更新中)
数据结构·c++·算法
hunandede1 小时前
FFmpeg存放压缩后的音视频数据的结构体:AVPacket简介,结构体,函数
c++
hunandede2 小时前
FFmpeg 4.3 音视频-多路H265监控录放C++开发十三:将AVFrame转换成AVPacket。视频编码,AVPacket 重要函数,结构体成员学习
c++·ffmpeg·音视频
奋斗的小花生8 小时前
c++ 多态性
开发语言·c++
闲晨8 小时前
C++ 继承:代码传承的魔法棒,开启奇幻编程之旅
java·c语言·开发语言·c++·经验分享
UestcXiye9 小时前
《TCP/IP网络编程》学习笔记 | Chapter 3:地址族与数据序列
c++·计算机网络·ip·tcp
霁月风10 小时前
设计模式——适配器模式
c++·适配器模式