MemoryModule - 应用编程细节
文章目录
- MemoryModule - 应用编程细节
- 概述
- 笔记
- 实验环境
- 升级MemoryModule,在上下文中加入DLL在内存载入前的信息
- MemoryModule.h
- MemoryModule.cpp
- 实现接口MemoryGetPayload()
- 整理 - 在内存载入的DLL中,取得资源表中的信息,取得载入前的DLL内容载荷
- 备注
- END
MemoryModule - 应用编程细节
概述
MemoryModule将DLL从内存载入,试过了好使。
现在有如下需求:
- 在内存载入的DLL中,对自身对应的载入前实体做完整性的hash校验。
- 在内存载入的DLL中,取得资源信息(文件版本资源中的版本信息等,字符串资源)
需求1,官方没提供内存载入之前的实体信息,这个要自己改,在CTX上加入载入前的信息(pData, lenData)
需求2,官方演示了前半段,演示的不全。需要自己整理一下。
笔记
实验环境
vs2019 x64 unicode debug mfc dlg
升级MemoryModule,在上下文中加入DLL在内存载入前的信息
MemoryModule.h
/*** Get address of exported method. Supports loading both by name and by* ordinal value.*/
FARPROC MemoryGetProcAddress(HMEMORYMODULE, LPCSTR);// 增加接口, 取DLL在内存中载入前的载荷(pData, lenData)
// 有了这个接口, 在DLL中就可以拿载入前的DLL数据做完整性校验(可以知道是不是被逆向工程师改了)
// 这个接口的好处,不用将内存载入前的信息(pData, lenData)通过DLL接口传进去,那样比较扎眼。
// 有了这个接口,只需要DLL提供一个接口,将上下文HMEMORYMODULE hDllWasLoad传进去。不容易被人家改
bool MemoryGetPayload(HMEMORYMODULE hDllWasLoad, uint8_t** ppData, int* pLen);
MemoryModule.cpp
将 MemoryModule.c 改名为MemoryModule.cpp
#include "pch.h" // add this for vs2019 build#include <windows.h>
#include <winnt.h>
#include <stddef.h>
#include <stdint.h> // add this for uint8_t
#include <tchar.h>
#ifdef DEBUG_OUTPUT
#include <stdio.h>
#endif
typedef struct {PIMAGE_NT_HEADERS headers;unsigned char *codeBase;HCUSTOMMODULE *modules;int numModules;BOOL initialized;BOOL isDLL;BOOL isRelocated;CustomAllocFunc alloc;CustomFreeFunc free;CustomLoadLibraryFunc loadLibrary;CustomGetProcAddressFunc getProcAddress;CustomFreeLibraryFunc freeLibrary;struct ExportNameEntry *nameExportsTable;void *userdata;ExeEntryProc exeEntry;DWORD pageSize;
#ifdef _WIN64POINTER_LIST *blockedMemory;
#endifuint8_t* pDataInByLoad; // add DLL payload info(pData, lenData) on MEMORYMODULE define's tailint lenDataInByLoad;
} MEMORYMODULE, *PMEMORYMODULE;
修正OutputLastError()的编译错误(工程为vs2019 + unicode)
static inline void
OutputLastError(const char *msg)
{
#ifndef DEBUG_OUTPUTUNREFERENCED_PARAMETER(msg);
#elseLPVOID tmp;char *tmpmsg;FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&tmp, 0, NULL);tmpmsg = (char *)LocalAlloc(LPTR, strlen(msg) + strlen((const char*)tmp) + 3); // bugfixsprintf(tmpmsg, "%s: %s", msg, (const char*)tmp); // bugfixOutputDebugStringA(tmpmsg); // bugfixLocalFree(tmpmsg);LocalFree(tmp);
#endif
}
升级MemoryLoadLibraryEx()
HMEMORYMODULE MemoryLoadLibraryEx(const void *data, size_t size,CustomAllocFunc allocMemory,CustomFreeFunc freeMemory,CustomLoadLibraryFunc loadLibrary,CustomGetProcAddressFunc getProcAddress,CustomFreeLibraryFunc freeLibrary,void *userdata)
{
// ...result = (PMEMORYMODULE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MEMORYMODULE));if (result == NULL) {freeMemory(code, 0, MEM_RELEASE, userdata);
#ifdef _WIN64FreePointerList(blockedMemory, freeMemory, userdata);
#endifSetLastError(ERROR_OUTOFMEMORY);return NULL;}result->pDataInByLoad = (uint8_t*)data; // add thisresult->lenDataInByLoad = (int)size; // add thisresult->codeBase = code;result->isDLL = (old_header->FileHeader.Characteristics & IMAGE_FILE_DLL) != 0;result->alloc = allocMemory;result->free = freeMemory;result->loadLibrary = loadLibrary;result->getProcAddress = getProcAddress;result->freeLibrary = freeLibrary;result->userdata = userdata;result->pageSize = sysInfo.dwPageSize;
#ifdef _WIN64result->blockedMemory = blockedMemory;
#endif
// ...
}
实现接口MemoryGetPayload()
bool MemoryGetPayload(HMEMORYMODULE hDllWasLoad, uint8_t** ppData, int* pLen)
{bool b_rc = false;PMEMORYMODULE hDllCtx = NULL;do {if ((NULL == hDllWasLoad) || (NULL == ppData) || (NULL == pLen)){break;}hDllCtx = (PMEMORYMODULE)hDllWasLoad;*ppData = hDllCtx->pDataInByLoad;*pLen = hDllCtx->lenDataInByLoad;b_rc = true;} while (false);return b_rc;
}
整理 - 在内存载入的DLL中,取得资源表中的信息,取得载入前的DLL内容载荷
以下是刚做完实验的草稿代码,能看出以上2个需求的实现了。
再做整理,就可以是正式的代码。
// extern "C" __declspec(dllexport) bool APIENTRY test(HMEMORYMODULE hDll)
typedef bool (APIENTRY* PFN_test)(HMEMORYMODULE hDll);
// DLL定义了一个接口 e.g. init(HMEMORYMODULE hDll), 只要调用这个接口,就可以在接口内知道DLL在内存载入前的载荷,和载入后的资源信息(STRING by resource ID, FILE VERSION(e.g. 内部exe名称))#pragma comment(lib, "Version.lib") // VerQueryValue// _T("CompanyName")
CString get_FileInfoValue(BYTE* byData, const TCHAR* pszValueName)
{CString csQuery;CString csRc;TCHAR* lpVers = NULL;unsigned int uLen = 0;std::string strA;std::wstring strW;_ASSERT(NULL != pszValueName);// _T("\\StringFileInfo\\%s\\%s") // 拼接要查询的文件版本信息的字符串csQuery.Format(_T("\\StringFileInfo\\%s\\%s"), _T("080404b0"), pszValueName);_ASSERT(NULL != byData);// \StringFileInfo\080404b0\CompanyName// 取得了文件资源区内容后,就可以直接用WIN32API VerQueryValue(), 这个API和DLL载入的基地址没关系,只和文件版本信息的具体数据有关系。VerQueryValue(byData, (LPCWSTR)csQuery, (void**)&lpVers, &uLen);if ((uLen > 0) && (NULL != lpVers)){csRc = lpVers;}return csRc;
}void CLoaderDlg::OnBnClickedButton1() {uint8_t* pBuf = NULL;int len = 0;bool b = false;HMEMORYMODULE handle = NULL;PFN_test pfn_test = NULL;HMEMORYRSRC hRc = NULL;DWORD resourceSize = 0;LPVOID resourceData = NULL;CString csTmp;int i_rc = 0;TCHAR buffer[MAX_PATH + 1];do {len = sizeof(ucAry_ary_DllForTest_x64Debug);DLOG(INFO) << "sizeof(ucAry_ary_DllForTest_x64Debug) = " << len;pBuf = new uint8_t[len + 1];assert(NULL != pBuf);pBuf[len] = '\0';memcpy(pBuf, ucAry_ary_DllForTest_x64Debug, len);DLOG(INFO) << "pBuf = " << (void*)pBuf << ", len = " << len;handle = MemoryLoadLibrary(pBuf, len);if (NULL == handle) {DLOG(INFO) << "Can't load library from memory";assert(false);break;}DLOG(INFO) << "handle = " << handle;// HMEMORYMODULE module, LPCTSTR name, LPCTSTR type, WORD languagehRc = MemoryFindResource(handle, MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION);if (NULL == hRc){DLOG(INFO) << hRc << " = MemoryFindResourceEx()";break;}resourceSize = MemorySizeofResource(handle, hRc);resourceData = MemoryLoadResource(handle, hRc);// 已经验证过了,好使csTmp = get_FileInfoValue((BYTE*)resourceData, _T("CompanyName"));// csTmp is _T("TODO: <公司名>")// IDS_STRING102// 已经验证过了,好使i_rc = MemoryLoadString(handle, 102, buffer, sizeof(buffer));// i_rc = 6, buffer = _T("测试字符串2")if (i_rc >= 0){buffer[i_rc] = TEXT('\0');}pfn_test = (PFN_test)MemoryGetProcAddress(handle, "test");if (NULL == pfn_test) {break;}// 已经验证过了,只要内存载入DLL成功,MemoryModule库的API在DLL外部调用和接口内部调用,都是正确的。// 因为EXE和DLL在一个进程空间内, 内存指针都是一个(只要内存指针有效,在DLL外部和DLl内部访问的handle(从内存载入DLL的上下文句柄)都是同一个)b = pfn_test(handle);DLOG(INFO) << "pfn_test() = " << b;} while (false);if (NULL != handle) {MemoryFreeLibrary(handle);handle = NULL;}if (NULL != pBuf) {delete[] pBuf;pBuf = NULL;}
}
备注
刚开始,只是简单的用MemoryModule从内存载入DLL
后来有新需求时,如果不借助MemoryModule,而是自己取东西,那得对PE结构有多熟悉才能搞定啊。
查了很多资料,都不理想。
再想想,既然MemoryModule都从内存载入了DLL, 执行DLL接口都好使。那这些PE内部信息,MemoryModule的载入操作应该都门清啊。
回头来看,果真如此。
如果不满足于使用第三方库,而是尽力再了解的深入一些(应该比普通应用再深入一点就行),就有很多好东西可以挖出来用。
END
相关文章:
MemoryModule - 应用编程细节
文章目录 MemoryModule - 应用编程细节概述笔记实验环境升级MemoryModule,在上下文中加入DLL在内存载入前的信息MemoryModule.hMemoryModule.cpp实现接口MemoryGetPayload() 整理 - 在内存载入的DLL中,取得资源表中的信息,取得载入前的DLL内容…...
Java程序CPU持续高,如何排查?
首先找到进程ID jps然后找到该进程用占用cpu高的线程 top -Hp 进程ID将线程ID转化为十六进制 printf “0x%x” 线程ID使用jstack 工具跟踪堆栈定位问题 jstack 进程ID | grep 十六进制线程ID -A 5说明,最后-A 5是打印出来后5行。...
(Java)心得:LeetCode——15.三数之和
一、原题 给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k ,同时还满足 nums[i] nums[j] nums[k] 0 。请你返回所有和为 0 且不重复的三元组。 注意:答案中不可以包含重复的三元组。…...
Rust中忽略JSON反序列化时的不必要字段
在Rust中处理JSON数据时,经常会遇到JSON数据中包含一些在目标数据结构中不存在的字段的情况。如果你使用的是serde和serde_json这两个流行的库来处理JSON,那么有一些简单的方法可以忽略这些不必要的字段。 默认行为:忽略未知字段 在Rust中&…...

UDP多对多组播通信
广播和多播仅应用于UDP。TCP是一个面向连接的协议,TCP一定是点对点的,一点是两个主机来建立连接的,TCP肯定是单播。只有UDP才会使用广播和组播。 如下示例实现一个UDP多对多的组播通信,进程中有收、发两个线程,分别表…...

Linux技术---部署PXE服务器实现批量安装操作系统
部署PXE服务器实现批量安装操作系统 部署PXE服务器实现批量安装操作系统 部署PXE服务器实现批量安装操作系统1.安装相关服务组件1.1 安装tftp和xinetd1.2 安装DHCP服务1.3 准备 Linux 内核、初始化镜像文件、 PXE 引导程序、安装FTP服务并准备安装源1.4 配置启动菜单文件1.5 验…...

日志:打印技巧
一、概览 Unity日志打印技巧 常规日志打印彩色日志日志存储与上传日志开关日志双击溯源 二、常规日志打印 1、打印Hello World 调用堆栈可以很好的帮助我们定位问题,特别是报错的Error日志 Debug.Log("Hello World");Debug.Log("This is a log m…...

二叉树的常见操作
建立树 复制二叉树 计算深度 计算总结点数 计算叶子结点数...

CSS 根据子元素选择父元素,并设置父元素的样式
场景举例:当子元素有增加了一个class时,需要影响其父元素的样式 可以使用":has"伪类来实现选择父元素的效果 <style>.parent:has(.child){background-color: #eee;}p{width:100px;border:1px solid #000;} </style> <body>…...
onnx转trt时,关于动态shape自动配置默认值的脚本
onnx转trt时,关于动态shape自动配置默认值,一般需要指定3个shape,分别是最小最优与最大。但是我们在测试时不想写那么多的代码,能否自动实现3个shape的配置,这里实现了一版。 import osimport tensorrt as trt import…...

实验室无法培养的菌,原来可以这么研究!
厌氧氨氧化(anammox)细菌在全球氮循环和废水氮去除中发挥着至关重要的作用,由于anammox细菌生长缓慢、难以培养等特点,对其生态学和生物学特性知之甚少。近日,凌恩生物合作客户重庆大学陈猷鹏教授团队在《Science of t…...

Xed编辑器开发第一期:使用Rust从0到1写一个文本编辑器
这是一个使用Rust实现的轻量化文本编辑器。学过Rust的都知道,Rust 从入门到实践中间还隔着好几个Go语言的难度,因此,如果你也正在学习Rust,那么恭喜你,这个项目被你捡到了。本项目内容较多,大概会分三期左右陆续发布&a…...

农业自动气象监测站:赋能智慧农业的新动力
在信息化、智能化快速发展的今天,农业领域也迎来了前所未有的变革。其中,农业自动气象监测站作为智慧农业的重要组成部分,正在发挥着越来越重要的作用。它们如同农业生产的“眼睛”和“耳朵”,实时感知和记录着大气的微妙变化&…...

2-6 任务 猜数小游戏(单次版)
本任务要求编写一个猜数小游戏(单次版),游戏规则是计算机产生一个0到100之间的随机整数,用户通过输入猜测的数字进行猜测,根据猜测情况给出提示,直到猜对为止。编程思路是利用while循环和多分支结构实现永真…...
springboot 定时任务解决方案
Scheduled (springboot 自带的 注解) 基于注解Scheduled默认为单线程,开启多个任务时,任务的执行时机会受上一个任务执行时间的影响。 EnableScheduling注解: 在配置类上使用,开启计划任务的支持(类上)。…...

谷粒商城实战(024 业务-订单模块-分布式事务1)
Java项目《谷粒商城》架构师级Java项目实战,对标阿里P6-P7,全网最强 总时长 104:45:00 共408P 此文章包含第284p-第p290的内容 简介 模拟积分服务出异常,前方的锁库存事务未回滚,这时候就需要分布式事务 本地事务 事务的隔离…...
.NET使用Microsoft.IdentityModel.Tokens对SAML2.0登录断言校验
如题。使用SAML单点登录对IDP返回的Response断言使用微软提供的Microsoft.IdentityModel.Tokens对断言(Assertion)进行校验。 首先需要安装Muget包,Microsoft.IdentityModel.Tokens和Microsoft.IdentityModel.Tokens.Saml。 简易示例代码如…...

性能测试学习二
瓶颈的精准判断 TPS曲线 tps图 响应时间图 拐点在哪里呢? 这是一个阶梯式增加的场景,拐点在第二个压力阶梯上就出现了,因为响应时间增加了,tps增加的却不多,在第三个阶段时,tps增加的就更少了,响应时间也在不断增加,所以性能瓶颈在加剧,越往后越明显【tps的增长,…...

小丑的身份证和复印件 (BFS + Floyd)
本题链接:登录—专业IT笔试面试备考平台_牛客网 题目: 样例: 输入 2 10 (JOKERjoke #####asdr) 输出 12 思路: 根据题意,要求最短时间,实际上也可以理解为最短距离。 所以应该联想到有关最短距离的算法&…...

C++类与对象(上)
C类与对象 面向过程和面向对象初步认识类的引入类的定义类的两种定义方式: 类的访问限定符及封装访问限定符 封装类的作用域类的实例化类对象模型如何计算类对象的大小结构体内存对齐规则: this指针 面向过程和面向对象初步认识 C语言是面向过程的&…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...

MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍
文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结: 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析: 实际业务去理解体会统一注…...

ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...

使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台
🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...
在Ubuntu24上采用Wine打开SourceInsight
1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...

网站指纹识别
网站指纹识别 网站的最基本组成:服务器(操作系统)、中间件(web容器)、脚本语言、数据厍 为什么要了解这些?举个例子:发现了一个文件读取漏洞,我们需要读/etc/passwd,如…...

【VLNs篇】07:NavRL—在动态环境中学习安全飞行
项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战,克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...