irc

彼节者有间,而刀刃者无厚;以无厚入有间,恢恢乎其于游刃必有余地矣!

导航

VC简单文件生成

一、引言

对于许多应用程序来说,运行一个程序通常需要包含多个文件。但是有些环境或应用中,需要把所有程序包含文件整合成一个文件,以简化操作流程。

将多个文件合并成一个文件,实质上就是在编译程序是将多个文件整合成一个文件, 运行后先释放原文件到相应目录,再执行应用程序。

比如有一个程序需要一个DLL文件和一个EXE文件,我们可以把DLL文件包含到一个EXE文件中,运行EXE文件就会将原来的DLL文件释放到相应目录,程序就可以正常运行了。

本文将通过在程序中添加一个DLL文件资源,然后在程序运行时再释放该DLL文件的实例,介绍资源法释放文件的技术过程。程序代码在XP系统VS2008下编译通过。

二、功能与实现
2.1 PE文件资源
     PE文件中的资源包含了如图片、声音、视频等一些信息,计算机上任何以文件形式存在的数据都可以做成资源包含在PE文件中。这些资源可以在PE文件载入内存运行是被自身访问、修改。一般资源都包含在PE文件的.rsrc的节中。
      资源法生成文件,就是指通过编译在PE文件中的资源生成文件。

2.2 整体思路
     在编译EXE文件时,将DLL文件作为它的资源一起编译。编译EXE后,DLL文件就会以资源形式包含在EXE文件中。在EXE文件中添加新的代码,通过新代码释放资源中的DLL文件。需要注意的是,新添加的代码必须在调用DLL文件之前执行,具体实现过程如图1所示。

  图1
2.3 添加资源过程
1.首先打开VS2008,并打开所要修改程序的解决方案。选中需要修改的项目,点击右键,弹出菜单,选择添加资源如图2所示: 
 
图2
2.在弹出窗口中选择导入,如图3所示: 
 
图3
  3. 选择导入后,在弹出的导入对话框中的对象类型中选择所有文件,选中需要导入的文件,如图4所示:
 
图4
4.  选中文件后,点击确认,继续弹出自定义资源类型对话框,在资源类型中输入DLL或者其它自己认为合适的类型名称,确认既完成资源的添加。如图5所示: 
 
图5
这样就完成了资源添加工作,通过资源试图可以查看已添加成功的资源文件,默认添加后的资源ID名称为
DR_DLL1,如需要修改ID名称,可以通过右键点击属性来修改成自己想要的名称。
2.4 生成文件代码
2.4.1 所需要用的API函数
      在编写释放资源代码前,先介绍几个对资源进行操作的API函数。
1.  FindResource函数
功能:  寻找模块中的资源
原型: 
HRSRC FindResource( HMODULE hModule,  LPCTSTR lpName,  LPCTSTR lpType);
参数:  hModule    指向要查找的模块句柄,本进程NULL即可。
lpName    指向要查找的资源名称。(既本例中的ID_DLL1)
          lpType    指向要查找资源的类型。(既添加过程中输入的DLL)
返回:  函数调用成功,返回要查找的资源句柄,调用失败则返回NULL。
2.  LoadResource函数
功能:  载入指定资源到全局存储器
原型: 
HGLOSAL LoadResource(HMODULE hModule, HRSRC hResInfo);
参数:  hModule    同FindResource,指向要载入的模块句柄。
          hResInfo    指向被装载资源的句柄,又FindResource返回。
返回:  成功则返回相关资源句柄,失败则返回NULL。
3.  LockResource函数
功能:  锁定内存中的资源
原型: 
LPVOID LockResource(  HGLOBAL hResDate);
参数:  指向被装载的资源句柄,该参数由LoadResource函数返回。
返回:  成功则返回资源第一个字节的指针,调用失败返回NULL。
4.  SizeofResource函数
功能:  得到指定资源的字节数大小。
原型: 
DWORD SizeofResource( HMODULE hModule, HRSRC hResInfo);
参数:  hModule 和FindResource函数的第一个参数相同
          hResinfo 指向被装载资源的句柄,由FindResource函数返回。
返回:  成功则返回指定资源的字节数,失败则返回零。
2.4.2 释放文件实现流程
介绍所需要的API函数后,下面介绍释放文件流程。具体过程如图6所示: 
 
图6
2.4.3具体实现代码
按照图6所示流程,编写释放文件实现代码,可以把整个过程封装成一个函数。具体代码如下:

 1 BOOL ResourceToFile(TCHAR *szFilename, TCHAR *szName, TCHAR* szType)
 2 {
 3     // 寻找自身进程中的资源
 4     HRSRC hRes = FindResource(NULL, szName, szType);
 5     if(hRes == NULL)
 6         return FALSE;
 7 
 8     // 装载资源
 9     HGLOBAL hgRes = LoadResource(NULL, hRes);
10     if(hgRes == NULL)
11         return FALSE;
12 
13     // 锁定资源
14     LPVOID pRes = LockResource(hgRes);
15     if(pRes == NULL)
16         return FALSE;
17 
18     // 得到资源字数
19     DWORD dwSize = SizeofResource(NULL, hRes);
20     if(dwSize == 0)
21         return FALSE;
22 
23     // 创建文件
24     HANDLE hFile = CreateFile(szFilename,
25         GENERIC_WRITE,
26         0,
27         0,
28         CREATE_ALWAYS,
29         FILE_ATTRIBUTE_NORMAL,
30         0);
31     if(hFile == INVALID_HANDLE_VALUE)
32         return FALSE;
33 
34     // 把资源写入到文件
35     DWORD dwWritten;
36     if(!WriteFile(hFile, pRes, dwSize, &dwWritten, 0))
37         return FALSE;
38     // 关闭文件句柄
39     CloseHandle(hFile);
40     return TRUE;
41 } 


注意:有的资料上在装载资源后提到要用GlobalFree(hgRes)释放资源,使用LoadResource函数装载资源不需要释放。
该函数有三个参数,
第一个szFilename为生成文件名(带路径,最好是全路径),
第二个参数szName为资源ID,
第三个参数szType,为资源类型。使用起来非常方便,当然也可以根据个人需要修改,具体调用过程代码如下:

 1 // 得到程序自身路径
 2 GetCurrentDirectory(sizeof(szPath), szPath);
 3 
 4 _tcscat(szPath, "\HOOK.dll");   
 5 
 6 // 把资源导出成为文件
 7 if(!ResourceToFile(szPath, MAKEINTRESOURCE(IDR_DLL1), TEXT("DLL")))
 8 {
 9     ::MessageBox(NULL, "生成HOOK.dll错误……", "Error", MB_OK);
10 }
11 else
12 {
13     ::MessageBox(NULL, "生成HOOK.dll成功……", "TIPS", MB_OK);
14 }
15 
16 Sleep(15);

编译后运行该程序,既会在该程序目录下生成need.dll文件。本文为个人学习笔记,抄袭别人资料居多,没有太多技术含量,主要是为了加深印象,不当之处,请及时与本人联系。

主要参考书目:《精通黑客编程》HACK编程实例精讲II    作者:边立忠
三、注:
本文转自看雪论坛:
http://bbs.pediy.com/showthread.php?t=136360&referrerid=253426
经测试:释放文件是没什么问题
但调用dll的exe程序需要 延迟加载 该dll,否则程序一启动就会报错。

测试代码文档如下: 

posted on 2011-07-21 14:40  irc  阅读(280)  评论(0)    收藏  举报

Top