首页 > 代码库 > PE Checksum Algorithm的较简实现

PE Checksum Algorithm的较简实现

这篇BLOG是我很早以前写的,因为现在搬移到CNBLOGS了,经过整理后重新发出来。

工作之前的几年一直都在搞计算机安全/病毒相关的东西(纯学习,不作恶),其中PE文件格式是必须知识。有些PE文件,比如驱动,系统会在加载时对checksum进行校验,确保驱动文件的完整性。关于PE文件如何校验,网上有很多资料可以学习,这里有一篇文章《An Analysis of the Windows PE Checksum Algorithm》是对WINDOWS API  CheckSumMappedFile进行逆向分析的。文章的结尾提到WINDOWS的这个校验和算法和IP协议的校验和算法类似,IP的校验和算法实现是RFC1071,如果对其他的校验和算法感兴趣,可以阅读WIKI的《Error Detection and correction》。

但是CheckSumMappedFile的实现略显复杂,不够直观,后来读WRK的代码时,发现了WINDOWS内核在加载驱动时实现的校验和算法要简洁直观很多,分享给大家:

uint32_t calc_checksum(uint32_t checksum, void *data, int length) {    if (length && data != nullptr) {        uint32_t sum = 0;        do {            sum = *(uint16_t *)data + checksum;            checksum = (uint16_t)sum + (sum >> 16);            data = (char *)data + 2;        } while (--length);    }    return checksum + (checksum >> 16);}uint32_t generate_pe_checksum(void *file_base, uint32_t file_size) {    uint32_t file_checksum = 0;    PIMAGE_NT_HEADERS nt_headers = ImageNtHeader(file_base);    if (nt_headers) {        uint32_t header_size = (uintptr_t)nt_headers - (uintptr_t)file_base +            ((uintptr_t)&nt_headers->OptionalHeader.CheckSum -            (uintptr_t)nt_headers);        uint32_t remain_size = (file_size - header_size - 4) >> 1;        void *remain = &nt_headers->OptionalHeader.Subsystem;        uint32_t header_checksum = calc_checksum(0, file_base, header_size >> 1);        file_checksum = calc_checksum(header_checksum, remain, remain_size);        if (file_size & 1){            file_checksum += (uint16_t)*((char *)file_base + file_size - 1);        }    }    return (file_size + file_checksum);}