当前位置: 首页 > article >正文

Windows系统编程(六)内存操作与InlineHook

内存操作

我们以代码进行讲解有关系统内存的操作

#include <iostream>
#include <Windows.h>
#include <Psapi.h>//进程相关操作需要包括的头文件

int main()
{
    //获取系统当前物理内存和虚拟内存使用情况的信息
	MEMORYSTATUSEX lpMemStatus = { sizeof(MEMORYSTATUSEX) };//该结构用于保存系统物理内存和虚拟内存(包括扩展内存)的当前状态的信息。
	GlobalMemoryStatusEx(&lpMemStatus);//获取

	//获取系统内存信息
	SYSTEM_INFO lpSysInfo = { 0 };//该结构用于保存当前计算机系统的相关信息
	GetSystemInfo(&lpSysInfo);//获取

	//获取进程内存信息
	//GetCurrentProcess();获取当前进程句柄
	//GetCurrentProcessId();获取当前进程ID
	PROCESS_MEMORY_COUNTERS pmcInfo;//该结构接收有关进程的内存使用情况的信息。
	GetProcessMemoryInfo(GetCurrentProcess(), &pmcInfo, sizeof(PROCESS_MEMORY_COUNTERS));//获取

    //获取指定进程的虚拟地址空间中的页面范围的信息
	LPVOID lpAddr = VirtualAlloc(NULL, 0x100, MEM_COMMIT, PAGE_READONLY);//在调用进程的虚拟地址空间中分配或保留一块内存区域
    MEMORY_BASIC_INFORMATION mbiInfo;//该结构用于进程虚拟地址空间中的页面范围的信息
	VirtualQueryEx(GetCurrentProcess(), lpAddr, &mbiInfo, sizeof(mbiInfo));//查询指定进程的目标虚拟地址空间中内存区域的相关信息
	VirtualFree(lpAddr, 0, MEM_RELEASE);//释放已申请的虚拟内存

    //修改指定进程的虚拟地址空间中的页面范围属性
    LPVOID lpAddr = VirtualAlloc(NULL, 0x100, MEM_COMMIT, PAGE_READONLY);//此处申请的虚拟内存只能读
	DWORD lpflOldProtect = 0;//用于接收原有的内存访问属性
	VirtualProtectEx(GetCurrentProcess(), lpAddr, 0x100, PAGE_READWRITE, &lpflOldProtect);//修改虚拟内存属性为可读可写
	memcpy(lpAddr, "123456", 7);//此时可在指定虚拟内存写信息
	VirtualProtectEx(GetCurrentProcess(), lpAddr, 0x100, lpflOldProtect, &lpflOldProtect);//修改为原来的内存访问属性
	VirtualFree(lpAddr, 0, MEM_RELEASE);//释放已申请的虚拟内存

    //创建堆
	//堆:由一种数据结构进行管理的内存,一个进程可以有多个堆,但通常使用默认堆,默认堆具有默认大小,可随认为申请而变大
    //内存是在进程的默认堆中进行分配
	HANDLE hHeap = HeapCreate(HEAP_NO_SERIALIZE, 0, 1024);//创建一个堆对象,此时操作系统为该堆保留一段连续虚拟内存,此时并未分配物理内存
	LPVOID lpAddr = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, MAX_PATH);//在目标堆分配物理内存,此时虚拟内存映射物理内存
	memcpy(lpAddr, "123456", 7);//在目标堆内存写数据
	HeapFree(hHeap, HEAP_NO_SERIALIZE, lpAddr);//释放堆内存
	HeapDestroy(hHeap);//销毁堆对象
	system("pause");
	return 0;
}

如上代码所提及的API,Ex版本通常可以跨进程,不带Ex版本只可以自己的进程

Inline HOOK

Inline hook(内联钩子)是一种在程序运行时修改函数执行流程的技术。它通过修改函数的原始代码,将目标函数的执行路径重定向到自定义的代码段,从而实现对目标函数的拦截和修改。

当我们需要修改某API的参数时,有两种方法:

1.API传参时修改内存

2.Inline HOOK:API传参以后,在函数内部执行之前,拦截函数进行参数修改

接下来我们将通过一个实例讲解Inline HOOK

如下已知的源代码

#include <iostream>
#include <Windows.h>

int main()
{
	MessageBoxA(NULL, "rkvir", "success", MB_OK);
	system("pause");
	MessageBoxA(NULL, "rkvir", "success", MB_OK);
	return 0;
}

接下来我们将通过第二种方法Inline HOOK来实现MessageBox参数的修改

1.找到API汇编实现处

将该exe文件拖入x32dbg

如图是上文程序调用MessageBoxA的汇编代码:首先压入了四个参数,然后调用MessageBoxA

如图是MessageBoxA的实现代码

根据上图内存地址可知,前三行代码正好五个字节

2.Inline HOOK

原理:当我们需要通过HOOK修改API的传参时,便要进入API内部,在功能实现前做拦截:修改前五个字节为jmp到目标内存处,使得当程序进入API内部时,在功能实现前便会跳转到目标内存处而不会执行原先的实现代码

注意:32位程序内存地址四个字节,jmp指令一个字节,一共五个字节

实现流程:

1.定位目标函数的地址:通过函数名或者导入表等方式找到目标函数在内存中的地址。

2.修改目标函数的内存权限:将目标函数的内存权限修改为可写可执行,以便后续修改函数的指令。

3.备份目标函数的原始指令:将目标函数的原始指令备份到自定义的缓冲区中。

4.修改目标函数的指令:将目标函数的指令修改为跳转到自定义代码的指令,以实现拦截和修改

5.编写自定义代码:编写自定义的代码,实现对目标函数的拦截和修改逻辑。

6.执行自定义代码:将自定义的代码插入到目标函数的执行流程中,使其被调用时执行自定义逻辑。

7.恢复目标函数的原始指令:在自定义代码执行完毕后,恢复目标函数的原始指令,以确保目标函数的正常执行。

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
#include <Windows.h>

//保存目标函数的地址(被HOOK的函数)
PROC m_FunAddress = NULL;
//保存MessageBoxA老的五个字节
BYTE m_OldBytes[5] = { 0 };
//保存MessageBoxA新的五个字节
BYTE m_NewBytes[5] = { 0 };

//Hook
//pszModuleName:目标函数所处模块的名称
//pszFuncName:目标函数名
//pfnHookFunc:劫持流程函数的地址
BOOL Hook(const char * pszModuleName, const char * pszFuncName, PROC pfnHookFunc)
{
	HMODULE hModule = GetModuleHandleA(pszModuleName);//获取目标函数所处模块的句柄
	m_FunAddress = GetProcAddress(hModule, pszFuncName);//获取目标函数地址
	if (m_FunAddress == NULL)
	{
		return FALSE;
	}
	DWORD dwRet = 0;
	BOOL bRet = ReadProcessMemory(GetCurrentProcess(), m_FunAddress, m_OldBytes, 5, &dwRet);//读取MessageBoxA老的五个字节
	if (!bRet)
	{
		return FALSE;
	}
	m_NewBytes[0] = '\xE9';//jmp的硬编码
    //jmp跳转的地址为相对地址
	//相对地址 = 劫持函数地址 - 目标函数地址 - 指令长度
	*(DWORD *)(m_NewBytes + 1) = (DWORD)pfnHookFunc - (DWORD)m_FunAddress - 5;
	bRet = WriteProcessMemory(GetCurrentProcess(), m_FunAddress, m_NewBytes, 5, &dwRet);//在目标函数处写入新的五个字节
	if (!bRet)
	{
		return FALSE;
	}
	else
	{
		return TRUE;
	}

}

VOID UnHook()//卸载hook
{
	if (m_FunAddress!= NULL)
	{
		DWORD dwRet = 0;
		WriteProcessMemory(GetCurrentProcess(), m_FunAddress, m_OldBytes, 5, &dwRet);
	}
}

VOID ReHook()//恢复hook
{
	if (m_FunAddress != NULL)
	{
		DWORD dwRet = 0;
		WriteProcessMemory(GetCurrentProcess(), m_FunAddress, m_NewBytes, 5, &dwRet);
	}
}

int
WINAPI
MyMessageBoxA//HOOK的函数
(
	_In_opt_ HWND hWnd,
	_In_opt_ LPCSTR lpText,
	_In_opt_ LPCSTR lpCaption,
	_In_ UINT uType
)
{
	//卸载HOOK
	UnHook();
	int bRet = MessageBoxA(hWnd, "hook", "hook", uType);
	//重新挂钩
	ReHook();
	return bRet;
}

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH://dll加载时
		Hook("user32.dll", "MessageBoxA", (PROC)MyMessageBoxA);
		break;
    case DLL_THREAD_ATTACH:
		break;
    case DLL_THREAD_DETACH:
		break;
    case DLL_PROCESS_DETACH://dll卸载时
		UnHook();
        break;
    }
    return TRUE;
}


http://www.kler.cn/a/551698.html

相关文章:

  • 国自然青年基金|针对罕见神经上皮肿瘤的小样本影像深度数据挖掘关键技术研究|基金申请·25-02-15
  • 电磁兼容(EMC):整改案例(十二)调整PCB叠层设计解决静电问题
  • [STM32 - 野火] - - - 固件库学习笔记 - - - 十五.设置FLASH的读写保护及解除
  • WebRTC嵌入式视频通话SDK:EasyRTC从免插件到轻量级带来的音视频通话技术
  • AI工具篇:利用DeepSeek+Kimi 辅助生成综述汇报PPT
  • 无人机+低轨卫星:无限距离集群网络技术详解
  • JAVA系列之数组的秘密(数组的一般用法+力扣 斯坦福大学练习精解)
  • Ansible自动化运维中剧本角色(roles)来完成apache服务操作
  • 如何在本地和线上安装和配置RabbitMQ
  • 交换机三层转发原理(涵盖ARP,ICMP,IP协议)
  • 探秘 Python 枚举类型:从基础到实战的深度指南
  • pyqt写一个待办程序
  • IIS asp.net权限不足
  • Android Studio:用handler实现计数
  • 基于遗传算法排课系统
  • Flutter 3.29.0 新特性 CupertinoNavigationBar 可配置bottom属性
  • AI(人工智能)会给嵌入式领域带来哪些机遇与挑战?
  • golang常用库之-swaggo/swag根据注释生成接口文档
  • 电磁铁在生产与生活中的广泛应用
  • Ubuntu 24.04.1 LTS 本地部署 DeepSeek 私有化知识库