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. NOKOV度量光学动作捕捉系统工作流程

    如果你对影视.动画或者游戏有一定关注,相信你一定听说过"动作捕捉".事实上,无论是屏幕中的战场,还是真实的军事领域,从2K游戏中的虚拟球员,到医疗.康复.运动领域的专业研究:从机器 ...

  2. 【JAVA基础】JAVA基础知识整理

    https://www.weixueyuan.net/java/rumen_1/ JAVA的三大版本 JDK.JRE.JVM JAVA安装与卸载 JDK结构 HelloWorld运行 编译型与解释型 ...

  3. Educational Codeforces Round 82 (Rated for Div. 2) A. Erasing Zeroes(超简单的写法)

    题意: 统计间隔在1中0的个数 思路: 超简单写法,直接利用string的find.rfind函数即可 #include<bits/stdc++.h> using namespace st ...

  4. 【每日一题】6.Rinne Loves Edges (树形DP)

    题目链接:Here 树形DP 算法讲解:Here 无向联通图其实就是树的形状,其次让我们以 s 为根使得所有的叶子节点不能到达根并且让删去边权的总和最小,那么就是典型的 树形DP 了. \(dp_i\ ...

  5. vue+spingboot 实现服务器端文件下载功能

    vue3 和springboot配合如何实现服务器端文件的下载. 先看springboot的后台代码: @PostMapping("/download") @ResponseBod ...

  6. Python实现PowerPoint(PPT/PPTX)到PDF的批量转换

    如果需要处理大量的PPT转PDF的工作,一个个打开并另存为PDF是非常费时的做法.我们可以利用Python编程语言的强大的工具来自动化这个过程,使得批量转换变得简单而高效.本文将介绍如何使用Pytho ...

  7. Java之利用openCsv导出csv文件

    当时导入的时候用的openCsv,那么导出的时候自然也是用这个,查了好多资料才找到解决方案,下面记录一下实现过程. 1.Controller层: /** * 导出csv文件 */ @RequestMa ...

  8. Linux 中常用的基础命令

    by emanjusaka from https://www.emanjusaka.top/2024/01/linux-base-command 彼岸花开可奈何 本文欢迎分享与聚合,全文转载请留下原文 ...

  9. Oracle Rac 的简单学习

    Oracle Rac 的简单学习 Oracle RAC的概念 Oracle RAC (Real Application Clusters) 是 Oracle 数据库管理系统的一个功能, 它允许将数据库 ...

  10. [转帖]浅析TiDB二阶段提交

    https://cloud.tencent.com/developer/article/1608073 关键内容说明: TiDB 对于每个事务,会涉及改动的所有key中,选择出一个作为当前事务的Pri ...