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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/708692.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

K8s Pod资源管理组件

目录 Pod基础概念 在Kubrenetes集群中Pod有如下两种使用方式 pause容器使得Pod中的所有容器可以共享两种资源 网络 存储 总结 kubernetes中的pause容器主要为每个容器提供功能 Kubernetes设计这样的Pod概念和特殊组成结构的用意 通常把Pod分为以下几类 自主式Pod 控…

【字符串】-Lc3-无重复字符的最长子串(indexOf(String str, int fromIndex))

写在前面 最近想复习一下数据结构与算法相关的内容&#xff0c;找一些题来做一做。如有更好思路&#xff0c;欢迎指正。 目录 写在前面一、场景描述二、具体步骤1.环境说明2.代码 写在后面 一、场景描述 给定一个字符串&#xff0c;请你找出其中不含有重复字符的 最长子串 &…

input css padding

这样控件会跑出外套控件在HTML JSP里面是经常出现的。但有些外国adobe的as控件不存在这种情况&#xff0c;这是因为内层控件定义的时候不能超出外层控件的范围。 修改下&#xff1a;去掉原来css padding&#xff0c;然后加上宽度和高度

C语言 常量

常量是固定值&#xff0c;在程序执行期间不会改变。这些固定的值&#xff0c;又叫做字面量。 常量可以是任何的基本数据类型&#xff0c;比如整数常量、浮点常量、字符常量&#xff0c;或字符串字面值&#xff0c;也有枚举常量。 常量就像是常规的变量&#xff0c;只不过常量的…

EAP-TLS实验之Ubuntu20.04环境搭建配置(FreeRADIUS3.0)(四)

该篇主要介绍了利用配置ca.cnf、server.cnf、client.cnf在certs路径下生成证书文件&#xff08;非执行bootstrap脚本&#xff0c;网上也有很多直接通过openssl命令方式生成的文章&#xff09;&#xff0c;主要参考&#xff08;概括中心思想&#xff09;官方手册&#xff0c;以及…

s-table和columns初始化不完整,造成table文件的filter报错

问题 顺藤摸瓜找errorHandler.js文件 发现文件并没有什么问题 顺藤摸瓜找index.vue文件 首先找到报错的filter&#xff0c;发现与columnsSetting相关 找到columnsSetting发现等于columns 返回自己使用S-table组件的地方&#xff0c;发现columns初始化时仅初始化为ref()未表明…

统信软件:统一操作系统 UOS 代言人

这是ren_dong的第32篇原创 1、Deepin Deepin&#xff1a;最受欢迎的民用国产操作系统 2008 年,Deepin 操作系统最早版本正式发布&#xff0c;是由 深之度创始人刘闻欢组织团队研发的基于 Debian 的本地化 Linux 操作系统 2011 年,武汉深之度科技有限公司成立&#xff0c;开始产…

Facebook的虚拟社交愿景:元宇宙时代的新起点

在当今数字化时代&#xff0c;社交媒体已经成为人们生活中不可或缺的一部分。而随着科技的不断进步和社会的发展&#xff0c;元宇宙已经成为了人们关注的热点话题之一。作为社交媒体的领军企业之一&#xff0c;Facebook也在积极探索虚拟社交的未来&#xff0c;将其视为元宇宙时…

LeetCode 2886.改变数据类型

DataFrame students ------------------- | Column Name | Type | ------------------- | student_id | int | | name | object | | age | int | | grade | float | ------------------- 编写一个解决方案来纠正以下错误&#xff1a; grade 列被存储为浮点数&#xff0c;将它转…

6U VPX全国产飞腾D2000/8核+复旦微FPGA信息处理主板

产品特性 产品功能 飞腾计算平台&#xff0c;国产化率100% VPX-MPU6503是一款基于飞腾D2000/8核信息处理主板&#xff0c;采用由飞腾D2000处理器飞腾X100桥片的高性能计算机模块&#xff0c;双通道16G贴装内存&#xff0c;板载128G 固态SSD&#xff1b;预留固态盘扩展接口&…

cppzmq入门

cppzmq是一个基于ZeroMQ的开源C 库&#xff0c;用于构建分布式和并发应用程序。它提供了与ZeroMQ消息队列进行通信的简单接口。本文将介绍cppzmq的基本概念、常用模式以及示例代码。 基本概念 ZeroMQ&#xff1a;ZeroMQ是一个轻量级的消息队列库&#xff0c;它允许应用程序通过…

LaTeX笔记

文章目录 基本操作文本加粗 图片插入引用 表格插入引用 公式插入引用 参考文献超链接跳转问题修改hyperref包属性&#xff0c;去掉方框 latex入门指南&#xff1a;插入图片、表格、公式方法一览_latex插入表格-CSDN博客 基本操作 文本加粗 先选中&#xff0c;再 ctrlb 图片…

试题 算法训练 礼物

资源限制 内存限制&#xff1a;256.0MB C/C时间限制&#xff1a;1.0s Java时间限制&#xff1a;3.0s Python时间限制&#xff1a;5.0s 问题描述 JiaoShou在爱琳大陆的旅行完毕&#xff0c;即将回家&#xff0c;为了纪念这次旅行&#xff0c;他决定带回一些礼物给好朋友。…

蓝桥杯第十二届电子类单片机组程序设计

目录 前言 蓝桥杯大赛历届真题_蓝桥杯 - 蓝桥云课&#xff08;点击查看&#xff09; 单片机资源数据包_2023&#xff08;点击下载&#xff09; 一、第十二届比赛原题 1.比赛题目 2.题目解读 蓝桥杯第十四届电子类单片机组程序设计_蓝桥杯单片机哪一届最难-CSDN博客 二、…

金三银四面试必问:Redis真的是单线程吗?

文章目录 01 Redis中的多线程1&#xff09;redis-server&#xff1a;2&#xff09;jemalloc_bg_thd3&#xff09;bio_xxx&#xff1a; 02 I/O多线程03 Redis中的多进程04 结论▼延伸阅读 由面试题“Redis是否为单线程”引发的思考 作者&#xff1a;李乐 来源&#xff1a;IT阅读…

Android Kotlin协程实战

你能听懂的Kotlin协程课&#xff0c;跟老司机学&#xff0c;不用自己瞎折腾 认识协程 协程难在哪儿? Ja v a中不曾出现的&#xff0c;新概念概念不清晰&#xff0c;我们看到的大都是不同语言对于协程的实现或者衍生Kotlin 基础不扎实多线程编程基础太薄弱 协程是什么? 协…

OpenAI最新发布的文生视频模型Sora到底强在哪?

文章目录 1.Sora到底强在哪&#xff1f;2. 不足3. 结尾 2024年2月16日&#xff0c;当大家沉浸在过年的喜庆氛围中&#xff0c;OpenAI发布首款文生成视频大模型 Sora &#xff0c;其炸裂登场让人感到惊艳。 Sora官网介绍&#xff1a;https://openai.com/sora 说起文生视频工具…

SLA 是什么?如何实现 SLA 管理

随着业务的不断壮大&#xff0c;为了满足日益增长的客户需求&#xff0c;网络必须保持与这些需求同步。同时&#xff0c;为了提高最终用户的体验&#xff0c;运维人员/网络管理员在监控企业级网络时遇到了不少瓶颈&#xff0c;必须不断审查网络&#xff0c;以确保提供的服务质量…

【Python笔记-设计模式】备忘录模式

一、说明 备忘录模式是一种行为设计模式&#xff0c;允许在不暴露对象实现细节的情况下保存和恢复对象之前的状态。 (一) 解决问题 主要解决在不破坏封装性的前提下&#xff0c;捕获一个对象的内部状态&#xff0c;并在对象之外保存这个状态&#xff0c;以便在需要时恢复对象…

c#委托的三种实现方式

委托是实质一个类&#xff0c;主要目的是将方法当作参数进行传递。 委托是.NET编程的精髓之一&#xff0c;在日常编程中经常用到&#xff0c;在C#中实现委托主要有Func、Action、delegate三种方式&#xff0c;本节主要就这三种委托的用法通过实例展开讲解。 Func用法解析 【F…