openssl3.2 - exp - calc PE file checksum and SHA3-512

2024-02-29 13:52

本文主要是介绍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的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/759013

相关文章

Open a folder or workspace... (File -> Open Folder)

问题:vscode Open with Live Server 时 显示Open a folder or workspace... (File -> Open Folder)报错 解决:不可以单独打开文件1.html ; 需要在文件夹里打开 像这样

android java.io.IOException: open failed: ENOENT (No such file or directory)-api23+权限受权

问题描述 在安卓上,清单明明已经受权了读写文件权限,但偏偏就是创建不了目录和文件 调用mkdirs()总是返回false. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.READ_E

bash: arm-linux-gcc: No such file or directory

ubuntu出故障重装了系统,一直用着的gcc使用不了,提示bash: arm-linux-gcc: No such file or directorywhich找到的命令所在的目录 在google上翻了一阵发现此类问题的帖子不多,后来在Freescale的的LTIB环境配置文档中发现有这么一段:     # Packages required for 64-bit Ubuntu

编译linux内核出现 arm-eabi-gcc: error: : No such file or directory

external/e2fsprogs/lib/ext2fs/tdb.c:673:29: warning: comparison between : In function 'max2165_set_params': -。。。。。。。。。。。。。。。。。。 。。。。。。。。。。。。。 。。。。。。。。 host asm: libdvm <= dalvik/vm/mterp/out/Inte

linux 内核提权总结(demo+exp分析) -- 任意读写(四)

hijack_modprobe_path篇 本文转自网络文章,内容均为非盈利,版权归原作者所有。 转载此文章仅为个人收藏,分享知识,如有侵权,马上删除。 原文作者:jmpcall 专栏地址:https://zhuanlan.kanxue.com/user-815036.htm     原理同hijack_prctl, 当用户执行错误格式的elf文件时内核调用call_usermod

linux 内核提权总结(demo+exp分析) -- 任意读写(三)

hijack_prctl篇 本文转自网络文章,内容均为非盈利,版权归原作者所有。 转载此文章仅为个人收藏,分享知识,如有侵权,马上删除。 原文作者:jmpcall 专栏地址:https://zhuanlan.kanxue.com/user-815036.htm   prctl函数: 用户态函数,可用于定制进程参数,非常适合和内核进行交互 用户态执行prctl函数后触发prctl系统

linux 内核提权总结(demo+exp分析) -- 任意读写(二)

hijack_vdso篇 本文转自网络文章,内容均为非盈利,版权归原作者所有。 转载此文章仅为个人收藏,分享知识,如有侵权,马上删除。 原文作者:jmpcall 专栏地址:https://zhuanlan.kanxue.com/user-815036.htm     vdso: 内核实现的一个动态库,存在于内核,然后映射到用户态空间,可由用户态直接调用 内核中的vdso如果被修改

linux 内核提权总结(demo+exp分析) -- 任意读写(一)

cred篇 本文转自网络文章,内容均为非盈利,版权归原作者所有。 转载此文章仅为个人收藏,分享知识,如有侵权,马上删除。 原文作者:jmpcall 专栏地址:https://zhuanlan.kanxue.com/user-815036.htm   每个线程在内核中都对应一个线程结构块thread_infothread_info中存在task_struct类型结构体 struct t

linux 内核提权总结(demo+exp分析) -- ROP(二)

ret2usr CR4篇 本文转自网络文章,内容均为非盈利,版权归原作者所有。 转载此文章仅为个人收藏,分享知识,如有侵权,马上删除。 原文作者:jmpcall 专栏地址:https://zhuanlan.kanxue.com/user-815036.htm   smep: smep是内核的一种保护措施, 使得内核不可执行用户态代码 内核通过CR4寄存器的第20位来控制smep,

linux 内核提权总结(demo+exp分析) -- ROP(一)

基础ROP篇(linux 5.0.21) 本文转自网络文章,内容均为非盈利,版权归原作者所有。 转载此文章仅为个人收藏,分享知识,如有侵权,马上删除。 原文作者:jmpcall 专栏地址:https://zhuanlan.kanxue.com/user-815036.htm   内核提权与用户态攻击的区别 攻击流程 用户态攻击: 执行 system("/bin/sh") 获得shel