gpt4 book ai didi

C++ 使用CRC32检测内存映像完整性的实现步骤

转载 作者:qq735679552 更新时间:2022-09-27 22:32:09 25 4
gpt4 key购买 nike

CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.

这篇CFSDN的博客文章C++ 使用CRC32检测内存映像完整性的实现步骤由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.

仅对.text代码段进行校验:

通常程序中至少包括了代码段,数据段,而数据段中所存储的数据是经常会发生变动的,例如我们的全局变量,静态变量等都会默认存储在数据段,而代码段则不会发生变化,我们在检验时只需要注重.text内存段中的数据完整性即可,针对内存的校验同样可以抵御调试器的CC断点,该断点原理就是在下端处写入int3指令,同样可以检测得到.

C++ 使用CRC32检测内存映像完整性的实现步骤

校验思路如下 1.首先从内存得到PE的代码节的RVA和节大小 2.根据得到的RVA和节大小计算出crc32或是RC4值 3.读取自身保存的原始CRC32值,与校验结果进行比较 。

1.先来实现第一步,读取内存映像的起始地址与大小,我们可以这样做.

#include <stdio.h>#include <windows.h>int main(int argc, char *argv[]){	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;	// 定位到NT头	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 --> 镜像大小: %x \n", va_base, sec_len);	system("pause");	return 0;}

2.第二部就是计算校验和,然后计算该节的CRC32值,并存入全局变量,也就是程序打开后自动初始化计算一次内存crc32值并放入全局变量中,然后开一个线程,每三秒检测一次内存变化,如果变化则终止执行或弹窗提示,你也可以提前计算处校验和并写入PE空缺位置.

#include <stdio.h>#include <windows.h>DWORD CRC32(BYTE* ptr, DWORD Size){	DWORD crcTable[256], crcTmp1;	// 动态生成CRC-32表	for (int i = 0; i<256; i++)	{		crcTmp1 = i;		for (int j = 8; j>0; j--)		{			if (crcTmp1 & 1) crcTmp1 = (crcTmp1 >> 1) ^ 0xEDB88320L;			else crcTmp1 >>= 1;		}		crcTable[i] = crcTmp1;	}	// 计算CRC32值	DWORD crcTmp2 = 0xFFFFFFFF;	while (Size--)	{		crcTmp2 = ((crcTmp2 >> 8) & 0x00FFFFFF) ^ crcTable[(crcTmp2 ^ (*ptr)) & 0xFF];		ptr++;	}	return (crcTmp2 ^ 0xFFFFFFFF);}// 检查内存中CRC32特征值DWORD CheckMemory(){	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 --> 镜像大小: %x \n", va_base, sec_len);	DWORD CheckCRC32 = CRC32((BYTE*)(va_base), sec_len);	// printf(".text节CRC32 = %x \n", CheckCRC32);	return CheckCRC32;}int main(int argc,char *argv[]){	// 用于保存初始化时 .text 节中的CRC32值	DWORD OriginalCRC32 = 0;	// 初始化时,给全局变量赋值,记录下初始的CRC32值	OriginalCRC32 = CheckMemory();	while (1)	{		Sleep(3000);		DWORD NewCRC32 = CheckMemory();		if (OriginalCRC32 == NewCRC32)			printf("程序没有被打补丁. \n");		else			printf("程序被打补丁 \n");	}	system("pause");	return 0;}

C++ 使用CRC32检测内存映像完整性的实现步骤

上方代码是保护了整个程序,在实际应用中,为了提高效率,有时我们只需要保护其中一个片段代码就好,这样可以提高效率,所有我们对上面代码稍作修改即可实现针对特定片段的内存校验.

#include <stdio.h>#include <windows.h>DWORD CRC32(BYTE* ptr, DWORD Size){	DWORD crcTable[256], crcTmp1;	// 动态生成CRC-32表	for (int i = 0; i<256; i++)	{		crcTmp1 = i;		for (int j = 8; j>0; j--)		{			if (crcTmp1 & 1) crcTmp1 = (crcTmp1 >> 1) ^ 0xEDB88320L;			else crcTmp1 >>= 1;		}		crcTable[i] = crcTmp1;	}	// 计算CRC32值	DWORD crcTmp2 = 0xFFFFFFFF;	while (Size--)	{		crcTmp2 = ((crcTmp2 >> 8) & 0x00FFFFFF) ^ crcTable[(crcTmp2 ^ (*ptr)) & 0xFF];		ptr++;	}	return (crcTmp2 ^ 0xFFFFFFFF);}// 检查内存中CRC32特征值DWORD CheckMemory(DWORD va_base, DWORD sec_len){	PIMAGE_DOS_HEADER pDosHeader = NULL;	PIMAGE_NT_HEADERS pNtHeader = NULL;	PIMAGE_SECTION_HEADER pSecHeader = NULL;	DWORD ImageBase;	ImageBase = (DWORD)GetModuleHandle(NULL);	pDosHeader = (PIMAGE_DOS_HEADER)ImageBase;	pNtHeader = (PIMAGE_NT_HEADERS32)((DWORD)pDosHeader + pDosHeader->e_lfanew);	// 以下三条语句可用于确定位置	// pSecHeader = IMAGE_FIRST_SECTION(pNtHeader);	// DWORD va_base1 = ImageBase + pSecHeader->VirtualAddress;   // 定位代码节va基地址	// DWORD sec_len1 = pSecHeader->Misc.VirtualSize;             // 获取代码节长度	// printf("镜像基址(.text): %x --> 镜像大小: %x \n", va_base1, sec_len1);	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 = CheckMemory(begin_addr, size);	while (1)	{	begin: // 标记为需要保护的区域		printf("hello lyshark \n");		printf("hello lyshark \n");		printf("hello lyshark \n");	end:   // 保护区域声明结束		if (OriginalCRC32 == CheckMemory(begin_addr, size))			printf("此区域没有被破解 \n");		else			printf("此区域已被修改\n");		Sleep(3000);	}	system("pause");	return 0;}

C++ 使用CRC32检测内存映像完整性的实现步骤

通过使用磁盘校验结合内存校验两种方式综合保护,可以极大的提高软件的安全性,绕过方式则是找到哪儿跟全局变量将其修正为正确的值即可,同样的也可以更暴力一些直接将判断条件改掉均可.

文章出处:https://www.cnblogs.com/lyshark 。

以上就是C++ 使用CRC32检测内存映像完整性的实现步骤的详细内容,更多关于C++用CRC32检测内存映像完整性的资料请关注我其它相关文章! 。

原文链接:https://www.cnblogs.com/LyShark/p/13657453.html 。

最后此篇关于C++ 使用CRC32检测内存映像完整性的实现步骤的文章就讲到这里了,如果你想了解更多关于C++ 使用CRC32检测内存映像完整性的实现步骤的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com