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

内存CRC32特征检测通常用于防止软件破解或打补丁,内存特征码检查实现原理是通过定位到.text节表的首地址及该节的长度,然后计算该节的CRC32值并存入全局变量,通过在程序内部打开一个子线程用于实时监测内存,一旦发现CRC32值发生了变化,则可执行终止程序运行等操作,以此来实现防止破解或打补丁的目的。

我们来看这样一段代码,程序通过GetModuleHandle(NULL)函数获取到自身程序的句柄,并通过PE结构定位到.text节,取出该节内的VirtualAddress虚拟地址,以及VirtualSize虚拟长度,最后调用CRC32((BYTE*)(va_base), sec_len)获取到该节的CRC数据。

// 检查内存中CRC32特征值
DWORD CalculateMemoryCRC32()
{
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNtHeader = NULL;
PIMAGE_SECTION_HEADER pSecHeader = NULL;
DWORD ImageBase; // 获取基地址
ImageBase = (DWORD)GetModuleHandle(NULL); // 定位到PE头结构
pDosHeader = (PIMAGE_DOS_HEADER)ImageBase;
pNtHeader = (PIMAGE_NT_HEADERS32)((DWORD)pDosHeader + pDosHeader->e_lfanew); // 定位第一个区块地址,因为默认的话第一个就是.text节
pSecHeader = IMAGE_FIRST_SECTION(pNtHeader);
DWORD va_base = ImageBase + pSecHeader->VirtualAddress; // 定位代码节va基地址
DWORD sec_len = pSecHeader->Misc.VirtualSize; // 获取代码节长度
printf("镜像基址(.text): %x | 镜像大小: %d \n", va_base, sec_len); DWORD CheckCRC32 = CRC32((BYTE*)(va_base), sec_len);
printf(".text节CRC32 = %x \n", CheckCRC32); return CheckCRC32;
}

当主程序执行时,我们首先通过CalculateMemoryCRC32函数获取到当前代码段的校验码,并存储到OriginalCRC32全局变量内,在循环体内通过不断的计算CRC数据并与全局初始值做对比,以此来实现防止破解的作用。

int main(int argc, char *argv[])
{
// 用于保存初始化时 .text 节中的CRC32值
DWORD OriginalCRC32 = 0; // 初始化时,给全局变量赋值,记录下初始的CRC32值
OriginalCRC32 = CalculateMemoryCRC32(); while (1)
{
// 每隔3秒计算一次
Sleep(3000); // 计算新的CRC
DWORD NewCRC32 = CalculateMemoryCRC32();
if (OriginalCRC32 == NewCRC32)
{
printf("[+] 当前CRC [ %x ] 程序没有被打补丁 \n",NewCRC32);
}
else
{
printf("[-] 当前CRC [ %x ] 已被打补丁 \n", NewCRC32);
}
} system("pause");
return 0;
}

编译并运行上述程序片段,当读者使用x64dbg修改内存中的字节时,此处将int3修改为nopCRC32会提示我们内存已经被打补丁,输出效果如下图所示;

当然上述方法虽然可以对全局进行保护,但如果程序过大则此类验证效率将变得很低,我们需要通过使用打标签的方式对特定内存区域进行保护,如下代码中所示,我们通过begin设置开始保护标签,通过end设置结束保护标签,通过size = end_addr - begin_addr;计算即可获取到当前所需要保护的内存长度,最后通过CalculateMemoryCRC32实现计算内存CRC的目的,读者可以在当前进程内启动子线程用于实现专门的内存检测。

// 检查内存中CRC32特征值
DWORD CalculateMemoryCRC32(DWORD va_base, DWORD sec_len)
{
DWORD CheckCRC32 = CRC32((BYTE*)(va_base), sec_len);
return CheckCRC32;
} int main(int argc, char *argv[])
{
// 用于保存初始化时 .text 节中的CRC32值
DWORD OriginalCRC32 = 0; DWORD begin_addr, end_addr, size; // 获取到两个位置的偏移地址
__asm mov begin_addr, offset begin;
__asm mov end_addr, offset end; // 计算出 两者内存差值
size = end_addr - begin_addr; // 校验指定内存位置
OriginalCRC32 = CalculateMemoryCRC32(begin_addr, size); while (1)
{
// 标记为需要保护的区域
begin:
printf("hello lyshark \n");
printf("hello lyshark \n");
printf("hello lyshark \n"); // 保护区域声明结束
end: // 计算并对比
if (OriginalCRC32 == CalculateMemoryCRC32(begin_addr, size))
{
printf("[+] 此区域没有被修改 \n");
}
else
{
printf("[-] 此区域已被修改\n");
} Sleep(3000);
}
system("pause");
return 0;
}

当保护区域内的参数发生变化时则会弹出数据被篡改,如下所示我们通过填充一个nop指令,观察下图,读者能够发现我们的检测生效了;

5.1 内存CRC32完整性检测的更多相关文章

  1. 利用SHELL脚本实现文件完整性检测程序(1.2版更新)

    一..开发背景 因时势所逼,需要对服务器的文件系统实行监控.虽然linux下有不少入侵检测和防窜改系统,但都比较麻烦,用起来也不是很称手.自己琢磨着也不需要什么多复杂的功能,写个脚本应该就可以满足基本 ...

  2. [转载]浅谈C/C++内存泄漏及其检测工具

    http://dev.yesky.com/147/2356147_3.shtml 对于一个c/c++程序员来说,内存泄漏是一个常见的也是令人头疼的问题.已经有许多技术被研究出来以应对这个问题,比如Sm ...

  3. C/C++内存泄漏及检测 转

    C/C++内存泄漏及检测 2011-02-20 17:51 by 吴秦, 30189 阅读, 13 评论, 收藏, 编辑 “该死系统存在内存泄漏问题”,项目中由于各方面因素,总是有人抱怨存在内存泄漏, ...

  4. iOS内存泄漏自动检测工具PLeakSniffer

    新款objective-C内存泄漏自动检测工具 PLeakSniffer , GitHub地址 (https://github.com/music4kid/PLeakSniffer). 背景 前些天读 ...

  5. qt 关于内存泄漏的检测

    Qt 关于内存泄露的检测: 收藏人:guitarhua     2012-02-10 | 阅:  转:    |   来源   |  分享               Qt 关于内存泄露的检测:工具篇 ...

  6. [转]浅谈C/C++内存泄露及其检测工具

    转自:http://www.cnblogs.com/taoxu0903/archive/2007/10/27/939261.html 对于一个c/c++程序员来说,内存泄漏是一个常见的也是令人头疼的问 ...

  7. C++中内存泄漏的检测方法介绍

    C++中内存泄漏的检测方法介绍 首先我们需要知道程序有没有内存泄露,然后定位到底是哪行代码出现内存泄露了,这样才能将其修复. 最简单的方法当然是借助于专业的检测工具,比较有名如BoundsCheck, ...

  8. Android内存泄漏的检测流程、捕捉以及分析

    https://blog.csdn.net/qq_20280683/article/details/77964208 Android内存泄漏的检测流程.捕捉以及分析 简述: 一个APP的性能,重度关乎 ...

  9. 【内存泄漏】 C/C++内存泄漏及其检测工具

    对于一个c/c++程序员来说,内存泄漏是一个常见的也是令人头疼的问题.已经有许多技术被研究出来以应对这个问题,比如 Smart Pointer,Garbage Collection等.Smart Po ...

  10. C/C++内存泄露及检测工具

    内存泄漏的定义   一般我们常说的内存泄漏是指堆内存的泄漏.堆内存是指程序从堆中分配的,大小任意的(内存块的大小可以在程序运行期决定),使用完后必须显示释放的内 存.应用程序一般使用malloc,re ...

随机推荐

  1. 文心一言 VS 讯飞星火 VS chatgpt (180)-- 算法导论13.4 3题

    三.用go语言,在练习13.3-2 中,将关键字 41.38.31.12.19.8 连续插入一棵初始的空树中,从而得到一棵红黑树.请给出从该树中连续删除关键字 8.12.19.31.38.41 后的红 ...

  2. 正确理解c# default关键字

    背景 最近QA测试一个我开发的一个Web API时,我意识到之前对C#的default的理解一直是想当然的.具体情况是这样,这个API在某些条件下要返回模型的默认值,写法类似于下面这样 [HttpGe ...

  3. CO01生产订单屏幕增强

    一.生产订单客户屏幕新增字段 二.生产订单抬头AUFK表的CI_AUFK中新增屏幕字段 三.CMOD 增强分配PPCO0012 修改0100屏幕,新增对应字段,其中生产订单类型设置为下拉框 EXIT_ ...

  4. Python使用pandas库读取csv文件,并分组统计的一个例子

    代码: # coding=gbk # 从HostWrites.csv读取数据并分组统计 import pandas import datetime print "\r\n从 HostWrit ...

  5. 第六届蓝桥杯C++C组 A~F题题解

    蓝桥杯历年国赛真题汇总:Here 1. 分机号 X老板脾气古怪,他们公司的电话分机号都是3位数,老板规定,所有号码必须是降序排列,且不能有重复的数位.比如: 751,520,321 都满足要求,而, ...

  6. freeswitch号码变化方案

    概述 freeswitch是一款简单易用的开源音视频软交换平台. 在生产环境中,由于各个线路的号码规则并不统一,经常需要针对中继线路做号码变换的方案. 本文主要介绍fs中有哪些可选的号码变换方案. 环 ...

  7. 基于AHB_BUS的eFlash控制器设计-软硬件系统设计

    eFlash软硬件系统设计 软硬件划分 划分好软硬件之后,IP暴露给软件的寄存器和时序如何? 文档体系:详细介绍eflash控制器的设计文档 RTL代码编写:详细介绍eflash控制器的RTL代码 1 ...

  8. 07 - HTTP

    HTTP 强烈推荐学习:HTTP | MDN 一 .基础概念 请求和响应报文 客户端发送一个请求报文给服务器,服务器根据请求报文中的信息进行处理,并将处理结果放入响应报文中返回给客户端. 请求报文结构 ...

  9. [转帖]Oracle参数解析(parallel_force_local)

    https://www.modb.pro/db/122032 是否需要增加这个参数? 往期专题请查看www.zhaibibei.cn这是一个坚持Oracle,Python,MySQL原创内容的公众号 ...

  10. [转帖]使用 TiUP cluster 在单机上安装TiDB

    https://zhuanlan.zhihu.com/p/369414808   TiUP 是 TiDB 4.0 版本引入的集群运维工具,TiUP cluster 是 TiUP 提供的使用 Golan ...