5.1 内存CRC32完整性检测
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修改为nop则CRC32会提示我们内存已经被打补丁,输出效果如下图所示;

当然上述方法虽然可以对全局进行保护,但如果程序过大则此类验证效率将变得很低,我们需要通过使用打标签的方式对特定内存区域进行保护,如下代码中所示,我们通过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完整性检测的更多相关文章
- 利用SHELL脚本实现文件完整性检测程序(1.2版更新)
一..开发背景 因时势所逼,需要对服务器的文件系统实行监控.虽然linux下有不少入侵检测和防窜改系统,但都比较麻烦,用起来也不是很称手.自己琢磨着也不需要什么多复杂的功能,写个脚本应该就可以满足基本 ...
- [转载]浅谈C/C++内存泄漏及其检测工具
http://dev.yesky.com/147/2356147_3.shtml 对于一个c/c++程序员来说,内存泄漏是一个常见的也是令人头疼的问题.已经有许多技术被研究出来以应对这个问题,比如Sm ...
- C/C++内存泄漏及检测 转
C/C++内存泄漏及检测 2011-02-20 17:51 by 吴秦, 30189 阅读, 13 评论, 收藏, 编辑 “该死系统存在内存泄漏问题”,项目中由于各方面因素,总是有人抱怨存在内存泄漏, ...
- iOS内存泄漏自动检测工具PLeakSniffer
新款objective-C内存泄漏自动检测工具 PLeakSniffer , GitHub地址 (https://github.com/music4kid/PLeakSniffer). 背景 前些天读 ...
- qt 关于内存泄漏的检测
Qt 关于内存泄露的检测: 收藏人:guitarhua 2012-02-10 | 阅: 转: | 来源 | 分享 Qt 关于内存泄露的检测:工具篇 ...
- [转]浅谈C/C++内存泄露及其检测工具
转自:http://www.cnblogs.com/taoxu0903/archive/2007/10/27/939261.html 对于一个c/c++程序员来说,内存泄漏是一个常见的也是令人头疼的问 ...
- C++中内存泄漏的检测方法介绍
C++中内存泄漏的检测方法介绍 首先我们需要知道程序有没有内存泄露,然后定位到底是哪行代码出现内存泄露了,这样才能将其修复. 最简单的方法当然是借助于专业的检测工具,比较有名如BoundsCheck, ...
- Android内存泄漏的检测流程、捕捉以及分析
https://blog.csdn.net/qq_20280683/article/details/77964208 Android内存泄漏的检测流程.捕捉以及分析 简述: 一个APP的性能,重度关乎 ...
- 【内存泄漏】 C/C++内存泄漏及其检测工具
对于一个c/c++程序员来说,内存泄漏是一个常见的也是令人头疼的问题.已经有许多技术被研究出来以应对这个问题,比如 Smart Pointer,Garbage Collection等.Smart Po ...
- C/C++内存泄露及检测工具
内存泄漏的定义 一般我们常说的内存泄漏是指堆内存的泄漏.堆内存是指程序从堆中分配的,大小任意的(内存块的大小可以在程序运行期决定),使用完后必须显示释放的内 存.应用程序一般使用malloc,re ...
随机推荐
- 题解 [HDU6746] Civilization(贪心+模拟)
来源:2020 年百度之星·程序设计大赛 - 初赛一 一道贪心 + 细节模拟题 题意很简单,这里不详细写了 观察题目,\(n\) 只有 500 ,可以 \(n \times n\) 枚举每个位置作为起 ...
- POJ 2726、POJ3074 :数独(二进制DFS)
题目链接:https://ac.nowcoder.com/acm/contest/1014/B 题目描述 In the game of Sudoku, you are given a large 9 ...
- 2016年第七届 蓝桥杯A组 C/C++决赛题解
蓝桥杯历年国赛真题汇总:Here 1.随意组合 小明被绑架到X星球的巫师W那里. 其时,W正在玩弄两组数据 (2 3 5 8) 和 (1 4 6 7) 他命令小明从一组数据中分别取数与另一组中的数配对 ...
- vivo 调用链 Agent 原理及实践
一.项目背景 2017年,vivo互联网研发团队认为调用链系统对实际业务具有较大的价值,于是开始了研发工作.3年的时间,调用链系统整体框架不断演进--本文将介绍vivo调用链系统 Agent 技术原理 ...
- 详解异步任务 | 看 Serverless Task 如何解决任务调度&可观测性中的问题
在上篇文章<解密函数计算异步任务能力之「任务的状态及生命周期管理」>中,我们介绍了任务系统的状态管理,并介绍了用户应如何根据需求,对任务状态信息进行实时的查询等操作.在本篇中我们将会进一步 ...
- <vue 基础知识 2、插值语法> v-once,v-html,v-text,v-pre,v-cloak
代码结构 一. Mustache 1.效果 展示如何将数据展示在页面上 2.代码 01-Mustache.html <!DOCTYPE html> <html lang=&q ...
- 【驱动】I2C驱动分析(二)-驱动框架
I2C驱动框架简介 I2C 驱动属于总线-设备-驱动模型的,与I2C总线设备驱动模型相比,大体框架是一样,系统的整体框架如下所示. 最上层是应用层,在应用层用户可以直接用open read write ...
- S3C2440移植uboot之新建单板_时钟_SDRAM_串口
上一节S3C2440移植uboot之启动过程概述我们我们分析了uboot启动流程,这节将开始新建一块单板支持S3C2440. 目录 1.新建单板 1.1 将2410的单板文件夹拷贝成2440: 1.2 ...
- 真实感渲染:WebGPU介绍和使用光栅化管线绘制一个三角形
大家好~本课程为"真实感渲染"的线上课程,从0开始,介绍相关的图形学算法和数学基础,给出详细的数学推导.伪代码和实现代码,最终带领大家开发出基于物理的渲染器 线上课程资料: 本节课 ...
- C++ list容器
一.前言 list容器,又称为双向链表容器,即该容器的底层是以双向链表的形式实现的,因此list容器中的元素可以分散存储在内存空间里,而不是必须存储在一整块连续的内存空间中. list容器中各个元素的 ...