如题。 加密与解密第三版的里面可以通过这种方式校验PE文件代码段,但是发现对EXE有效, 对dll不生效。 求解。
写crc校验码:
/*******************************************************
/*《加密与解密(第三版)》配套实例
/* 14.3.3 内存映像校验
/* add2crc32.cpp -- 计算文件的CRC32值
/* code by kanxue
/*(c) 看雪软件安全网站 www.pediy.com 2000-2008
********************************************************/
#include <windows.h>
int patch();
DWORD CRC32(BYTE*,DWORD);
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
patch();
return 0;
}
//////////////////////////////////////////////////////////////////////
int patch()
{
PIMAGE_DOS_HEADER pDosHeader=NULL;
PIMAGE_NT_HEADERS pNtHeader=NULL;
PIMAGE_SECTION_HEADER pSecHeader=NULL;
TCHAR szFileName[MAX_PATH ] ;
DWORD szTemp;
static OPENFILENAME ofn ;
HANDLE hFile;
long FileSize;
DWORD szCRC32;
TCHAR *pBuffer ;
ZeroMemory(&ofn, sizeof(ofn)); // 初始化OPENFILENAME结构
static TCHAR szFilter[] =TEXT ("EXE Files (*.exe)\0*.exe\0") \
TEXT ("All Files (*.*)\0*.*\0\0") ;
szFileName[0] = '\0';
ZeroMemory(&ofn, sizeof(ofn)); // 初始化OPENFILENAME结构
ofn.lStructSize = sizeof (OPENFILENAME) ;
ofn.lpstrFilter = szFilter ;
ofn.lpstrFile = szFileName ;
ofn.nMaxFile = MAX_PATH ;
ofn.nMaxFileTitle = MAX_PATH ;
ofn.Flags = OFN_HIDEREADONLY | OFN_CREATEPROMPT ;
if(GetOpenFileName (&ofn))
{
hFile = CreateFile(
szFileName,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if( hFile != INVALID_HANDLE_VALUE )
{
FileSize=GetFileSize(hFile,&szTemp); // 获取文件大小
if (FileSize == 0xFFFFFFFF) return FALSE;
pBuffer = new TCHAR [FileSize]; // 申请内存
if(ReadFile(hFile, pBuffer, FileSize, &szTemp, NULL)==NULL) return FALSE;// 读取数据
}
else
{
MessageBox(NULL,"I can't access file!","CRC error",MB_ICONEXCLAMATION);
return 0;
}
}
else
return 0;
pDosHeader=(PIMAGE_DOS_HEADER)pBuffer;
pNtHeader=(PIMAGE_NT_HEADERS32)((DWORD)pDosHeader+pDosHead-z>e_lfanew);
pSecHeader=IMAGE_FIRST_SECTION(pNtHeader); //得到第一个区块的起始地址
IMAGE_FILE_HEADER* pFileHeader = &pNtHeader->FileHeader;
for (int i = 0; i < pFileHeader->NumberOfSections;i++)
{
if((strcmp((char*)pSecHeader->Name,".text") == 0))
{
break;
}
pSecHeader++;
}
szCRC32=CRC32((BYTE*)(pBuffer+pSecHead-z>PointerToRawData),pSecHeader->Misc.VirtualSize);
DWORD Writeadd=DWORD(pDosHeader->e_lfanew-4);//定位到PE文件头(即字串“PE\0\0”处)前4个字节处,准备在这写CRC-32值:
SetFilePointer(hFile,Writeadd,NULL,FILE_BEGIN);//设置文件指针
if(!WriteFile(hFile,&szCRC32,4,&szTemp,NULL))
{
MessageBox(NULL,"Error while patching !","Patch aborted",MB_ICONEXCLAMATION);
CloseHandle(hFile);
return 0;
}
delete pBuffer; // 释放内存
CloseHandle(hFile);
MessageBox(NULL,"Patch successfull !","Patch",MB_ICONINFORMATION);
return 1;
}
////////////////////////////////////////////////////////////////
// 计算字符串的CRC32值
// 参数:欲计算CRC32值字符串的首地址和大小
// 返回值: 返回CRC32值
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);
}
获取映像文件crc码,然后进行校验
/*******************************************************
/*《加密与解密(第三版)》配套实例
/* 14.3.3 内存映像校验
/* memcrc32.cpp -- 内存映像校验,仅校验代码区块
/* code by kanxue
/*(c) 看雪软件安全网站 www.pediy.com 2000-2008
********************************************************/
#include <windows.h>
DWORD CRC32(BYTE*,DWORD);
BOOL CodeSectionCRC32( );
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
HMODULE hmodule = LoadLibraryA("Test.dll");
if(CodeSectionCRC32())
MessageBox(NULL,TEXT ("CRC32 Check OK!"),TEXT ("OK"),MB_ICONEXCLAMATION);
else
MessageBox(NULL,"File corrupted! !","CRC error",MB_ICONEXCLAMATION);
return 0;
}
////////////////////////////////////////////////////////////////
// 计算代码区块的CRC32值
//
BOOL CodeSectionCRC32( )
{
PIMAGE_DOS_HEADER pDosHeader=NULL;
PIMAGE_NT_HEADERS pNtHeader=NULL;
PIMAGE_SECTION_HEADER pSecHeader=NULL;
DWORD ImageBase,OriginalCRC32;
ImageBase=(DWORD)GetModuleHandle("Test.dll");//取基址,其实本例也可直接用0x4000000这个值
//ImageBase=(DWORD)GetModuleHandle(NULL);//取基址,其实本例也可直接用0x4000000这个值
pDosHeader=(PIMAGE_DOS_HEADER)ImageBase;
pNtHeader=(PIMAGE_NT_HEADERS32)((DWORD)pDosHeader+pDosHead-z>e_lfanew);
//定位到PE文件头(即字串“PE\0\0”处)前4个字节处,并读出储存在这里的CRC-32值:
OriginalCRC32 =*((DWORD *)((DWORD)pNtHeader-4));
pSecHeader=IMAGE_FIRST_SECTION(pNtHeader); //得到第一个区块的起始地址
IMAGE_FILE_HEADER* pFileHeader = &pNtHeader->FileHeader;
for (int i = 0; i < pFileHeader->NumberOfSections;i++)
{
if((strcmp((char*)pSecHeader->Name,".text") == 0))
{
break;
}
pSecHeader++;
}
//假设第一个区块就是代码区块
//是从磁盘文件得到代码块的地址和大小来计算CRC32值
if(OriginalCRC32==CRC32((BYTE*) (ImageBase+pSecHead-z>VirtualAddress),pSecHeader->Misc.VirtualSize))
return TRUE;
else
return FALSE;
//如果程序从磁盘文件获取第一区块的数据,加壳后,数据将可能不准确,因此对于要加壳的程序来说,
//直接填上代码区块的地址和大小,方法是先随便填一数据,编译后用PE工具查看生成文件的代码区块的RVA和大小,
//再填进来重新编译
/*
if(OriginalCRC32==CRC32((BYTE*) 0x401000,0x36AE))
return TRUE;
else
return FALSE;
*/
}
////////////////////////////////////////////////////////////////
// 计算字符串的CRC32值
// 参数:欲计算CRC32值字符串的首地址和大小
// 返回值: 返回CRC32值
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);
}
exe一样, dll不一样, 但是二者不都是pe文件吗? 难道还有隐藏的规则吗?
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)