本文主要是介绍openssl3.2 - exp - calc PE file checksum and SHA3-512,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
openssl3.2 - exp - calc PE file checksum and SHA3-512
概述
想在程序中, 对自身的PE内容算校验和和HASH, 然后送给服务端判断PE文件是否被修改了.
前几天, 看了一个资料, 里面有算PE校验和的实现. 迁移到自己工程.
但是没有算HASH, 正好已经将openssl官方demo过了一遍, 有个官方demo正好是对buffer算hash(openssl3.2 - 官方demo学习 - encode - rsa_encode.c), 也迁移到自己工程.
程序中释放openssl资源时, 开始判断条件写错了. 如下:
if (NULL == _ossl_lib_ctx){OSSL_LIB_CTX_free(_ossl_lib_ctx);_ossl_lib_ctx = NULL;}
导致有内存泄漏.
但是我前几天做了openssl3.2检测内存泄漏的实验(openssl3.2 - crypto-mdebug被弃用后, 内存泄漏检查的替代方法), 非常好使.
现在我的工程模板中都加入了内存检测的实现, 程序跑完, 退出时, 如果有内存泄漏, 直接断言, 然后用代码块注释法, 可以很快的定位修复内存泄漏问题.
void* my_CRYPTO_malloc(size_t num, const char* file, int line)
{void* p = NULL;It_mem_hook it;CMemHookRec* rec = NULL;p = malloc(num);if (NULL != p){it = g_mem_hook_map.find((uint64_t)p);if (it != g_mem_hook_map.end()) {// printf("find key\n");assert(false);}else {// printf("not find key\n");rec = new CMemHookRec();if (NULL != rec){rec->rec_sn = ++g_u64_malloc_cnt_all;// 观察UI上显示的内存分配记录的序号, 然后在具体序号上下断点, 然后跟进库里面, 再跟出到自己的应用代码处, 就基本知道是啥没释放:) if (2232 == rec->rec_sn){rec->rec_sn = rec->rec_sn; // 如果哪里泄漏了, 可以单步到openssl库代码中// 如果是自己没调用释放函数, 用代码块的注释排除法, 很快能确定问题.}
俺居然预判了可能会发生内存泄漏时如何检测的场景, 提前将检测措施搞定了. 真机智啊:P
笔记
main.cpp
/*!
* \file main.cpp
* \note openssl3.2 - exp - calc PE file checksum and SHA3-512
*/#include "my_openSSL_lib.h"
#include <openssl/crypto.h>
#include <openssl/bio.h>#include <stdlib.h>
#include <stdio.h>
#include <assert.h>#include "CMemHookRec.h"#include <imagehlp.h>
#pragma comment(lib, "imagehlp.lib")#include "CPeFileCheck.h"void my_openssl_app();const char* psz_argv0 = NULL;int main(int argc, char** argv)
{psz_argv0 = argv[0];setvbuf(stdout, NULL, _IONBF, 0); // 清掉stdout缓存, 防止调用printf时阻塞mem_hook();my_openssl_app();mem_unhook();return 0;/*! run resultPE calc okPE checksum old = 0x0PE checksum calc = 0x23776SHA3 512 len = 64SHA3 512 data below:0C F4 16 D4 4E 2A 9B 206A 9C B4 22 4F A8 3D 1925 D8 6E 7F 7C 45 20 6B70 78 77 4B FF A6 94 B5D1 EE 16 EB 6D 0A B3 9719 0B 1D 7D EE 63 0A D61D 01 F9 02 1D 93 2C 91F5 00 39 CC 82 9D 65 92ENDfree map, g_mem_hook_map.size() = 0*/
}void my_openssl_app()
{CPeFileCheck* pe = NULL;DWORD dwPeCheckSum = 0;bool b_rc = false;DWORD dwPeCheckSumOrg = 0;DWORD dwPeCheckSumCalc = 0;uint8_t* pHash = NULL;int HashLen = 0;int i = 0;int col_cnt = 0;do {pe = new CPeFileCheck();if (NULL == pe){break;}// 必须是全路径名称b_rc = pe->PE_calc(psz_argv0);if (!b_rc){printf("error\n");}else {printf("PE calc ok\n");if (pe->get_PE_checkSum(dwPeCheckSumOrg, dwPeCheckSumCalc)){printf("PE checksum old = 0x%X\n", dwPeCheckSumOrg);printf("PE checksum calc = 0x%X\n", dwPeCheckSumCalc);}if (pe->get_PE_Hash_SHA3_512(&pHash, HashLen)){printf("SHA3 512 len = %d\n", HashLen);printf("SHA3 512 data below:\n");for (i = 0; i < HashLen; i++){printf("%2.2X", pHash[i]);if (8 == ++col_cnt){col_cnt = 0;printf("\n");}else {printf(" ");}}}}} while (false);if (NULL != pe){delete pe;pe = NULL;}printf("\nEND\n");
}
CPeFileCheck.h
/*!
\file CPeFileCheck.h
*/#ifndef __CPEFILECHECK_H__
#define __CPEFILECHECK_H__#include "my_openSSL_lib.h"
#include <cstdint>#ifndef BYTE_ORDER
#define LITTLE_ENDIAN 1234
#define BIG_ENDIAN 4321
#define BYTE_ORDER LITTLE_ENDIAN
#endif /* BYTE_ORDER */#if BYTE_ORDER == BIG_ENDIAN
#define LE_UINT16(x) ((((x) >> 8) & 0x00FF) | \(((x) << 8) & 0xFF00))
#define LE_UINT32(x) (((x) >> 24) | \(((x) & 0x00FF0000) >> 8) | \(((x) & 0x0000FF00) << 8) | \((x) << 24))
#else
#define LE_UINT16(x) (x)
#define LE_UINT32(x) (x)
#endif /* BYTE_ORDER == BIG_ENDIAN */#define SIZE_64K 65536 /* 2^16 */
#define SIZE_16M 16777216 /* 2^24 */#define GET_UINT8_LE(p) ((const u_char *)(p))[0]#define GET_UINT16_LE(p) (uint16_t)(((const u_char *)(p))[0] | \(((const u_char *)(p))[1] << 8))#define GET_UINT32_LE(p) (uint32_t)(((const u_char *)(p))[0] | \(((const u_char *)(p))[1] << 8) | \(((const u_char *)(p))[2] << 16) | \(((const u_char *)(p))[3] << 24))#define PUT_UINT8_LE(i, p) ((u_char *)(p))[0] = (u_char)((i) & 0xff);#define PUT_UINT16_LE(i,p) ((u_char *)(p))[0] = (u_char)((i) & 0xff); \((u_char *)(p))[1] = (u_char)(((i) >> 8) & 0xff)#define PUT_UINT32_LE(i,p) ((u_char *)(p))[0] = (u_char)((i) & 0xff); \((u_char *)(p))[1] = (u_char)(((i) >> 8) & 0xff); \((u_char *)(p))[2] = (u_char)(((i) >> 16) & 0xff); \((u_char *)(p))[3] = (u_char)(((i) >> 24) & 0xff)class CPeFileCheck
{
public:CPeFileCheck();virtual ~CPeFileCheck();public:bool PE_calc(const char* pszFilePathName);bool get_PE_checkSum(DWORD& dwPECheckSumOrg, DWORD& dwPECheckSumCalc);bool get_PE_Hash_SHA3_512(uint8_t** ppdata, int& len);private:uint32_t get_file_size(const char* infile);uint8_t* map_file(const char* infile, const size_t size);void unmap_file(uint8_t* indata);bool is_PE_format_ok();bool calc_PE_checksum(DWORD& dwPeCheckSumCalc);bool calc_hash_SHA3_512();private:uint32_t m_u32_file_size;uint8_t* m_pu8_map_file;DWORD m_dwPeCheckSumOrg;DWORD m_dwPeCheckSumCalc;uint32_t m_header_size;uint32_t m_pe32plus;uint32_t m_magic;uint32_t m_nrvas;uint32_t m_sigpos;uint32_t m_siglen;unsigned int m_digest_length;uint8_t m_ary_digest_value[1024];bool m_b_calc_ok;
};#endif // #ifndef __CPEFILECHECK_H__
CPeFileCheck.cpp
//! \file CPeFileCheck.cpp#include "CPeFileCheck.h"
#include <sys/stat.h>#include "my_openSSL_lib.h"
#include <openssl/crypto.h>
#include <openssl/bio.h>#include <openssl/err.h>
#include <openssl/evp.h>
#include <cassert>CPeFileCheck::CPeFileCheck()
{m_u32_file_size = 0;m_pu8_map_file = NULL;m_dwPeCheckSumOrg = 0;m_dwPeCheckSumCalc = 0;m_header_size = 0;m_pe32plus = 0;m_magic = 0;m_nrvas = 0;m_sigpos = 0;m_siglen = 0;m_digest_length = 0;memset(m_ary_digest_value, 0, sizeof(m_ary_digest_value));m_b_calc_ok = false;
}CPeFileCheck::~CPeFileCheck()
{unmap_file(this->m_pu8_map_file);
}bool CPeFileCheck::get_PE_checkSum(DWORD& dwPECheckSumOrg, DWORD& dwPECheckSumCalc)
{dwPECheckSumOrg = this->m_dwPeCheckSumOrg;dwPECheckSumCalc = this->m_dwPeCheckSumCalc;return m_b_calc_ok;
}bool CPeFileCheck::get_PE_Hash_SHA3_512(uint8_t** ppdata, int& len)
{bool b_rc = false;do {if (NULL == ppdata){break;}*ppdata = this->m_ary_digest_value;len = this->m_digest_length;b_rc = m_b_calc_ok;} while (false);return b_rc;
}bool CPeFileCheck::PE_calc(const char* pszFilePathName)
{bool b_rc = false;do {if (NULL == pszFilePathName){break;}m_b_calc_ok = false;if (NULL != m_pu8_map_file){unmap_file(m_pu8_map_file);}m_u32_file_size = get_file_size(pszFilePathName);m_pu8_map_file = map_file(pszFilePathName, m_u32_file_size);if (NULL == m_pu8_map_file){break;}if (!is_PE_format_ok()){break;}if (!calc_PE_checksum(m_dwPeCheckSumCalc)){break;}if (!calc_hash_SHA3_512()){break;}m_b_calc_ok = true;b_rc = true;} while (false);return b_rc;
}bool CPeFileCheck::calc_hash_SHA3_512()
{//! \ref https://blog.csdn.net/LostSpeed/article/details/135581192bool b_rc = false;OSSL_LIB_CTX* _ossl_lib_ctx;int ret = 0;const char* _psz_option_properties = NULL;EVP_MD* _evp_md = NULL;EVP_MD_CTX* _evp_md_ctx = NULL;unsigned int digest_length;uint8_t* _p_digest_value = NULL;do {_ossl_lib_ctx = OSSL_LIB_CTX_new();if (NULL == _ossl_lib_ctx) {// fprintf(stderr, "OSSL_LIB_CTX_new() returned NULL\n");break;}/** Fetch a message digest by name* The algorithm name is case insensitive.* See providers(7) for details about algorithm fetching*/_evp_md = EVP_MD_fetch(_ossl_lib_ctx,"SHA3-512", _psz_option_properties);if (NULL == _evp_md) {// fprintf(stderr, "EVP_MD_fetch could not find SHA3-512.");break;}/* Determine the length of the fetched digest type */digest_length = EVP_MD_get_size(_evp_md);if (digest_length <= 0) {// fprintf(stderr, "EVP_MD_get_size returned invalid size.\n");break;}_p_digest_value = (uint8_t*)OPENSSL_malloc(digest_length);if (_p_digest_value == NULL) {// fprintf(stderr, "No memory.\n");break;}/** Make a message digest context to hold temporary state* during digest creation*/_evp_md_ctx = EVP_MD_CTX_new();if (NULL == _evp_md_ctx) {// fprintf(stderr, "EVP_MD_CTX_new failed.\n");break;}/** Initialize the message digest context to use the fetched* digest provider*/if (EVP_DigestInit(_evp_md_ctx, _evp_md) != 1) {// fprintf(stderr, "EVP_DigestInit failed.\n");break;}/* Digest parts one and two of the soliloqy */if (EVP_DigestUpdate(_evp_md_ctx, this->m_pu8_map_file, this->m_u32_file_size) != 1) {// fprintf(stderr, "EVP_DigestUpdate(hamlet_1) failed.\n");break;}if (EVP_DigestFinal(_evp_md_ctx, _p_digest_value, &digest_length) != 1) {// fprintf(stderr, "EVP_DigestFinal() failed.\n");break;}// hash in _p_digest_value[], len = digest_lengthif (digest_length > sizeof(m_ary_digest_value)){assert(false);break;}m_digest_length = digest_length;memcpy(m_ary_digest_value, _p_digest_value, digest_length);b_rc = true;} while (false);// 咱这次做的openssl内存泄漏检查的措施挺NB的, 如果下面的指针判断写错了(e.g. if (NULL == _evp_md_ctx) { ... }), 导致内存泄漏, 程序结束时, 就能有断言:P/* OpenSSL free functions will ignore NULL arguments */if (NULL != _evp_md_ctx){EVP_MD_CTX_free(_evp_md_ctx);_evp_md_ctx = NULL;}if (NULL != _p_digest_value){OPENSSL_free(_p_digest_value);_p_digest_value = NULL;}if (NULL != _evp_md){EVP_MD_free(_evp_md);_evp_md = NULL;}if (NULL != _ossl_lib_ctx){OSSL_LIB_CTX_free(_ossl_lib_ctx);_ossl_lib_ctx = NULL;}return b_rc;
}bool CPeFileCheck::is_PE_format_ok()
{bool b_rc = false;do {if (0 != memcmp(m_pu8_map_file, "MZ", 2)) {break;}if (this->m_u32_file_size < 64) {// printf("Corrupt DOS file - too short\n");break;}/* SizeOfHeaders field specifies the combined size of an MS-DOS stub, PE header,* and section headers rounded up to a multiple of FileAlignment.* SizeOfHeaders must be < filesize and cannot be < 0x0000002C (44) in Windows 7* because of a bug when checking section names for compatibility purposes */m_header_size = GET_UINT32_LE(this->m_pu8_map_file + 60);if (m_header_size < 44 || m_header_size > this->m_u32_file_size) {// printf("Unexpected SizeOfHeaders field: 0x%08X\n", header_size);break;}if (this->m_u32_file_size < m_header_size + 176) {// printf("Corrupt PE file - too short\n");break;}if (0 != memcmp(this->m_pu8_map_file + m_header_size, "PE\0\0", 4)) {// printf("Unrecognized DOS file type\n");break;}/* Magic field identifies the state of the image file. The most common number is* 0x10B, which identifies it as a normal executable file,* 0x20B identifies it as a PE32+ executable,* 0x107 identifies it as a ROM image (not supported) */m_magic = GET_UINT16_LE(this->m_pu8_map_file + m_header_size + 24);if (m_magic == 0x20b) {m_pe32plus = 1;}else if (m_magic == 0x10b) {m_pe32plus = 0;}else {// printf("Corrupt PE file - found unknown magic %04X\n", magic);break;}/* The image file checksum */this->m_dwPeCheckSumOrg = GET_UINT32_LE(this->m_pu8_map_file + m_header_size + 88);/* NumberOfRvaAndSizes field specifies the number of data-directory entries* in the remainder of the optional header. Each describes a location and size. */m_nrvas = GET_UINT32_LE(this->m_pu8_map_file + m_header_size + 116 + m_pe32plus * 16);if (m_nrvas < 5) {// printf("Can not handle PE files without certificate table resource\n");break;}/* Certificate Table field specifies the attribute certificate table address (4 bytes) and size (4 bytes) */m_sigpos = GET_UINT32_LE(this->m_pu8_map_file + m_header_size + 152 + m_pe32plus * 16);m_siglen = GET_UINT32_LE(this->m_pu8_map_file + m_header_size + 152 + m_pe32plus * 16 + 4);/* Since fix for MS Bulletin MS12-024 we can really assumethat signature should be last part of file */if (((m_sigpos != 0) || (m_siglen != 0)) &&((m_sigpos == 0) || (m_siglen == 0) || (m_sigpos >= this->m_u32_file_size) || ((m_sigpos + m_siglen) != this->m_u32_file_size))) {// printf("Ignoring PE signature not at the end of the file\n");m_sigpos = 0;m_siglen = 0;}b_rc = true;} while (false);return b_rc;
}bool CPeFileCheck::calc_PE_checksum(DWORD& dwPeCheckSumCalc)
{bool b_rc = false;uint32_t n = 0, checkSum = 0, offset = 0;BIO* bio = BIO_new(BIO_s_mem());uint8_t* buf = (uint8_t*)OPENSSL_malloc(SIZE_64K);do {dwPeCheckSumCalc = 0;/* calculate the checkSum */while (n < this->m_u32_file_size) {size_t i, written, nread;size_t left = m_u32_file_size - n;unsigned short val = 0;if (left > SIZE_64K)left = SIZE_64K;if (!BIO_write_ex(bio, this->m_pu8_map_file + n, left, &written)){break;}// 如果只想移动指针, 就用BIO_seek(void)BIO_seek(bio, 0);// BIO_reset(bio); // BIO_reset对于不是只读的BIO, 会清掉内容n += (uint32_t)written;if (!BIO_read_ex(bio, buf, written, &nread)){break;}for (i = 0; i < nread / 2; i++) {val = LE_UINT16(buf[i]);if (offset == m_header_size + 88|| offset == m_header_size + 90) {/* The image file checksum */val = 0;}checkSum += val;checkSum = LOWORD(LOWORD(checkSum) + HIWORD(checkSum));offset += 2;}}checkSum = LOWORD(LOWORD(checkSum) + HIWORD(checkSum));checkSum += offset;dwPeCheckSumCalc = checkSum;b_rc = true;} while (false);if (NULL != buf){OPENSSL_free(buf);buf = NULL;}if (NULL != bio){BIO_free(bio);bio = NULL;}return b_rc;
}uint32_t CPeFileCheck::get_file_size(const char* infile)
{int ret = 0;struct _stat64 st;ret = _stat64(infile, &st); // 必须是全路径名称, 否则返回-1if (ret) {// printf("Failed to open file: %s\n", infile);return 0;}if (st.st_size < 4) {// printf("Unrecognized file type - file is too short: %s\n", infile);return 0;}if (st.st_size > UINT32_MAX) {// printf("Unsupported file - too large: %s\n", infile);return 0;}return (uint32_t)st.st_size;
}uint8_t* CPeFileCheck::map_file(const char* infile, const size_t size)
{uint8_t* indata = NULL;HANDLE fhandle, fmap;(void)size;fhandle = CreateFileA(infile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);if (fhandle == INVALID_HANDLE_VALUE) {return NULL;}fmap = CreateFileMapping(fhandle, NULL, PAGE_READONLY, 0, 0, NULL);CloseHandle(fhandle);if (fmap == NULL) {return NULL;}indata = (uint8_t*)MapViewOfFile(fmap, FILE_MAP_READ, 0, 0, 0);CloseHandle(fmap);return indata;
}void CPeFileCheck::unmap_file(uint8_t* indata)
{if (!indata)return;UnmapViewOfFile(indata);
}
END
这篇关于openssl3.2 - exp - calc PE file checksum and SHA3-512的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!