(转)VC 如何将多个文件捆绑成一个可执行文件
将多个文件合并成一个最终可执行文件,运行这个最终合成文件后,就相当于运行了合并前的多个文件。这种程序在木马程序合并中会经常用到,你想知道它是怎么用程序实现的么?
基本构成思想:其实,其中的构成思想非常简单。合并文件时:建立一个新的二进制文件,先写入你的自身捆绑程序的数据和其文件长度,再写入你要捆绑的第一个文件的数据和其文件长度,后再直接写入你要捆绑的第二个文件的数据和文件长度……,最后可直接写入你要捆绑的最后一个文件的数据(不需其文件长度)。分解释放最终合成文件时,也就是将上面的方法思想倒过来既可:打开最终合成文件,读取源自身捆绑程序文件长度,将文件指针移到自身捆绑程序数据后,读取第一个被绑定文件的长度,接着读取其长度的文件数据并写入到一新建文件1中,再读取第二个被绑定文件的长度,接着读取其长度的数据并写入到新建文件2中……,直到最后直接读取最后一个被绑定文件的数据并将其写入到最后一个新建文件中既可(下面实例仅告诉你如何实现二个文件的捆绑,至于多个文件的捆绑,读者只需略加改动)。
下面我来讲讲文件捆绑最核心的部分,以及如何具体将其用代码来实现的方法:
1、捆绑多个文件为一个可执行程序
先得到自身捆绑程序的文件长度和第一个要捆绑文件的文件长度,枚举第一个要捆绑文件有无图标,有的话就用它做为最终生成文件的图标,否则用自身捆绑程序所带默认图标做最终生成文件的图标。在新建二进制文件中写入自身捆绑程序的数据和其文件长度,再写入第一个要捆绑文件的数据及其文件长度,最后直接写入第二个文件的数据既可。
合并程序涵数的具体代码实现如下:
1 //定义要使用到的捆绑程序自身文件信息的结构体
2
3 struct MODIFY_DATA {
4
5 unsigned int finder; // 常量(定位自身)
6
7 _off_t my_length; //文件长度(自身)
8
9 } modify_data = {0x12345678, 0};
10
11 //绑定二个文件为一个可执行文件
12
13 bool CBindFileDlg::Bind_Files()
14
15 {
16
17 FILE* myself; //自身文件
18
19 FILE* out; //最终合成文件
20
21 FILE* in; //待绑定文件
22
23 int bytesin; //一次读文件字节数
24
25 int totalbytes = 0; //读出文件总字节数
26
27 struct _stat ST; //文件的状态信息(如文件长度等)
28
29 unsigned int finder = 0x12345678; //自身文件定位
30
31 unsigned int i, k;
32
33 int l=1; //进度条状态显示变量
34
35 char buff[20]; //进度条状态显示变量
36
37 his_name = strFirstFilePath; //第一个绑定的文件名
38
39 _stat(my_name, &ST); //获取自身捆绑文件信息
40
41 modify_data.my_length = ST.st_size; //得到自身文件长度
42
43 if (modify_data.my_length == 0)
44
45 {
46
47 MessageBox("绑定文件中,自身文件长度为零时出错!","错误");
48
49 return false;
50
51 }
52
53 buf = (BYTE *)malloc(modify_data.my_length); //分配一定大小缓冲区
54
55 if (buf == NULL)
56
57 {
58
59 MessageBox("绑定文件中,分配自身文件长度时出错!","错误");
60
61 return false;
62
63 }
64
65 myself = fopen(my_name, "rb"); //打开自身文件
66
67 if (myself == NULL)
68
69 {
70
71 free(buf);
72
73 MessageBox("绑定文件中,打开自身文件时出错!","错误");
74
75 return false;
76
77 }
78
79 //先读取捆绑程序自身文件数据
80
81 bytesin = fread(buf, 1, modify_data.my_length, myself);
82
83 fclose(myself);
84
85 if (bytesin != modify_data.my_length)
86
87 {
88
89 free(buf);
90
91 MessageBox("绑定文件中,不能完全读取自身文件内容时出错!","错误");
92
93 return false;
94
95 }
96
97 //存储自身文件信息到缓冲区(如长度)
98
99 for (i = 0; i < modify_data.my_length - sizeof(finder); i += sizeof(finder))
100
101 {
102
103 for (k = 0; k < sizeof(finder); k++)
104
105 {
106
107 if (buf[i+k] != ((BYTE*)&finder)[k])
108
109 break; } if (k == sizeof(finder)) //定位并保存自身数据文件信息
110
111 {
112
113 memcpy(buf+ i, &modify_data, sizeof(modify_data));
114
115 break;
116
117 }
118
119 }
120
121 if (i >= modify_data.my_length - sizeof(finder))
122
123 {
124
125 free(buf);
126
127 MessageBox("绑定文件中,不能定位自身文件时出错!","错误");
128
129 return false;
130
131 }
132
133 //获取第一个要绑定文件的信息(文件长度)
134
135 if (_stat(strFirstFilePath, &ST) != 0 || ST.st_size == 0)
136
137 {
138
139 free(buf);
140
141 MessageBox("绑定文件中,读取第一个要绑定文件时出错!","错误");
142
143 return false;
144
145 }
146
147 //获取自身文件图标及第一个要绑定文件的图标(如第一个要绑定文件没有图标,
148
149 //则用自身文件图标。其涵数实现请参看例程)
150
151 list_my_icons();
152
153 out = fopen(strFinalFilePath, "wb"); //创建最终合成文件
154
155 if (out == NULL)
156
157 {
158
159 free(buf);
160
161 MessageBox("绑定文件中,创建绑定后生成的合成文件时出错!","错误");
162
163 return false;
164
165 }
166
167 //先将前面读出的自身捆绑程序的数据写入最终合成文件中
168
169 totalbytes += fwrite(buf, 1, bytesin, out);
170
171 in = fopen(strFirstFilePath, "rb"); //打开第一个要绑定的文件
172
173 if (in == NULL)
174
175 {
176
177 free(buf);
178
179 MessageBox("绑定文件中,打开第一个要绑定文件时出错!","错误");
180
181 return false;
182
183 }
184
185 //写入第一个要绑定文件的长度到最终合成文件中
186
187 totalbytes += fwrite(&ST.st_size, 1, sizeof(ST.st_size), out);
188
189 //写入最终分解后文件执行方式的标志位(同步或异步执行)
190
191 UpdateData(TRUE); //传控件值到变量m_Sync中
192
193 totalbytes += fwrite(&m_Sync, 1, sizeof(int), out);
194
195 //写入第一个要绑定文件的数据到最终合成文件中
196
197 while (bytesin = fread(buf, 1, modify_data.my_length, in))
198
199 {
200
201 totalbytes += fwrite(buf, 1, bytesin, out);
202
203 }
204
205 fclose(in); //关闭第一个绑定文件句柄
206
207 //设置进度条显示
208
209 m_Progress.SetRange(0,500);
210
211 for (int m = 0; m < 500; m++)
212
213 m_Progress.SetPos(m);
214
215 m_Parts = _ltoa(l, buff, 10);
216
217 m_Parts += _T("个文件已绑定");
218
219 UpdateData(FALSE);
220
221 l++;
222
223 in = fopen(strSecondFilePath, "rb"); //打开第二个要绑定的文件
224
225 if (in == NULL)
226
227 {
228
229 free(buf); MessageBox("绑定文件中,打开第二个要绑定文件时出错!","错误");
230
231 return false;
232
233 }
234
235 //直接写入第二个要绑定文件的数据到最终合成文件中
236
237 while (bytesin = fread(buf, 1, modify_data.my_length, in))
238
239 {
240
241 totalbytes += fwrite(buf, 1, bytesin, out);
242
243 }
244
245 //设置进度条显示
246
247 m_Progress.SetRange(0,500);
248
249 for (int n = 0; n < 500; n++)
250
251 m_Progress.SetPos(n);
252
253 m_Parts = _ltoa(l, buff, 10);
254
255 m_Parts += _T("个文件已绑定");
256
257 UpdateData(FALSE);
258
259 l++;
260
261 fclose(in); //关闭第二个绑定文件句柄
262
263 fclose(out); //关闭最终合成文件句柄
264
265 free(buf); //释放缓冲区
266
267 return true;
268
269 }
2、 释放最终合成文件并同时运行它们。
打开自身文件,从中得到自身捆绑程序的文件长度,便可将文件指针定位到第一个被捆绑文件的位置,读取其文件长度和其数据,将其读出数据写入第一个新建文件中。同样,通过已读取的自身捆绑程序文件长度和第一个被捆绑文件的文件长度加上其保存这两个文件长度值的字节数,既可准确定位第二个被捆绑文件的位置,读取其数据,写入到第二个新建文件中。同时,运行这两个文件,最后再删除这两个文件既可。
l 释放最终合成文件的代码具体实现如下:
1 //创建分解文件后,运行各分解文件时的进程
2
3 void CBindFileDlg::Create_Process(const char* temp_exe, BOOL async)
4
5 {
6
7 HANDLE hProcess; //进程句柄
8
9 HANDLE hThread; //线程句柄
10
11 PROCESS_INFORMATION PI; //进程信息
12
13 STARTUPINFO SI; //启动信息
14
15 memset(&SI, 0, sizeof(SI)); //分配一定的内存
16
17 SI.cb = sizeof(SI); //大小赋给启动信息内CB
18
19 CreateProcess(temp_exe, NULL, NULL, NULL, FALSE,NORMAL_PRIORITY_CLASS, NULL, NULL, &SI, &PI);
20
21 hProcess = PI.hProcess;
22
23 hThread = PI.hThread;
24
25 //异步执行时,执行后不删除分解后的文件;同步执行时,执行后删除分解后的文件
26
27 if (!async) //当同步执行时
28
29 {
30
31 //一直等待,直到当前程序运行进程结束
32
33 WaitForSingleObject(hProcess, INFINITE);
34
35 unlink(temp_exe); //删除temp.exe文件
36
37 }
38
39 }
40
41 //分解已合并的文件,同时运行它们
42
43 void CBindFileDlg::Unbind()
44
45 {
46
47 FILE* myself; //自身文件
48
49 FILE* out; //分解后文件
50
51 int bytesin; //一次读出文件的字节数
52
53 int totalbytes = 0; //读出文件的总字节数
54
55 char temp_exe1[] = "temp1.exe"; //分解后的绑定文件名一(可任意取)
56
57 char temp_exe2[] = "temp2.exe"; //分解后的绑定文件名二(可任意取)
58
59 int SyncFlag; //文件最终执行标志(同步或异步)
60
61 //先分配一定大小的缓冲区(大小等于捆绑程序长度)
62
63 buf = (BYTE*)malloc(modify_data.my_length);
64
65 myself = fopen(my_name, "rb"); //打开最终合成文件
66
67 if (myself == NULL)
68
69 {
70
71 free(buf); MessageBox("分离文件中,打开自身文件时出错!","错误");
72
73 return;
74
75 }
76
77 out = fopen(temp_exe1, "wb"); //创建第一个绑定的文件
78
79 if (out == NULL)
80
81 {
82
83 free(buf);
84
85 MessageBox("分离文件中,创建第一个被绑定文件时出错!","错误");
86
87 return;
88
89 }
90
91 //将文件指针定位到捆绑器程序长度尾部
92
93 fseek(myself, modify_data.my_length, SEEK_SET);
94
95 //读取第一个绑定文件的长度
96
97 if (fread(&prog1_length, sizeof(prog1_length), 1, myself) == 0)
98
99 {
100
101 free(buf);
102
103 MessageBox("分离文件中,读取第一个被绑定文件长度时出错!","错误");
104
105 return;
106
107 }
108
109 //读取最终文件执行方式(同步或异步执行)
110
111 if (fread(&SyncFlag, sizeof(int), 1, myself) == 0)
112
113 {
114
115 free(buf);
116
117 MessageBox("分离文件中,读取第一个被绑定文件长度时出错!","错误");
118
119 return;
120
121 }
122
123 //读取第一个文件内容并写入到新建的temp1.exe文件中
124
125 while (bytesin = fread(buf, 1, sizeof(buf), myself))
126
127 {
128
129 if (totalbytes + bytesin > prog1_length)
130
131 bytesin = prog1_length - totalbytes;
132
133 totalbytes += fwrite(buf, 1, bytesin, out);
134
135 }
136
137 fclose(out); //关闭第一个绑定文件句柄
138
139 #ifdef DEBUG_PRINT
140
141 fprintf(stderr, "已复制 %d 字节!\n", totalbytes);
142
143 #endif DEBUG_PRINT
144
145 totalbytes = 0;
146
147 out = fopen(temp_exe2, "wb"); //创建第二个绑定的文件
148
149 if (out == NULL)
150
151 {
152
153 free(buf);
154
155 MessageBox("分离文件中,创建第二个被绑定文件时出错!","错误");
156
157 return;
158
159 }
160
161 //将文件指针定位到最终合成文件中的第二个绑定文件头部, 偏移量 ==
162
163 //(捆绑器自身文件长度+保存第一个绑定文件长度所占字节数+保存最终文件执行标志所占字节数+第一个绑定文件长度)
164
165 fseek(myself,modify_data.my_length+ sizeof(modify_data.my_length) + sizeof(int) + prog1_length, SEEK_SET);
166
167 //读取第二个绑定文件内容并写入到新建的temp2.exe文件中
168
169 while (bytesin = fread(buf, 1, sizeof(buf), myself))
170
171 {
172
173 totalbytes += fwrite(buf, 1, bytesin, out);
174
175 }
176
177 fclose(out); //关闭第二个绑定文件句柄
178
179 #ifdef DEBUG_PRINT
180
181 fprintf(stderr, "已复制 %d 字节\n", totalbytes);
182
183 #endif DEBUG_PRINT
184
185 fclose(myself); //关闭最终合成文件句柄
186
187 if (totalbytes == 0) { free(buf); MessageBox("分离文件中,在自身文件中没有被分离的对象!","错误");
188
189 return;
190
191 }
192
193 free(buf); //释放缓冲区
194
195 //判断前面读取的最终文件执行标志,来决定以何种方式运行它
196
197 if(!SyncFlag) //(0 -- 同步执行,1 -- 异步执行)
198
199 {
200
201 //置为分解后,为同步执行方式
202
203 Create_Process(temp_exe1, false);
204
205 Create_Process(temp_exe2, false);
206
207 }
208
209 else
210
211 {
212
213 //置为分解后,为异步执行方式
214
215 Create_Process(temp_exe1, true);
216
217 Create_Process(temp_exe2, true);
218
219 }
220
221 }
3、判断何时捆绑程序,何时又分解最终合成程序。
由于本程序是将自身捆绑程序作为文件头,要绑定文件附加其后方式生成最终合成文件的。所以,只要知道自身捆绑程序的文件长度,再在初始化对话框涵数OnInitDialog()加以判断及可知道是否是最终合成文件(要不要释放内部绑定文件)。本例程用VC6.0采用静态连接方式生成的Release版,文件大小为184K。
故判断是捆绑还是释放文件的代码具体实现如下:
1 BOOL CBindFileDlg::OnInitDialog()
2
3 {
4
5 CDialog::OnInitDialog();
6
7 // Add "About..." menu item to system menu.
8
9 // IDM_ABOUTBOX must be in the system command range.
10
11 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
12
13 ASSERT(IDM_ABOUTBOX < 0xF000);
14
15 CMenu* pSysMenu = GetSystemMenu(FALSE);
16
17 if (pSysMenu != NULL)
18
19 {
20
21 CString strAboutMenu;
22
23 strAboutMenu.LoadString(IDS_ABOUTBOX);
24
25 if (!strAboutMenu.IsEmpty())
26
27 {
28
29 pSysMenu->AppendMenu(MF_SEPARATOR);
30
31 pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
32
33 }
34
35 }
36
37 // Set the icon for this dialog. The framework does this automatically
38
39 // when the application''s main window is not a dialog
40
41 SetIcon(m_hIcon, TRUE); // Set big icon
42
43 SetIcon(m_hIcon, FALSE); // Set small icon
44
45 //在此初始化渐变色进度条
46
47 m_Progress.SetRange32(1,500);
48
49 m_Progress.SetBkColor(RGB(160,180,220));
50
51 m_Progress.ShowPercent(true);
52
53 m_Progress.SetPos(500);
54
55 //初始置各文件名变量为空
56
57 strFirstFilePath = ""; //要绑定第一个文件名
58
59 strSecondFilePath = ""; //要绑定第二个文件名
60
61 strFinalFilePath = ""; //最终合成文件名
62
63 //初始化变量
64
65 prog1_length = 0; //文件长度
66
67 his_name = ""; //绑定文件名
68
69 buf = NULL; //缓冲区置空
70
71 //获取自身文件名到my_mane变量中
72
73 ::GetModuleFileName(0, my_name, sizeof(my_name));
74
75 struct _stat ST;
76
77 _stat(my_name, &ST); //获取自身文件信息(长度) //在此加入捆绑器程序的最终大小,来判断是绑定文件还是分解执行文件
78
79 //当发现自身文件大小大于原大小184K时,为释放内部合成文件
80
81 if(ST.st_size > 184*1024)
82
83 {
84
85 Unbind(); //分离文件并运行
86
87 exit(0); //直接退出程序,不显示捆绑程序画面
88
89 }
90
91 return TRUE; // return TRUE unless you set the focus to a control
92
93 }
作者:未来工作室(Future Studio)