文件生成技术之资源法学习笔记
摘要:介绍文件生成技术。通过VC2008将应用程序所需多个文件合并成一个文件。
关键字:VC2008 文件生成 资源法
一、引言
对于许多应用程序来说,运行一个程序通常需要包含多个文件。但是有些环境或应用中,需要把所有程序包含文件整合成一个文件,以简化操作流程。
将多个文件合并成一个文件,实质上就是在编译程序是将多个文件整合成一个文件,
运行后先释放原文件到相应目录,再执行应用程序。比如有一个程序需要一个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名称为IDR_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所示流程,编写释放文件实现代码,可以把整个过程封装成一个函数。具体代码如下:
BOOL ResourceToFile(TCHAR *szFilename, TCHAR *szName, TCHAR* szType)
{
// 寻找自身进程中的资源
HRSRC hRes = FindResource(NULL, szName, szType);
if(hRes == NULL)
return FALSE;
// 装载资源
HGLOBAL hgRes = LoadResource(NULL, hRes);
if(hgRes == NULL)
return FALSE;
// 锁定资源
LPVOID pRes = LockResource(hgRes);
if(pRes == NULL)
return FALSE;
// 得到资源字数
DWORD dwSize = SizeofResource(NULL, hRes);
if(dwSize == 0)
return FALSE;
// 创建文件
HANDLE hFile = CreateFile(szFilename,
GENERIC_WRITE,
0,
0,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
0);
if(hFile == INVALID_HANDLE_VALUE)
return FALSE;
// 把资源写入到文件
DWORD dwWritten;
if(!WriteFile(hFile, pRes, dwSize, &dwWritten, 0))
return FALSE;
// 关闭文件句柄
CloseHandle(hFile);
return TRUE;
}
注意:有的资料上在装载资源后提到要用GlobalFree(hgRes)释放资源,使用LoadResource函数装载资源不需要释放。
该函数有三个参数,第一个szFilename为生成文件名(带路径,最好是全路径),第二个参数szName为资源ID,第三个参数szType,为资源类型。使用起来非常方便,当然也可以根据个人需要修改,具体调用过程代码如下:
int _tmain(int argc, _TCHAR* argv[])
{
TCHAR szPath[256];
CONFIGINFO info = {0};
// 得到程序自身路径
GetCurrentDirectory(sizeof(szPath), szPath);
// 得到生成文件名,带路径
_tcscat(szPath, L"\\need.dll");
// 把资源导出成为文件
if(!ResourceToFile(szPath, MAKEINTRESOURCE(IDR_DLL1), TEXT("DLL")))
{
_tprintf(L"generate need.dll error...\r\n");
return 0;
}
else
_tprintf(L"generate need.dll success...\r\n");
return 0;
}
编译后运行该程序,既会在该程序目录下生成need.dll文件。本文为个人学习笔记,抄袭别人资料居多,没有太多技术含量,主要是为了加深印象,不当之处,请及时与本人联系。
主要参考书目:
《精通黑客编程》HACK编程实例精讲II 作者:边立忠
[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。