校验和(Checksum)

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

校验和(Checksum)
校验和(Checksum)
PE的可选映像头(IMAGE_OPTION_HEADER)⾥⾯,有⼀个Checksum字段,是该⽂件的校验和,⼀般EXE⽂件可以使0,但⼀些重要的和系统DLL及驱动⽂件必须有⼀个校验和.
Windows 提供了⼀个API函数MapFileAndCheckSum 测试⽂件的Checksum,它位于IMAGEHLP.DLL链接库⾥,其原型:
ULONG MapFileAndCheckSum
{
LPSTR FileName, // ⽂件名
LPDWORD HeaderSum, // 指向PE⽂件头的CheckSum
LPDWORD new_checksum // 指向新计算出的Checksum
}
程序⼀旦运⾏后,new_checksum 地址处将放当前的⽂件的校验和,old_checksum地址指向PE⽂件的checksum字段
安全的⽅法是将此值放在注册表⾥,需要时⽐较.
内存映像校验
磁盘⽂件完整性校验可以抵抗解密者直接修改⽂件,但对内存补丁却没有效果,必须对内存关键的代码进⾏校验.
1 对整个代码进⾏校验
每个程序⾄少有⼀个代码区块和数据区块,数据区块属性可读写,程序运⾏时全局变量通常会放在这⾥,这些数据会动态变化,因此校验这部分是没什么意义,⽽代码段只读,存放的是程序代码,在程序中数据数不会变的,因此⽤这部分进⾏内存校验是可⾏的.
具体实现⽅法:
(1) 从内存中映像中得到PE相关数据,如代码块的RVA和内存⼤⼩
(2) 根据得到代码区块的RVA值和内存⼤⼩,计算出内存数据的CRC-32值
(3) 读取⾃⾝⽂件先前存储的CRC-32值(PE⽂件头前⼀个字段),这个值是通过软件写进去的.
(4) ⽐较两个CRC-32值.
这样⽐较内存的代码段校验,只要内存的数据被修改,就能发现。

BOOL CodeSectionCRC32()
{
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNTHeader = NULL;
PIMAGE_SECTION_HEADER pSection = NULL;
DWORD ImageBase,OriginalCRC32;
ImageBase = (DWORD)GetModuleHandle(NULL); // 取基址
pDosHeader = (PIMAGE_DOS_HEADER)ImageBase;
pNtHeader = (PIMAGE_NT_HEADER32)((DWORD)pDosHeader + pDosHeader -> e_lfanew);
// 定位到PE⽂件头前4个字节值,并读取存储在这⾥的CRC -32值
OriginalCRC32 = *((DWORD*)(DWORD)pNtHeader - 4);
pSecHeader = IMAGE_FIRST_SECTION(pNtHeader); // 得到第⼀个区块的地址
//假设第⼀个区块就是代码区块
if(OriginalCRC32 == CRC32((BYTE*)ImageBase + pSecHeader -> VirtualAddress)
// 为了⽅便加壳
// 上⼀句也可为if(OriginalCRC32 == CRC32((BYTE *)0x401000, 0x36AE)
return TRUE;
else
return FALSE;
}
2 检验代码⽚段
在实际过程中,有时只需对⼀⼩段代码进⾏内存校验,以防⽌调试⼯具INT3断点
下⾯是⼀段汇编代码
翻译成VC
DWORD address1, address2,size;
_asm Mov address1, offset begindecryt;
_asm Mov address2,offset enddecrypt;
begindecryt : // 标记代码的起始地址
MessageBox(NULL, _T(“Hello World”), _T(“OK”), MB_ICONEXCLAMATION);
enddecrypt: // 标记代码的结束地址
size = address2 – address1;
if(CRC32(BYTE*)address1, size) == 0x78E888AE)
return TRUE;
else
return FALSE;
使 .text 区块可写
在Win32 平台上,⽂件编译后,.text 区块的属性⽯只读的,但是要是写,必须通过PE⼯具修改.text区块的属性为E0000020h 表⽰可写可读可执⾏
void Docrypt(DWORD* pData, DWORD Size, DWRD value)
{
// ⾸先要做的是改变着⼀块虚拟内存的内存保护状态,以便可以⾃由存取代码
MEMORY_BASIC_INFORMATION mbi_thunk;
// 查询页信息
VirtualQuery(pData, &mbi_thunk, sizeof(MEMORY_BASIC_INFORMATION));
// 改写页保护属性为读写
VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize, PAGE_READWRITE, &mbi_thunk.Protect);
size = Size/0x4; // 对数据共需要异或的次数
While(Size --)
{
*pData = (*pData) ^ value;
pData ++;
}
// 恢复也的元保护属性
DWORD dwOldProtect VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize,
mbi_thunk.Protect,
&dwOldProtect);
}。

相关文档
最新文档