当前位置: 欣欣网 > 码农

CRC校验完整性

2024-06-04码农

点击上方 蓝字 江湖评谈 设为关注/星标




前言

本篇用作技术性研究,一个简单的算法。

设想一个问题,一个程序如果它没有漏洞如何hook(攻击)它呢?答案很简单,人为制造漏洞。比如常用的指令性的更改(je指令更改为jne等属此类)。但是这样就会造成了程序(exe或者dll)里二进制的不一致性,防范这种hook方法,就是检验程序二进制的完整性,CRC算法就是这种校验的体现。

CRC算法

我们可以把程序进行如下CRC算法Result

DWORD CRC32(BYTE* ptr, DWORD Size){DWORDcrcTable[256], crcTmp1;for(int i = 0; i < 256; i++){crcTmp1 = i;for(int j = 8; j > 0; j--){if(crcTmp1 & 1) crcTmp1 = (crcTmp1 >> 1) ^ 0xEDB88320L;elsecrcTmp1 >>= 1;}crcTable[i] = crcTmp1;}DWORDcrcTmp2 = 0xFFFFFFFF;while(Size--){crcTmp2 = ((crcTmp2 >> 8) & 0x00FFFFFF) ^ crcTable[(crcTmp2 ^ (*ptr)) & 0xFF];ptr++;}return(crcTmp2 ^ 0xFFFFFFFF);}

ptr参数是二进制文件需要crc校验的起始地址,Size则是校验的二进制字节数。如果想要校验一个exe或者DLL的Result数值,那么我们可以如下:

GetOpenFileName(&ofn);hFile = CreateFile( szFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,NULL);fileSize = GetFileSize(hFile, &szTemp);pDosHeader = (PIMAGE_DOS_HEADER)pBuffer;pNtHeader = (PIMAGE_NT_HEADERS64)((DWORD)pDosHeader + pDosHeader->e_lfanew);fileSize = fileSize - DWORD(pDosHeader->e_lfanew);szCRC32 = CRC32((BYTE*)(pBuffer + pDosHeader->e_lfanew), fileSize);DWORD Writeadd = DWORD(pDosHeader->e_lfanew - 4);SetFilePointer(hFile, Writeadd, NULL, FILE_BEGIN);if (!WriteFile(hFile, &szCRC32, 4, &szTemp, NULL)){ CloseHandle(hFile);}

当程序开始运行的时候,我们可以校验ptr到size中间的crc result,进行一个判断:

pBuffer = new TCHAR [fileSize]; ReadFile(hFile,pBuffer, fileSize, &NumberOfBytesRW, NULL);CloseHandle(hFile); pDosHeader=(PIMAGE_DOS_HEADER)pBuffer;pNtHeader=(PIMAGE_NT_HEADERS32)((DWORD)pDosHeader+pDosHeader->e_lfanew); fileSize=fileSize-DWORD(pDosHeader->e_lfanew);if (CRC32((BYTE*)(pBuffer+pDosHeader->e_lfanew),fileSize) == OriginalCRC32 )returnTRUE;elsereturnFALSE;

如果返回false则表示,exe或者dll更改了,此时我们就可以退出程序,不作任何运行,以防止被认为破解。

结尾

以上是校验的过程,主要的原理即把二进制进行计算,然后得出的结果进行保存,运行的时候再次进行计算,比较两次计算结果。代码取自【加密与解密】一书。整体来说,这种保护性较弱,但可以作为一种手段升级下。

往期精彩回顾