PE CheckSum algorithm
<< Back
If you ever want to calculate the CheckSum field for a Portable Executable, you can use
the Win32 API
CheckSumMappedFile
or
MapFileAndCheckSum
from ImageHlp.dll, or you can calculate it yourself.
DWORD ShowCheckSum(LPCTSTR lpszFile, IMAGE_DOS_HEADER* dosHeader, DWORD dwFileSize)
{
PIMAGE_NT_HEADERS32 pNTHeader;
pNTHeader = (PIMAGE_NT_HEADERS32)MakePtr(dosHeader, dosHeader->e_lfanew);
WORD* pCheckSum1 = (WORD*)&pNTHeader->OptionalHeader.CheckSum;
DWORD dwCheckSum = 0;
WORD* pFile = (WORD*)dosHeader;
DWORD dwCount = dwFileSize;
while (dwCount)
{
if (pFile == pCheckSum1)
{
pFile += 2;
dwCount -= 4;
continue;
}
if (dwCount == 1)
{
dwCheckSum += *((PBYTE)pFile);
dwCount = 0;
}
else
{
dwCheckSum += *pFile;
dwCount -= 2;
pFile++;
}
if (dwCheckSum > 0xffff)
dwCheckSum = (dwCheckSum & 0xffff) + (dwCheckSum >> 16);
}
dwCheckSum += dwFileSize;
return dwCheckSum;
}
While the structure IMAGE_NT_HEADERS32 is different than the structure IMAGE_NT_HEADERS64, the relative memory locations of the CheckSum field are the same in both structures.
- Map the entire PE into memory. The starting memory location is also the start of IMAGE_DOS_HEADER
- Process 2 bytes (as in a WORD) at a time. Sum all the WORD (excluding the CheckSum field) into a DWORD
- If the file size happens to be an odd number (which I have never seen one), then just add the last BYTE to the DWORD
- After each sum, if the DWORD exceeds the max size of the WORD (which is 0xffff), then we take the lower 16 bits of the DWORD and add 1 to it
- At the end, add the file size to the DWORD