将多个文件合并成一个最终可执行文件,运行这个最终合成文件后,就相当于运行了合并前的多个文件,这种程序在木马或后门程序合并中会经常用到,你想知道它是怎么用程序实现的么?下面我就用VC6做的一个文件捆绑器的例子来告诉你。
其实文件捆绑器的构成思想非常简单:合并文件时,建立一个新的二进制文件,先写入你的自身捆绑程序的数据和文件长度,再写入你要捆绑的第一个文件的数据和其文件长度,跟着写入你要捆绑的第二个文件的数据和文件长度……最后直接写入你要捆绑的最后一个文件的数据(不需其文件长度)。分解释放最终合成文件时,将上面的方法倒过来既可:打开最终合成文件,读取源自身捆绑程序文件长度,将文件指针移到自身捆绑程序数据后,读取第一个被绑定文件的长度,接着读取其长度的文件数据并写入到一新建文件1中,再读取第二个被绑定文件的长度,接着读取其长度的数据并写入到新建文件2中……直到最后直接读取最后一个被绑定文件的数据并将其写入到最后一个新建文件中既可(下面实例仅告诉你如何实现两个文件的捆绑,至于多个文件的捆绑,读者只需略加改动既可,详情请查看配套光盘中的实例代码。)
下面我来讲讲文件捆绑最核心的部分,以及如何具体将其用代码来实现的方法(文章尽量采取行行注释的方法,希望每个读者朋友都能看懂)。 捆绑多个文件为一个可执行程序
先得到自身捆绑程序的文件长度和第一个要捆绑文件的文件长度,枚举第一个要捆绑文件有无图标,有的话就用它做为最终生成文件的图标,否则用自身捆绑程序所带默认图标做最终生成文件的图标。在新建二进制文件中写入自身捆绑程序的数据和其文件长度,再写入第一个要捆绑文件的数据及其文件长度,最后直接写入第二个文件的数据既可。
下面是合并程序函数的具体代码实现如下:
//定义要使用到的捆绑程序自身文件信息的结构体
struct MODIFY_DATA {
unsigned int finder; // 常量(定位自身)
_off_t my_length; //文件长度(自身)
} modify_data = {0x12345678, 0};
//绑定二个文件为一个可执行文件
bool CBindFileDlg::Bind_Files()
{
FILE* myself; //自身文件
FILE* out; //最终合成文件
FILE* in; //待绑定文件
int bytesin; //一次读文件字节数
int totalbytes = 0; //读出文件总字节数
struct _stat ST; //文件的状态信息(如文件长度等)
unsigned int finder = 0x12345678; //自身文件定位
unsigned int i, k;
int l=1; //进度条状态显示变量
char buff[20]; //进度条状态显示变量
his_name = strFirstFilePath; //第一个绑定的文件名
_stat(my_name, &ST); //获取自身捆绑文件信息
modify_data.my_length = ST.st_size; //得到自身文件长度
if (modify_data.my_length == 0)
{
MessageBox("绑定文件中,自身文件长度为零时出错!","错误");
return false;
}
buf = (BYTE *)malloc(modify_data.my_length); //分配一定大小缓冲区
if (buf == NULL)
{
MessageBox("绑定文件中,分配自身文件长度时出错!","错误");
return false;
}
myself = fopen(my_name, "rb"); //打开自身文件
if (myself == NULL)
{
free(buf);
MessageBox("绑定文件中,打开自身文件时出错!","错误");
return false;
}
//先读取捆绑程序自身文件数据
bytesin = fread(buf, 1, modify_data.my_length, myself);
fclose(myself);
if (bytesin != modify_data.my_length)
{
free(buf);
MessageBox("绑定文件中,不能完全读取自身文件内容时出错!","错误"
);
return false;
}
//存储自身文件信息到缓冲区(如长度)
for (i = 0; i < modify_data.my_length - sizeof(finder); i += sizeof(finder))
{
for (k = 0; k < sizeof(finder); k++)
{
if (buf[i+k] != ((BYTE*)&finder)[k])
break;
}
if (k == sizeof(finder)) //定位并保存自身数据文件信息
{
memcpy(buf+ i, &modify_data, sizeof(modify_data));
break;
}
}
if (i >= modify_data.my_length - sizeof(finder))
{
free(buf);
MessageBox("绑定文件中,不能定位自身文件时出错!","错误");
return false;
}
//获取第一个要绑定文件的信息(文件长度)
if (_stat(strFirstFilePath, &ST) != 0 || ST.st_size == 0)
{
free(buf);
MessageBox("绑定文件中,读取第一个要绑定文件时出错!","错误");
return false;
}
//获取自身文件图标及第一个要绑定文件的图标(如第一个要绑定文件没有图标,
//则用自身文件图标。其涵数实现请参看例程)
list_my_icons();
out = fopen(strFinalFilePath, "wb"); //创建最终合成文件
if (out == NULL)
{
free(buf);
MessageBox("绑定文件中,创建绑定后生成的合成文件时出错!","错误");
return false;
}
//先将前面读出的自身捆绑程序的数据写入最终合成文件中
totalbytes += fwrite(buf, 1, bytesin, out);
in = fopen(strFirstFilePath, "rb"); //打开第一个要绑定的文件
if (in == NULL)
{
free(buf);
MessageBox("绑定文件中,打开第一个要绑定文件时出错!","错误");
return false;
}
//写入第一个要绑定文件的长度到最终合成文件中
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); //关闭第一个绑定文件句柄
//设置进度条显示
m_Progress.SetRange(0,500);
for (int m = 0; m < 500; m++)
m_Progress.SetPos(m);
m_Parts = _ltoa(l, buff, 10);
m_Parts += _T("个文件已绑定");
UpdateData(FALSE);
l++;
in = fopen(strSecondFilePath, "rb"); //打开第二个要绑定的文件
if (in == NULL)
{
free(buf);
MessageBox("绑定文件中,打开第二个要绑定文件时出错!","错误");
return false;
}
//直接写入第二个要绑定文件的数据到最终合成文件中
while (bytesin = fread(buf, 1, modify_data.my_length, in))
{
totalbytes += fwrite(buf, 1, bytesin, out);
}
//设置进度条显示
m_Progress.SetRange(0,500);
for (int n = 0; n < 500; n++)
m_Progress.SetPos(n);
m_Parts = _ltoa(l, buff, 10);
m_Parts += _T("个文件已绑定");
UpdateData(FALSE);
l++;
fclose(in); //关闭第二个绑定文件句柄
fclose(out); //关闭最终合成文件句柄
free(buf); //释放缓冲区
return true;
} 释放最终合成文件
打开自身文件,从中得到自身捆绑程序的文件长度,便可将文件指针定位到第一个被捆绑文件的位置,读取其文件长度和其数据,将读出的数据写入第一个新建文件中。同样,通过已读取的自身捆绑程序文件长度和第一个被捆绑文件的文件长度加上保存这两个文件长度值的字节数,便可以准确定位第二个被捆绑文件的位置,读取其数据,写入到第二个新建文件中。同时,运行这两个文件,最后再删除这两个文件既可。
释放最终合成文件的代码具体实现如下:
//创建分解文件后,运行各分解文件时的进程
void CBindFileDlg::Create_Process(const char* temp_exe, BOOL async)
{
HANDLE hProcess; //进程句柄
HANDLE hThread; //线程句柄
PROCESS_INFORMATION PI;