ViaThinkSoft CodeLib
This article is in:
CodeLib → Programming aids → C / C++
//DOS .EXE header
struct image_dos_header
{
uint16_t e_magic; // Magic number
uint16_t e_cblp; // Bytes on last page of file
uint16_t e_cp; // Pages in file
uint16_t e_crlc; // Relocations
uint16_t e_cparhdr; // Size of header in paragraphs
uint16_t e_minalloc; // Minimum extra paragraphs needed
uint16_t e_maxalloc; // Maximum extra paragraphs needed
uint16_t e_ss; // Initial (relative) SS value
uint16_t e_sp; // Initial SP value
uint16_t e_csum; // Checksum
uint16_t e_ip; // Initial IP value
uint16_t e_cs; // Initial (relative) CS value
uint16_t e_lfarlc; // File address of relocation table
uint16_t e_ovno; // Overlay number
uint16_t e_res[4]; // Reserved words
uint16_t e_oemid; // OEM identifier (for e_oeminfo)
uint16_t e_oeminfo; // OEM information; e_oemid specific
uint16_t e_res2[10]; // Reserved words
int32_t e_lfanew; // File address of new exe header
};
struct image_file_header
{
uint16_t Machine;
uint16_t NumberOfSections;
uint32_t TimeDateStamp;
uint32_t PointerToSymbolTable;
uint32_t NumberOfSymbols;
uint16_t SizeOfOptionalHeader;
uint16_t Characteristics;
};
#define _CRT_SECURE_NO_WARNINGS
uint32_t calculate_checksum(const char* filename) {
//Calculate checksum of image
// Taken from "PE Bliss" Cross-Platform Portable Executable C++ Library
// https://github.com/mrexodia/portable-executable-library/blob/master/pe_lib/pe_checksum.cpp
// Converted from C++ to C by Daniel Marschall
FILE* fptr = fopen(filename, "rb");
if (fptr == NULL) return 0x00000000;
//Checksum value
unsigned long long checksum = 0;
struct image_dos_header header;
//Read DOS header
fseek(fptr, 0, SEEK_SET);
fread(&header, sizeof(struct image_dos_header), 1, fptr);
//Calculate PE checksum
fseek(fptr, 0, SEEK_SET);
unsigned long long top = 0xFFFFFFFF;
top++;
//"CheckSum" field position in optional PE headers - it's always 64 for PE and PE+
static const unsigned long checksum_pos_in_optional_headers = 64;
//Calculate real PE headers "CheckSum" field position
//Sum is safe here
unsigned long pe_checksum_pos = header.e_lfanew + sizeof(struct image_file_header) + sizeof(uint32_t) + checksum_pos_in_optional_headers;
//Calculate checksum for each byte of file
fseek(fptr, 0L, SEEK_END);
size_t filesize = ftell(fptr);
fseek(fptr, 0L, SEEK_SET);
for (size_t i = 0; i < filesize; i += 4)
{
unsigned long dw = 0;
//Read DWORD from file
fread(&dw, sizeof(dw), 1, fptr);
//Skip "CheckSum" DWORD
if (i == pe_checksum_pos)
continue;
//Calculate checksum
checksum = (checksum & 0xffffffff) + dw + (checksum >> 32);
if (checksum > top)
checksum = (checksum & 0xffffffff) + (checksum >> 32);
}
//Finish checksum
checksum = (checksum & 0xffff) + (checksum >> 16);
checksum = (checksum)+(checksum >> 16);
checksum = checksum & 0xffff;
checksum += (unsigned long)(filesize);
fclose(fptr);
//Return checksum
return (uint32_t)checksum;
}
bool repair_pe_checksum(const char* filename) {
size_t peoffset;
FILE* fptr;
uint32_t checksum = calculate_checksum(filename);
//if (checksum == 0x00000000) return false;
fptr = fopen(filename, "rb+");
if (fptr == NULL) return false;
fseek(fptr, 0x3C, SEEK_SET);
fread(&peoffset, sizeof(peoffset), 1, fptr);
fseek(fptr, (long)peoffset + 88, SEEK_SET);
fwrite(&checksum, sizeof(uint32_t), 1, fptr);
fclose(fptr);
return true;
}
Daniel Marschall
ViaThinkSoft Co-Founder
ViaThinkSoft Co-Founder