CRC校验技术是用于检测数据传输或存储过程中是否出现了错误的一种方法,校验算法可以通过计算应用与数据的循环冗余校验(CRC)检验值来检测任何数据损坏。通过运用本校验技术我们可以实现对特定内存区域以及磁盘文件进行完整性检测,并以此来判定特定程序内存是否发生了变化,如果发生变化则拒绝执行,通过此种方法来保护内存或磁盘文件不会被非法篡改。总之,内存和磁盘中的校验技术都是用于确保数据和程序的完整性和安全性的重要技术。
磁盘CRC(循环冗余校验)用于检测磁盘数据的完整性,一般而言某些木马专杀工具同样会用到磁盘CRC特征校验技术,该技术的实现原理与内存验证原理完全一致,针对磁盘的验证同样很简单,但此处我们需要将计算到的CRC32
值存储到PE文件自身中,通常我们可以存储到PE文件的前一个DWORD
的位置上,程序运行后对比这个值,来判断程序是否被打过补丁,如果打过直接结束掉。
BOOL CalculateDiskCRC32() { char szFileName[MAX_PATH] = { 0 };
char *pBuffer; DWORD pNumberOfBytesRead; int FileSize = 0;
GetModuleFileName(0, szFileName, MAX_PATH); HANDLE hFile = CreateFile(szFileName, GENERIC_READ, 1, 0, 3, FILE_ATTRIBUTE_NORMAL, 0); if (hFile == INVALID_HANDLE_VALUE) { return TRUE; }
FileSize = GetFileSize(hFile, 0); pBuffer = new char[FileSize];
ReadFile(hFile, pBuffer, FileSize, &pNumberOfBytesRead, 0); CloseHandle(hFile);
PIMAGE_DOS_HEADER pDosHeader = NULL; PIMAGE_NT_HEADERS32 pNtHeader = NULL;
pDosHeader = (PIMAGE_DOS_HEADER)pBuffer;
pNtHeader = (PIMAGE_NT_HEADERS32)((DWORD)pDosHeader + pDosHeader->e_lfanew);
DWORD OriginalCRC32 = *(DWORD *)((DWORD)pNtHeader - 4); printf("[*] 读出节表值 = %x \n", OriginalCRC32);
FileSize = FileSize - DWORD(pDosHeader->e_lfanew); DWORD CheckCRC32 = CRC32((BYTE*)(pBuffer + pDosHeader->e_lfanew), FileSize); printf("[+] 计算CRC32 = %x \n", CheckCRC32);
if (CheckCRC32 == OriginalCRC32) { return FALSE; } else { return TRUE; } return TRUE; }
int main(int argc, char* argv[]) { BOOL ref = CalculateDiskCRC32(); if (ref == TRUE) { printf("[-] 程序已被修改 \n"); } else { printf("[+] 程序正常 \n"); }
system("pause"); return 0; }
|
首先读者运行上述程序,则程序会输出当前的CRC32值be63ac8b
我们记下这个HASH值,如下图所示;
并将此值替换到如下图中的黄色位置,当程序运行后会读取该区域内的数据,并与动态计算的CRC32值进行计算,最终判断是否被修改,如下图所示;
通过CRC32数据对比并遍历磁盘文件,我们可以实现一个简单的特征定位查杀程序,用于专门定位某些特殊的程序,如下是修改后的代码片段;
BOOL CalcCRC32(char *FilePath) { HANDLE hFile = CreateFile(FilePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { return FALSE; }
DWORD dwSize = GetFileSize(hFile, NULL); if (dwSize == 0xFFFFFFFF) { return FALSE; }
BYTE *pFile = (BYTE*)malloc(dwSize); if (pFile == NULL) { return FALSE; }
DWORD dwNum = 0; ReadFile(hFile, pFile, dwSize, &dwNum, NULL);
DWORD dwCRC32 = CRC32(pFile, dwSize); if (pFile != NULL) { free(pFile); pFile = NULL; }
CloseHandle(hFile); return dwCRC32; }
int main(int argc, char* argv[]) { WIN32_FIND_DATA stFindFile; HANDLE hFindFile; char *szFilter = "*.exe"; char szFindFile[MAX_PATH]; char szSearch[MAX_PATH]; int ret = 0;
lstrcpy(szFindFile, "D:\\"); lstrcpy(szSearch, "D:\\"); lstrcat(szSearch, szFilter); DWORD dwTmpCRC32;
hFindFile = FindFirstFile(szSearch, &stFindFile); if (hFindFile != INVALID_HANDLE_VALUE) { do { lstrcat(szFindFile, stFindFile.cFileName); dwTmpCRC32 = CalcCRC32(szFindFile);
if (dwTmpCRC32 == 0xbe63ac8b) { printf("[*] CRC32 = %x 发现病毒 %s \n", dwTmpCRC32, szFindFile); } else { printf("[-] CRC32 = %x 正常程序 %s \n", dwTmpCRC32, szFindFile); } szFindFile[3] = '\0'; ret = FindNextFile(hFindFile, &stFindFile); } while (ret != 0); }
FindClose(hFindFile);
system("pause"); return 0; }
|
运行程序输出效果如下图所示;