龙马谷

 找回密码
 立即注册

QQ登录

只需一步,快速开始

龙马谷VIP会员办理客服QQ:82926983(如果临时会话没有收到回复,请先加QQ好友再发。)
1 [已完结] GG修改器新手入门与实战教程 31课 2 [已完结] GG修改器美化修改教程 6课 3 [已完结] GG修改器Lua脚本新手入门教程 12课
4 [已完结] 触动精灵脚本新手入门必学教程 22课 5 [已完结] 手游自动化脚本入门实战教程 9课 6 [已完结] C++射击游戏方框骨骼透视与自瞄教程 27课
7 [已完结] C++零基础UE4逆向开发FPS透视自瞄教程 29课 8 [已完结] C++零基础大漠模拟器手游自动化辅助教程 22课 9 [已完结] C++零基础开发DXF内存脚本辅助教程 32课
以下是天马阁VIP教程,本站与天马阁合作,赞助VIP可以获得天马阁对应VIP会员,名额有限! 点击进入天马阁论坛
1 [已完结] x64CE与x64dbg入门基础教程 7课 2 [已完结] x64汇编语言基础教程 16课 3 [已完结] x64辅助入门基础教程 9课
4 [已完结] C++x64内存辅助实战技术教程 149课 5 [已完结] C++x64内存检测与过检测技术教程 10课 6 [已完结] C+x64二叉树分析遍历与LUA自动登陆教程 19课
7 [已完结] C++BT功能原理与x64实战教程 29课 8 [已完结] C+FPS框透视与自瞄x64实现原理及防护思路
查看: 5118|回复: 0

C++ 实现动态资源文件释放

[复制链接]

20

主题

1

回帖

31

积分

编程入门

Rank: 1

龙马币
96

当我们开发Windows应用程序时,通常会涉及到使用资源(Resource)的情况。资源可以包括图标、位图、字符串等,它们以二进制形式嵌入到可执行文件中。在某些情况下,我们可能需要从可执行文件中提取自定义资源并保存为独立的文件。在这篇博客文章中,我们将讨论如何使用C++和WinAPI实现这个目标。

简介
首先,让我们考虑一个场景:我们有一个 Windows 应用程序,其中包含了一个自定义的二进制资源比如默认的配置文件,我们希望将这个资源提取出来并保存为一个独立的文件以用于初始化程序配置项。为了实现这个目标,我们可以使用Windows API提供的相关函数,来完成对资源的释放工作。

关键函数概述
GetModuleHandle

该函数用于获取指定模块的句柄。模块可以是一个可执行文件(例如 .exe 文件)或一个动态链接库(例如 .dll 文件)。该函数返回指定模块的实例句柄,以便在后续的操作中使用。

以下是 GetModuleHandle 函数的一般形式:
  1. HMODULE GetModuleHandle(
  2.   LPCTSTR lpModuleName
  3. );
复制代码

参数说明:

lpModuleName:指定要获取句柄的模块的名称。如果为 NULL,则返回调用线程的可执行模块句柄。
在许多情况下,GetModuleHandle 主要用于获取当前进程的模块句柄,以便在后续的操作中使用该句柄。模块句柄通常用于在进程中查找资源、定位函数地址等目的。

FindResource

该函数用于定位并返回指定模块(通常是 .exe 或 .dll 文件)中的资源。资源可以是诸如位图、图标、对话框模板、字符串等等的数据。

以下是 FindResource 函数的一般形式:
HRSRC FindResource(
  HMODULE hModule,
  LPCTSTR lpName,
  LPCTSTR lpType
);
参数说明:

hModule:指定包含资源的模块的句柄。如果为 NULL,则表示使用当前可执行模块的句柄。
lpName:指定资源的名称或标识符。可以是字符串或整数标识符。
lpType:指定资源的类型。通常是一个字符串,如 "RT_BITMAP" 表示位图资源。
如果找到,则返回指向资源的句柄(HRSRC)。这个句柄可以用于后续的资源加载和操作,函数的第二个参数经常配合MAKEINTRESOURCE一起使用,MAKEINTRESOURCE 是一个宏(macro),用于将整数标识符(ID)转换为字符串指针。在 Windows 编程中,通常用于标识资源的 ID。

  1. #define MAKEINTRESOURCE(i) ((LPCTSTR)((DWORD)((WORD)(i))))
复制代码

这个宏接受一个整数参数 i,然后将其转换为字符串指针。在资源标识符上下文中,通常将整数标识符转换为字符串是为了在使用相关资源函数时传递正确的参数。

举个例子,如果有一个字符串资源的标识符是 IDR_MYSTRING,则可以使用 MAKEINTRESOURCE 将其转换为字符串:

  1. LPCTSTR pszResourceName = MAKEINTRESOURCE(IDR_MYSTRING);
复制代码

在这里,pszResourceName 将指向字符串 "IDR_MYSTRING"。

在前面提到的 FindResource 中,通常将 MAKEINTRESOURCE(IDR_MYSTRING) 作为 lpName 参数传递给 FindResource。这是因为 FindResource 函数期望资源名称是字符串类型,而 IDR_MYSTRING 可能是一个整数标识符。通过使用 MAKEINTRESOURCE,则可以将整数标识符转换为字符串,以便正确地在资源中查找。

SizeofResource

该函数用于获取指定资源的大小。它返回资源的字节数,可以用于确定加载资源所需的内存大小。

以下是 SizeofResource 函数的一般形式:
  1. DWORD SizeofResource(
  2.   HMODULE hModule,
  3.   HRSRC   hResInfo
  4. );
复制代码

参数说明:

hModule:指定包含资源的模块的句柄。如果为 NULL,则表示使用当前可执行模块的句柄。
hResInfo:指定资源的句柄,通常由 FindResource 返回。
SizeofResource 返回资源的大小,以字节为单位。这个函数在加载资源之前可以用来分配足够的内存空间。

LoadResource

该函数用于加载指定资源的数据。该函数返回一个全局内存块的句柄,该内存块包含了资源的实际数据,你可以通过 LockResource 函数获取该内存块的指针来访问资源数据。

以下是 LoadResource 函数的一般形式:
  1. HGLOBAL LoadResource(
  2.   HMODULE hModule,
  3.   HRSRC   hResInfo
  4. );
复制代码

参数说明:

hModule:指定包含资源的模块的句柄。如果为 NULL,则表示使用当前可执行模块的句柄。
hResInfo:指定资源的句柄,通常由 FindResource 返回。
LoadResource 用于将资源数据加载到全局内存块中,并返回该内存块的句柄。在加载资源后,可以使用 LockResource 函数获取指向资源数据的指针。

LockResource

用于获取指定资源的数据指针。它接受一个全局内存块的句柄,该内存块通常由 LoadResource 函数返回,然后返回一个指向资源数据的指针。

以下是 LockResource 函数的一般形式:
  1. LPVOID LockResource(
  2.   HGLOBAL hResData
  3. );
复制代码

参数说明:

hResData:指定资源数据的全局内存块句柄,通常由 LoadResource 函数返回。
LockResource 用于锁定指定资源的全局内存块,并返回指向资源数据的指针。请注意,这个函数实际上并不执行拷贝,而是返回指向内存块的指针,因此对返回指针的任何修改都会直接影响到内存块本身。

FreeResource

用于释放由 LoadResource 函数加载的资源。这个函数通常用于释放不再需要的资源,以防止资源泄漏。

以下是 FreeResource 函数的一般形式:
  1. BOOL FreeResource(
  2.   HGLOBAL hResData
  3. );
复制代码

参数说明:

hResData:指定要释放的全局内存块句柄,通常由 LoadResource 函数返回。
FreeResource 用于释放之前由 LoadResource 加载的资源。请注意,这个函数通常在资源的生命周期结束时调用,以确保释放资源占用的内存。但在实际应用中,现代 Windows 应用通常不需要显式调用 FreeResource,因为 Windows 会在程序退出时自动释放资源。

在实际的应用程序中,FindResource 可以与 LoadResource 和 LockResource 等函数一起使用,用于加载和操作资源数据。当数据资源被加载到内存之后则可以直接通过fwrite函数将其直接写出到磁盘中,以此来实现释放资源的目的。

代码功能实现
首先新建一个控制台程序以作为本次的测试环境,接着准备好我们需要写出的数据,这里就准备一个lyshark.ini配置文件,在项目中右键选择添加并添加资源,此时会弹出如下图所示的提示信息;
001.png

此时会弹出添加资源菜单,通过点击导入按钮并输入资源类型为LYSHARK点击确定保存这个更改,如下图所示;
002.png

此时我们在主程序中引入#include "resource.h"包含资源头文件,并修改FindResource中的特定位置使其指向我们导入的配置文件,在释放时同样需要保持fopen("map\\lyshark.ini", "wb+")配置文件的格式。
004.png

这段资源释放的完整代码如下所示;

  1. #define _CRT_SECURE_NO_WARNINGS
  2. #include <Windows.h>
  3. #include <iostream>
  4. #include <WinUser.h>
  5. #include "resource.h"

  6. BOOL UseCustomResource()
  7. {
  8.         // 定位我们的自定义资源
  9.         HMODULE hModule = GetModuleHandle(NULL);
  10.         if (hModule == NULL)
  11.         {
  12.                 std::cerr << "错误:获取模块句柄失败。" << std::endl;
  13.                 return FALSE;
  14.         }

  15.         HRSRC hRsrc = FindResource(hModule, MAKEINTRESOURCE(IDR_LYSHARK1), TEXT("LYSHARK"));
  16.         if (hRsrc == NULL)
  17.         {
  18.                 std::cerr << "错误:无法找到资源。" << std::endl;
  19.                 return FALSE;
  20.         }

  21.         // 获取资源大小
  22.         DWORD dwSize = SizeofResource(hModule, hRsrc);
  23.         if (dwSize == 0)
  24.         {
  25.                 std::cerr << "错误:无效的资源大小。" << std::endl;
  26.                 return FALSE;
  27.         }

  28.         // 加载资源
  29.         HGLOBAL hGlobal = LoadResource(hModule, hRsrc);
  30.         if (hGlobal == NULL)
  31.         {
  32.                 std::cerr << "错误:无法加载资源。" << std::endl;
  33.                 return FALSE;
  34.         }

  35.         // 锁定资源
  36.         LPVOID lpVoid = LockResource(hGlobal);
  37.         if (lpVoid == NULL)
  38.         {
  39.                 std::cerr << "错误:无法锁定资源。" << std::endl;
  40.                 FreeResource(hGlobal);  // 在返回前释放资源
  41.                 return FALSE;
  42.         }

  43.         // 如果不存在,创建一个“map”目录
  44.         if (!CreateDirectory("map", NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
  45.         {
  46.                 std::cerr << "错误:无法创建目录。" << std::endl;
  47.                 FreeResource(hGlobal);
  48.                 return FALSE;
  49.         }

  50.         // 将资源写入文件
  51.         FILE* fp = fopen("map\\lyshark.ini", "wb+");
  52.         if (fp == NULL)
  53.         {
  54.                 std::cerr << "错误:无法创建或打开文件。" << std::endl;
  55.                 FreeResource(hGlobal);
  56.                 return FALSE;
  57.         }

  58.         fwrite(lpVoid, sizeof(char), dwSize, fp);
  59.         fclose(fp);

  60.         // 释放资源
  61.         FreeResource(hGlobal);

  62.         return TRUE;
  63. }

  64. int main(int argc, char* argv[])
  65. {
  66.         BOOL ref = UseCustomResource();
  67.         std::cout << "释放状态: " << ref << std::endl;

  68.         system("pause");
  69.         return 0;
  70. }
复制代码

以管理员模式运行上述程序,并等待,此时会释放一个目录并包含一个配置文件,如下图所示的输出结果;
003.png

结语
通过以上的代码实现,我们成功地将自定义资源提取并保存为一个独立的文件。这种技术在一些特殊情况下可能会很有用,例如需要动态加载或替换资源的情况。希望这篇博客对你理解如何使用 C++ 和 Windows API 进行资源操作有所帮助。

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

龙马谷| C/C++辅助教程| 安卓逆向安全| 论坛导航| 免责申明|Archiver|
拒绝任何人以任何形式在本论坛发表与中华人民共和国法律相抵触的言论,本站内容均为会员发表,并不代表龙马谷立场!
任何人不得以任何方式翻录、盗版或出售本站视频,一经发现我们将追究其相关责任!
我们一直在努力成为最好的编程论坛!
Copyright© 2018-2021 All Right Reserved.
在线客服
快速回复 返回顶部 返回列表