5.2 磁盘CRC32完整性检测

2023-09-19 09:42:21

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 许可协议。转载请注明出处!

更多推荐

【学习笔记】POJ 3834 graph game

点这里结论题😅,图一乐结论:如果原图中存在两个边集不交的生成树,那么Bob\text{Bob}Bob必胜;否则Alice\text{Alice}Alice必胜证明有点难😅首先,考虑维护两颗不存在红边的生成树,如果Alice\text{Alice}Alice断掉了其中一颗树上的一条边,将这个树分成两个连通块,那么Bo

求函数f(x,y)在曲线C上的最大方向导数问题

方向导数:在许多问题中,不仅要知道函数在坐标轴方向上的变化率(即偏导数),而且要设法求得函数在某点沿着其他特定方向上的变化率,这就是方向导数方向导数的定义式和计算公式定义式:前提:三元函数u=u(x,y,z)u=u(x,y,z)u=u(x,y,z)在点P0(x0,y0,z0)P_0(x_0,y_0,z_0)P0​(x0

2023华为杯研究生数学建模D题思路代码分析

完整的分析查看文末名片获取!问题一:区域碳排放量以及经济、人口、能源消费量的现状分析(1)建立指标与指标体系要求1:指标能够描述某区域经济、人口、能源消费量和碳排放量的状况;要求2:指标能够描述各部门(能源供应部门、工业消费部门、建筑消费部门、交通消费部门、居民生活消费、农林消费部门)的碳排放状况;要求3:指标体系能够

命令模式简介

概念:命令模式是一种行为设计模式,它将请求封装成一个对象,从而允许您将不同的请求参数化、队列化,并且能够在不同的时间点执行。通过引入命令对象(Command)来解耦发送者(Invoker)和接收者(Receiver),使得发送者无需知道具体的接收者或操作细节。命令对象封装了一系列操作,并提供了一个统一的方法(如exec

Delaunay三角剖分算法

目录一.简介1.1三角剖分1.2Delaunay三角剖分二.Delaunay三角剖分的相关理论2.1Delaunay三角形和(局部)Delaunay边的概念2.2Delaunay引理2.3翻转边算法(flipalgorithm)2.4Delaunay三角剖分的最优性质三.Delaunay三角剖分的构造算法3.1Laws

什么是JavaScript中的IIFE(Immediately Invoked Function Expression)?它的作用是什么?

聚沙成塔·每天进步一点点⭐专栏简介⭐JavaScript中的IIFE⭐示例⭐写在最后⭐专栏简介前端入门之旅:探索Web开发的奇妙世界欢迎来到前端入门之旅!感兴趣的可以订阅本专栏哦!这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发者,这里都将为你提供一个系统而

【Linux从入门到精通】多线程 | 线程介绍&线程控制

本篇文章主要对线程的概念和线程的控制进行了讲解。其中我们再次对进程概念理解。同时对比了进程和线程的区别。希望本篇文章会对你有所帮助。文章目录一、线程概念1、1什么是线程1、2再次理解进程概念1、3轻量级进程二、进程控制2、1创建线程pthread_create2、2线程与进程资源2、3线程id2、4获得线程idpthr

小米华为,化干戈为玉帛!

近日来,手机圈又掀起了各大厂家推出新品的高潮。首先是华为Mate60的推出,其自研的麒麟9000S芯片瞬间点燃了国内手机市场,得到了国内甚至国外业界人士的认可和好评。而近日网上盛传的小米创始人雷军的“愿意加入华为技术生态圈”的邀请,引起了网友们的高度关注。截图自今日头条@刘哥抖料大家都知道,小米采用的是高通芯片和谷歌操

代码签名证书品牌哪家好?选微软推荐机构

代码签名证书是保护软件代码完整性及来源可信的重要方式,软件程序要在操作系统中运行,就需要使用权威合规的代码签名证书,对软件代码进行数字签名,确保软件来源可信、未被非法篡改,消除操作系统“未知发布者”警告,让软件能够顺畅运行。众多代码签名证书厂商中,哪些厂商提供的代码签名证书才是获得操作系统信任的呢?本文将为大家介绍,如

【JVM】类加载器

类与类加载器类加载器虽然只用于实现类的加载动作,但它在Java程序中起到的作用却远超类加载阶段。对于任意一个类,都必须由加载它的类加载器和这个类本身一起共同确立其在Java虚拟机中的唯一性,每一个类加载器,都拥有一个独立的类名称空间。这句话可以表达得更通俗一些:比较两个类是否“相等”,只有在这两个类是由同一个类加载器加

springboot实战(七)之jackson配置前后端交互下划线转驼峰&对象序列化与反序列化

目录环境:1.驼峰转下划线配置1.1单个字段命名转化使用@JsonProperty注解1.2单个类进行命名转化使用@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)注解3.全局命名策略配置2.序列化以及反序列化2.1序列化2.2反序列化3.自定义序

热文推荐