如何将多个文件捆绑成一个可执行文件
作者:徐景周
下载示例程序代码(http://www.csdn.net/cnshare/soft/10/10356.shtm)
将多个文件合并成一个最终可执行文件,运行这个最终合成文件后,就相当于运行了合并前的多个文件。这种程序在木马程序合并中会经常用到,你想知道它是怎么用程序实现的么?下面我就拿我用VC6.0做的一个文件捆绑器的实例代码来告诉你,实例程序运行后的界面如下:
图例
基本构成思想:其实,文件捆绑的构成思想非常简单,它主要可分为合并文件和分解释放文件二大部分。合并文件时:建立一个新的二进制文件,先写入你的捆绑程序的自身数据和其文件长度,再写入你要捆绑的第一个文件的数据和其文件长度,后再直接写入你要捆绑的第二个文件的数据和其文件长度……,最后可直接写入你要捆绑的最后一个文件的数据(不再需要其文件长度)。分解释放最终合成文件时:也就是将上面的方法思想倒过来既可,打开最终合成文件,读取源捆绑程序自身文件长度,将文件指针移到捆绑程序自身数据后,读取第一个被绑定文件的长度,接着读取其后长度大小的一段文件数据并写入到一新建文件1中,再读取第二个被绑定文件的长度,接着读取其后长度大小的一段文件数据并写入到新建文件2中……,直到最后,就可直接读取最后一个被绑定文件的数据并将其写入到最后一个新建文件中既可。(下面实例代码仅告诉你如何实现二个文件的捆绑,至于多个文件的捆绑,读者只需按上面所说略加改动既可,实现详情请查看下载后的实例代码。)
下面我来讲讲文件捆绑最核心的部分,以及如何将其用代码来实现的方法:
1、 捆绑多个文件为一个可执行程序
思路:先获得捆绑程序自身的文件长度和第一个被捆绑文件的文件长度,枚举出第一个被捆绑文件的图标,有图标的话就用它做为最终生成文件的图标,否则就用捆绑程序自身所带图标做为最终生成文件的图标。然后,新建一个二进制文件,在其中写入捆绑程序自身的文件数据和其文件长度,接着写入第一个被捆绑文件的文件长度和最终合成文件的运行方式标志位(同步还是异步运行),紧接着再写入第一个被捆绑文件的文件数据,最后直接写入第二个被捆绑文件的文件数据既可。
l 合并程序涵数的具体代码实现如下:
//绑定二个文件为一个可执行文件
bool CBindFileDlg::Bind_Files()
{
…… (省略:此部分代码用来定义各成员变量)
his_name = strFirstFilePath; //第一个绑定的文件名
_stat(my_name, &ST); //获取自身捆绑文件信息
modify_data.my_length = ST.st_size; //得到自身文件长度
buf = (BYTE *)malloc(modify_data.my_length); //分配一定大小缓冲区
myself = fopen(my_name, "rb"); //打开自身文件
//先读取捆绑程序自身文件数据
bytesin = fread(buf, 1, modify_data.my_length, myself);
fclose(myself);
……(省略:此部分代码用来获取自身文件和第一个被捆绑文件长度,以及获取最终合成文件的图标)
out = fopen(strFinalFilePath, "wb"); //创建最终合成文件
//先将前面读出的自身捆绑程序的数据写入最终合成文件中
totalbytes += fwrite(buf, 1, bytesin, out);
in = fopen(strFirstFilePath, "rb"); //打开第一个要绑定的文件
//写入第一个要绑定文件的长度到最终合成文件中
totalbytes += fwrite(&ST.st_size, 1, sizeof(ST.st_size), out);
//写入最终分解后文件执行方式的标志位(同步或异步执行)
UpdateData(TRUE); //传控件值到变量m_Sync中
totalbytes += fwrite(&m_Sync, 1, sizeof(int), out);
//写入第一个要绑定文件的数据到最终合成文件中
while (bytesin = fread(buf, 1, modify_data.my_length, in))
{
totalbytes += fwrite(buf, 1, bytesin, out);
}
fclose(in); //关闭第一个绑定文件句柄
in = fopen(strSecondFilePath, "rb"); //打开第二个要绑定的文件
//直接写入第二个要绑定文件的数据到最终合成文件中
while (bytesin = fread(buf, 1, modify_data.my_length, in))
{
totalbytes += fwrite(buf, 1, bytesin, out);
}
……(省略:此部分代码用来关闭文件句柄)
}
2、 释放最终合成文件并同时运行它们。
思路:打开自身文件,从中得到捆绑程序自身的文件长度,将文件指针定位到捆绑程序自身数据后的第一个被捆绑文件的位置,读取其第一个被捆绑文件的文件长度和最终合成文件释放后的运行方式标志(同步还是异步方式执行),接着读取其第一个被捆绑文件的文件数据,将其读出数据直接写入到一个新建的二进制文件中。同样,通过已读取的捆绑程序自身文件长度和第一个被捆绑文件的文件长度再加上其保存这两个文件长度值的字节数及最终合成文件释放后的运行标志所占字节数,既可准确定位出第二个被捆绑文件的文件数据所在的指针位置,读取其文件数据后,直接写入到一个新建二进制文件中。最后,根据前面读出的文件释放后的运行标志,来决定以何种方式来运行释放的这两个文件,如果是同步方式,顺序运行后会删除这两个生成文件,异步方式则会同时运行而不会删除这二个生成文件。
l 释放最终合成文件的代码具体实现如下:
//分解已合并的文件,同时运行它们
void CBindFileDlg::Unbind()
{
……(省略掉:此部分代码主要用来定义成员变量)
myself = fopen(my_name, "rb"); //打开最终合成文件
out = fopen(temp_exe1, "wb"); //创建第一个释放的生成文件
//将文件指针定位到捆绑器程序尾部
fseek(myself, modify_data.my_length, SEEK_SET);
//读取第一个绑定文件的长度
fread(&prog1_length, sizeof(prog1_length), 1, myself);
//读取最终文件执行方式(同步或异步执行)
fread(&SyncFlag, sizeof(int), 1, myself) ;
//读取第一个文件内容并写入到新建的temp1.exe文件中
while (bytesin = fread(buf, 1, sizeof(buf), myself))
{
if (totalbytes + bytesin > prog1_length)
bytesin = prog1_length - totalbytes;
totalbytes += fwrite(buf, 1, bytesin, out);
}
fclose(out); //关闭第一个绑定文件句柄
totalbytes = 0; //重新清零
out = fopen(temp_exe2, "wb"); //创建第二个释放的生成文件
/*将文件指针定位到最终合成文件中的第二个绑定文件头部, 偏移量 ==(捆绑器自身文件长度+保存第一个绑定文件长度所占字节数+保存最终文件执行标志所占字节数+第一个绑定文件长度)*/
fseek(myself,modify_data.my_length+ sizeof(modify_data.my_length) + sizeof(int) + prog1_length, SEEK_SET);
//读取第二个绑定文件内容并写入到新建的temp2.exe文件中
while (bytesin = fread(buf, 1, sizeof(buf), myself))
{
totalbytes += fwrite(buf, 1, bytesin, out);
}
……(省略:此部分代码用来关闭文件句柄和决定生成文件的运行方式)
}
3、判断何时捆绑文件,何时又分解释放最终合成文件。
思路:由于本程序采用将捆绑程序自身直接作为最终合成文件的文件头,再把被绑定文件数据附加其后的方式来生成最终合成文件的。所以,只要知道捆绑程序自身的文件长度,根据文件长度是否大于原文件长度,就可判断出是否该释放分解文件了。可在初始化对话框涵数OnInitDialog()增加此判断,及可知道是否是最终合成文件(要不要释放内部绑定文件)。本例程用VC6.0采用静态连接方式生成的Release版,文件长度为184K,大于184K(184*1024)字节,既可判断出该做释放分解操作。
l 故判断是捆绑还是释放文件的代码具体实现如下:
BOOL CBindFileDlg::OnInitDialog()
{
……(省略:此部分代码用于初始化一些变量)
//获取自身文件名到my_mane变量中
::GetModuleFileName(0, my_name, sizeof(my_name));
struct _stat ST;
_stat(my_name, &ST); //获取自身文件信息(长度)
/*在此加入捆绑器程序的最终大小,来判断文件执行时是绑定文件还是分解执行文件当发现自身文件大小大于原大小184K时,为释放内部合成文件*/
if(ST.st_size > 184*1024)
{
Unbind(); //分离文件并运行
exit(0); //直接退出程序,不显示捆绑程序画面
}
}
以上部分代码的具体实现的细节问题,可在下载实例代码后,仔细查看源码既可(内有详细注释)。
联系方式:
地址:陕西省西安市劳动路2号院六单元
邮编:710082
作者EMAIL:jingzhou_xu@163.net
未来工作室(Future Studio)