PE结构网上到处都是,关于其中的扩展头(也叫可选头),其中有个成员CheckSum(相对于本结构的 40h偏移处,是结构的第22个成员),按描述说是PE的校验和,一般不使用,对于所有驱动、系统启动时加载的DLL、系统关键进程加载的DLL都要进行校验和的校验;
这个校验和可以通过API计算:CheckSumMappedFile 或者直接 MapFileAndCheckSum;
但是不少资料和书籍也说了其算法比较简单,自己手动写代码计算也可以,描述的计算原理一般是这样:
1、因为要计算整个文件数据嘛,所以开始这个字段的数据要先置0;
2、从文件头开始,每次读一个字(WORD),进行带进位的累加(ADC),超出WORD部分自动溢出;
3、将前面的累加和再加上PE文件的长度,结果就是这个校验和了。
(以上资料基本摘自戚利《Windows PE 权威指南》,在网上其他资料与其描述也基本相同);
比如这个连接的算法,在网上就随处可见,大部分都是这么算的:
http://sec.chinabyte.com/497/8918497.shtml
我简单写一下刚开始我按照上述资料写的代码:
;首先假设我已经把PE文件映射的起始地址放入ebx了!
mov ecx, _dwSize ;PE文件大小
shr ecx, 01h ;因为每次读2字节,所以循环次数是长度的一半。部分资料为了处理奇数在这里要+1再右移或其他方法,但本帖我就找偶数长度PE测试也是不对的,所以这里就不写那些兼容处理部分了;
xor edx, edx
xor eax, eax
clc
@@:
mov ax, word ptr [ebx]
adc dx, ax
add ebx, 02h
loop @B
mov eax, edx
add eax, _dwSize ;这样就算是计算完毕了。
但是我测试,这个算法根本不对(跟API计算的结果对比的话),差距很大的哦;
后来在CSDN里找到这个:
http://bbs.csdn.net/topics/20067469#post-12158577
我按照这位前辈的写法修改了上面:
;首先假设我已经把PE文件映射的起始地址放入ebx了!
mov ecx, _dwSize
shr ecx, 01h
xor edx, edx
clc
@@:
;------------------------------------
movzx eax, word ptr [ebx]
add ebx, eax
mov eax, edx
and edx, 0ffffh
shr eax, 10h
add edx, eax
;------------------------------------
add ebx, 02h
loop @B
mov eax, edx
add eax, _dwSize
我测试这样算出来的跟API比才是对的,但是我发帖子就想问问,这到底是个啥原理啊?
好多的教程、书籍都是些挺有名的前辈高人所写,不可能他们说错吧(这里的错1是:带进位加法,而第二段代码根本没有adc;2是word超出部分自动溢出,但第二段代码没有让其溢出,这里我有点看太懂,好像是把高16位和低16位相加了吧?)
谁能给解释解释?莫非这个算法微软后来又更新了?还有第二段代码的原理是什么,我标记出来有改动的部分,那些虽然指令简单,但逻辑上我不太理解。。。
多谢您指教了!
------解决思路----------------------
第二个代码:
9 add ebx, eax
这应该是add edx,eax吧。
你的代码:
adc dx, ax
应该是
add dx, ax
adc dx,0
这样才合理。
------解决思路----------------------
非也,按你的指令顺序,后面的add ebx, 02h把上一次adc dx, ax可能产生的进位清掉了,下一次也加不上。
另外,我测试了一下,按我的改法算出来的checksun和第二种方法算出来的是一致的。