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,否则程序一启动就会报错。
测试代码文档如下:
浙公网安备 33010602011771号