原创:星绽紫辉(rawdata)http://www.cppblog.com/rawdata 2009-1-20
转载请注明出处
关键字: PE 增加 区段 section 文件格式
现在我要给一PE文件增加区段(section),但是增加区段后我不希望影响PE文件的正常使用,那么应该怎么
做呢?我写这个教程的目的,希望能帮学习PE格式,当然也作为我以后参考的笔记。
简单地说:PE文件和普通文件没有什么区别,只是存在格式上的差异。另外,当你双击某个.exe文件
时,Windows Shell 程序将会尝试解析文件并运行它的PE代码。所以第一步,你必须对PE格式比较熟悉。现在
网上的PE教程我认为最好的就是罗云斌主页上的汇编教程了,我在这里长话短说,只是讨论和我们要解决的
问题相关的方面。
一般来讲,PE由以下几个部分依次排列下来:
1. Dos 头
2. Dos stub (通常你不必关心它的内容,重建PE只需完全拷贝即可)
3. NT 头
4. 节表
5. 文件对齐间隙
6. 第一节
7. 第二节
8. ...
9. 第 n 节 (文件结尾)
对于PE文件,如果没有文件对齐和内存对齐,那将是非常简单了。(但是,太简单了就不安全了,不是
吗?对于这种格式,当初的设计者还是动了不少脑筋的,呵呵~)。我们可以用非常简单的读文件函数,读取
各部分结构,然后把它重组还原PE。如果你是初次接触,建议你这样实践一下。
然后我们讨论一下如何增加区段,我们将尽量保证维持原来的PE结构的数据,然后在此基础上增加我们
的数据。现在我把这个过程步骤化:
一、读取Dos头
二、读取Dos stub
三、读取NT头,根据Dos头定位到此
四、读取NT头
五、读取节表
六、遍历读取所有节块
现在,我们把一个PE文件读到缓冲区了。然后我们进行修改:试验证明,只需要某些特征项即可,而不
必对所有参数进行修改,这样PE文件(如.exe)还是能正常运行。对于具体的节块,我们必须给某些关键的
参数赋值,否则将破坏PE结构,导致不能运行。
在开始修改前,有一些非常关键的东西我们必须知道:文件对齐和内存对齐。实际上,所有的section区
段都是文件对齐的(你把每一节当成一个块,具有起始文件位置和块大小),比如:第一节的文件偏移为
1024KB,节块大小为1000KB,那么第二节的文件偏移将是2048KB,而不是2024KB(文件偏移即是节块的开始
位置)。但这其实不是一成不变的。你可以修改它,只要满足文件对齐,但是带来的麻烦是,你必须同时也
修改它的定位目录----->节表里的PointerToRawData文件指针,否则将由于找不到对应的节块而产生错误。
我常常思考这样一个问题,到底要不要把PE装载到内存,然后在内存中增加区段,然后把PE内存dump成
新的PE文件达到增加区段的目的。实际上,这是完全可行的。但是,直接修改PE文件也是可以的,可以不把
PE装载到内存。因为我们仅仅是增加区段,不需要修改引入表之类的东西。在我增加区段成功后,对比发
现,节表里面的Virtual Address 实际上等于PointerToRawData,节表里面的Virtual Size 实际上等于SizeofRawData
(呵呵,我的网名就是rawdata)。于是,我想,这样的设计实际上是为了简化PE程序的设计的复杂性。内存对
齐转化为文件对齐,一旦设计好文件对齐,那么内存对齐就设计好了。但是,你千万不要认为两者一定总是相
等的,实际它有很大的灵活性,你可以随意设计,只要满足NT头里面的指定的内存对齐值参数。
还有一个关键的要注意的地方:必须重新修改NT头里面的pINH->OptionalHeader.SizeOfImage值。即整个PE
在内存的全部的映像的大小。我们可以这样给它赋予新的值:增加1个新的区段,就在原来的SizeOfImage值基
础上再加上该节块大小的文件对齐值,增加了几个区段,就累加几次,你应该明白了吧?
如果你感觉我的语言表达很糟糕,请你谅解。不过,请你放心,我后面会给出源代码。其实主要做的工
作就是在文件尾加上一些数据,然后修改文件头的一些参数,仅此而已,没有什么神奇的地方,还等什么?
赶快去写一个PE加区工具吧~~~
代码清单如下: (平台: window console)
把其中的PE文件名该为你想加区的PE文件名就可以了。
1
/**//**************************************************************************
2
* 文件名: Main.cpp
3
* 日 期: 2009年1月13日
4
* 作 者: rawdata
5
* 描 述:
6
***************************************************************************/
7
8
#include <windows.h>
9
#include <windowsx.h>
10
#include <winnt.h>
11
#include <iostream>
12
using namespace std;
13
14
#pragma warning(disable:4312)
15
#pragma warning(disable:4311)
16
#pragma warning(disable:4244)
17
18
int main(int argc,char**argv)
19

{
20
//------------------- 主要缓冲区定义 ----------------------
21
22
BYTE* pDos = NULL; //Dos头和Stub区
23
DWORD dwSizeDos = 0; //Dos头 大小
24
DWORD dwSizeStub = 0; //Dos Stub区大小
25
26
BYTE* pNT = NULL; //NT头
27
DWORD dwSizeNT = 0; //该区大小
28
29
BYTE* pSecH = NULL; //节表
30
DWORD dwSizeSecH = 0; //该区大小
31
WORD dwSizeAdd = 3; //增加的节的个数
32
33
BYTE* pDelta = NULL; //文件对齐填充数据
34
DWORD dwSizeDelta = 0; //该区大小
35
36
BYTE* pPrevSec = NULL; //节块
37
DWORD dwSizePrevSec = 0;//该区大小
38
39
BYTE* pAddSec = NULL; //新增的节块
40
DWORD dwSizeAddSec = 0; //该区大小
41
42
//---------------------- 其他临时定义 --------------------
43
44
const char* pszFilePath = NULL; //文件路径
45
HANDLE hFile = NULL; //文件句柄
46
47
PIMAGE_DOS_HEADER pIDH = NULL; //Dos头
48
PIMAGE_NT_HEADERS pINH = NULL; //NT 头
49
PIMAGE_SECTION_HEADER* ppISH = NULL; //节表
50
51
DWORD dwRealRead = 0; //实际每次文件读取的字节数
52
DWORD dwMiniPointer = 0; //第一个section的位置
53
BOOL bNeedModify = FALSE; //是否有必要需要修改节块的文件指针
54
55
DWORD dwRawDataSize = 10*1024; //增加区段的数据大小
56
57
DWORD dwTmp=0,dwTmp2=0,dwTmp3 = 0;
58
59
//Dos 头
60
//===============================================================================
61
//打开文件、读取Dos头
62
63
pszFilePath = argv[0];
64
pszFilePath = "BeingInjued.exe";//Test
65
66
cout<<"PE FileName:"<<pszFilePath<<endl;
67
68
if(0 == lstrcmp(pszFilePath,""))
69
{
70
cout<<"文件路径不能为空!"<<endl;
71
return -1;
72
}
73
74
hFile = CreateFile(pszFilePath,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,
75
FILE_ATTRIBUTE_NORMAL,NULL);
76
77
if(INVALID_HANDLE_VALUE == hFile)
78
{
79
cout<<"打开文件失败!"<<endl;
80
hFile = NULL;
81
goto Error;
82
}
83
84
dwSizeDos = sizeof(IMAGE_DOS_HEADER);
85
pDos = new BYTE[dwSizeDos];
86
memset(pDos,0,dwSizeDos);
87
88
if(!ReadFile(hFile,pDos,dwSizeDos,&dwRealRead,NULL))
89
{
90
cout<<"读取Dos头失败!"<<endl;
91
goto Error;
92
}
93
cout<<"Dos Header: "<<dwRealRead<<"bytes have read."<<endl;
94
95
//获得IMAGE_DOS_HEADER指针,效验
96
pIDH = (PIMAGE_DOS_HEADER)pDos;
97
if(memcmp(&(pIDH->e_magic),"MZ",2)!=0)
98
{
99
cout<<"不是有效的PE文件格式!"<<endl;
100
goto Error;
101
}
102
103
//DOS Stub
104
//================================================================================
105
106
dwSizeStub = pIDH->e_lfanew - dwSizeDos;
107
pDos = (BYTE*)realloc(pDos,dwSizeDos + dwSizeStub);
108
memset(pDos+dwSizeDos,0,dwSizeStub);
109
110
if(!ReadFile(hFile,pDos+dwSizeDos,dwSizeStub,&dwRealRead,NULL))
111
{
112
cout<<"读取DosStub失败!"<<endl;
113
goto Error;
114
}
115
cout<<"Dos Stub: "<<dwRealRead<<"bytes have read."<<endl;
116
117
//NT Header
118
//================================================================================
119
120
dwSizeNT = sizeof(IMAGE_NT_HEADERS);
121
pNT = new BYTE[dwSizeNT];
122
memset(pNT,0,dwSizeNT);
123
124
if(!ReadFile(hFile,pNT,dwSizeNT,&dwRealRead,NULL))
125
{
126
cout<<"读取NT Headers失败!"<<endl;
127
goto Error;
128
}
129
130
//获得NT指针
131
pINH = (PIMAGE_NT_HEADERS)pNT;
132
if(memcmp(&(pINH->Signature),"PE",2)!=0)
133
{
134
cout<<"错误的PE文件格式!"<<endl;
135
goto Error;
136
}
137
138
//节表
139
//================================================================================
140
141
dwSizeSecH = (pINH->FileHeader.NumberOfSections + dwSizeAdd) * sizeof(IMAGE_SECTION_HEADER);
142
pSecH = new BYTE[dwSizeSecH];
143
memset(pSecH,0,pINH->FileHeader.NumberOfSections + dwSizeAdd);
144
145
ppISH = (PIMAGE_SECTION_HEADER*)new DWORD[pINH->FileHeader.NumberOfSections + dwSizeAdd];
146
memset(ppISH,0,sizeof(DWORD)*(pINH->FileHeader.NumberOfSections + dwSizeAdd));
147
148
for(UINT i=0;i<pINH->FileHeader.NumberOfSections;i++)
149
{
150
if(!ReadFile(hFile,pSecH+i*sizeof(IMAGE_SECTION_HEADER),
151
sizeof(IMAGE_SECTION_HEADER),&dwRealRead,NULL))
152
{
153
cout<<"读取Section Headers失败!"<<endl;
154
goto Error;
155
}
156
157
ppISH[i] = (PIMAGE_SECTION_HEADER)(pSecH+i*sizeof(IMAGE_SECTION_HEADER));
158
159
cout<<"Name: "<<ppISH[i]->Name<<endl;
160
cout<<"Size: "<<ppISH[i]->SizeOfRawData<<endl;
161
cout<<"Virtual Adress: "<<ppISH[i]->VirtualAddress<<endl;
162
cout<<"PointerToRawData: "<<ppISH[i]->PointerToRawData<<endl;
163
}
164
cout<<endl;
165
166
167
//节块
168
//================================================================================
169
170
pPrevSec = (BYTE*)malloc(0);
171
for(i=0;i<pINH->FileHeader.NumberOfSections;i++)
172
{
173
dwTmp = ppISH[i]->SizeOfRawData;
174
pPrevSec = (BYTE*)realloc(pPrevSec,dwTmp2 + dwTmp);
175
memset(pPrevSec+dwTmp2,0,dwTmp);
176
177
SetFilePointer(hFile,ppISH[i]->PointerToRawData,NULL,FILE_BEGIN);
178
179
cout<<i<<":PointerToRawData:"<<ppISH[i]->PointerToRawData<<endl;
180
cout<<"BlockSize:"<<ppISH[i]->SizeOfRawData<<endl;
181
cout<<"Virtual Address:"<<ppISH[i]->VirtualAddress<<endl;
182
183
if(!ReadFile(hFile,pPrevSec+dwTmp2,dwTmp,&dwRealRead,NULL))
{
184
cout<<"ReadFile Faield!"<<endl;
185
goto Error;
186
}
187
188
dwTmp2 += dwTmp;
189
}
190
dwSizePrevSec = dwTmp2;
191
192
193
//数据填补、修改部分
194
//================================================================================
195
196
//第一个节块的位置
197
for(i=0;i<pINH->FileHeader.NumberOfSections;i++)
198
{
199
if(ppISH[i])
200
{
201
if(0 == dwMiniPointer)
202
dwMiniPointer = (DWORD)ppISH[i]->PointerToRawData;
203
204
if((ppISH[i]->PointerToRawData)<dwMiniPointer)
205
dwMiniPointer = (DWORD)ppISH[i]->PointerToRawData;
206
}
207
}
208
cout<<"Prev First Section Pos:"<<dwMiniPointer<<endl;
209
210
//空白填充区大小 ,先计算好
211
dwTmp = (dwSizeDos+dwSizeStub+dwSizeNT+dwSizeSecH);
212
if(dwMiniPointer >= dwTmp)
213
dwSizeDelta = dwMiniPointer - dwTmp;
214
else
215
{
216
dwSizeDelta = dwTmp % (pINH->OptionalHeader.FileAlignment);
217
218
if(dwSizeDelta != 0)
219
dwSizeDelta = pINH->OptionalHeader.FileAlignment - dwSizeDelta;
220
else dwSizeDelta = 0;
221
222
bNeedModify = TRUE;
223
}
224
cout<<"Delta:"<<dwSizeDelta<<endl;
225
pDelta = new BYTE[dwSizeDelta];
226
memset(pDelta,0,dwSizeDelta);
227
228
dwMiniPointer = dwTmp;
229
dwMiniPointer += dwSizeDelta;
230
231
//修改 NT 头,必须修改
232
pINH->FileHeader.NumberOfSections += dwSizeAdd;
233
234
235
//修改原来节表头的文件指针
236
cout<<endl;
237
if(bNeedModify)
238
{
239
for(i=0;i<(UINT)(pINH->FileHeader.NumberOfSections - dwSizeAdd);i++)
240
{
241
if(0 != i)
242
ppISH[i]->PointerToRawData =
243
ppISH[i-1]->PointerToRawData +
244
ppISH[i-1]->SizeOfRawData;
245
else
246
ppISH[i]->PointerToRawData = dwMiniPointer;
247
cout<<"New Entry:"<<i<<": "<<ppISH[i]->PointerToRawData<<endl;
248
}
249
}
250
251
//填充增加的节表头
252
cout<<endl;
253
char szName[8] = ".";
254
char szNum[7] =
{0};
255
szName[5] = 0;
256
dwTmp = ppISH[0]->VirtualAddress;
257
dwTmp2 = pINH->OptionalHeader.SectionAlignment;
258
dwTmp3 = pINH->OptionalHeader.FileAlignment;
259
int nCount = 1;
260
DWORD dwNewAllocSize = 0;
261
262
for(i=(pINH->FileHeader.NumberOfSections - dwSizeAdd);
263
i<pINH->FileHeader.NumberOfSections;i++)
264
{
265
ppISH[i] = (PIMAGE_SECTION_HEADER)(pSecH+i*sizeof(IMAGE_SECTION_HEADER));
266
memset(ppISH[i],0,sizeof(IMAGE_SECTION_HEADER));
267
268
ppISH[i]->Characteristics = ppISH[0]->Characteristics;
269
270
sprintf(szNum,"%d",nCount);
271
memcpy(szName+1,szNum,7);
272
memcpy(ppISH[i]->Name,szName,8);
273
274
dwNewAllocSize = dwRawDataSize % dwTmp3;
275
if(dwNewAllocSize != 0)
276
dwNewAllocSize = dwRawDataSize + (dwTmp3 - dwNewAllocSize);
277
else dwNewAllocSize = dwRawDataSize;
278
ppISH[i]->SizeOfRawData = dwNewAllocSize;
279
280
//增加的文件区段
281
dwSizeAddSec += ppISH[i]->SizeOfRawData;
282
283
dwNewAllocSize = dwRawDataSize % dwTmp2;
284
if(dwNewAllocSize != 0)
285
dwNewAllocSize = dwRawDataSize + (dwTmp2 - dwNewAllocSize);
286
else dwNewAllocSize = dwRawDataSize;
287
288
ppISH[i]->Misc.VirtualSize = dwNewAllocSize;
289
290
//修改NT头,必须修改
291
pINH->OptionalHeader.SizeOfImage += dwNewAllocSize;
292
293
ppISH[i]->PointerToRawData = (ppISH[i-1]->PointerToRawData+ppISH[i-1]->SizeOfRawData);
294
295
ppISH[i]->VirtualAddress = ppISH[i]->PointerToRawData;
296
if(ppISH[i]->VirtualAddress>=(0x7FFFFFFF-dwNewAllocSize))
297
{
298
cout<<"Error!Virtual address overflow!"<<endl;
299
goto Error;
300
}
301
cout<<"New Entry:"<<i<<": "<<ppISH[i]->PointerToRawData<<endl;
302
nCount++;
303
}
304
305
//修改NT头,可选,不设置也能正常运行,但是为保证数据准确,还是写上
306
pINH->OptionalHeader.SizeOfHeaders = dwMiniPointer;
307
308
309
310
//新的Sections,必须满足文件对齐
311
pAddSec = new BYTE[dwSizeAddSec];
312
memset(pAddSec,0,dwSizeAddSec);
313
314
//重建文件: dumpOK.exe
315
//================================================================================
316
317
CloseHandle(hFile);
318
hFile = CreateFile("dumpOK.exe",GENERIC_READ|GENERIC_WRITE,NULL,NULL,CREATE_ALWAYS,
319
FILE_ATTRIBUTE_NORMAL,NULL);
320
321
//Dos Data
322
if(!WriteFile(hFile,pDos,dwSizeDos+dwSizeStub,&dwRealRead,NULL))
323
{
324
cout<<"WriteFile Faield!"<<endl;
325
goto Error;
326
}
327
cout<<"Dos Data:"<<dwRealRead<<" bytes write."<<endl;
328
329
330
//NT 头
331
if(!WriteFile(hFile,pNT,dwSizeNT,&dwRealRead,NULL))
332
{
333
cout<<"WriteFile Faield!"<<endl;
334
goto Error;
335
}
336
cout<<"NT Data:"<<dwRealRead<<" bytes write."<<endl;
337
338
//节表 (包括新加的)
339
if(!WriteFile(hFile,pSecH,dwSizeSecH,&dwRealRead,NULL))
340
{
341
cout<<"WriteFile Faield!"<<endl;
342
goto Error;
343
}
344
cout<<"Section Headers:"<<dwRealRead<<" bytes write."<<endl;
345
346
//填充空白数据
347
if(!WriteFile(hFile,pDelta,dwSizeDelta,&dwRealRead,NULL))
{
348
cout<<"WriteFile Faield!"<<endl;
349
goto Error;
350
}
351
cout<<"Delta Data:"<<dwRealRead<<" bytes write."<<endl;
352
353
354
//原来的节块
355
if(!WriteFile(hFile,pPrevSec,dwSizePrevSec,&dwRealRead,NULL))
{
356
cout<<"WriteFile Faield!"<<endl;
357
goto Error;
358
}
359
cout<<"Section Blocks:"<<dwRealRead<<" bytes write."<<endl;
360
361
//增加的节块
362
if(!WriteFile(hFile,pAddSec,dwSizeAddSec,&dwRealRead,NULL))
{
363
cout<<"WriteFile Faield!"<<endl;
364
goto Error;
365
}
366
cout<<"Section Blocks:"<<dwRealRead<<" bytes write."<<endl;
367
cout<<"Requeried Works Success Completed."<<endl;
368
369
Error:
370
CloseHandle(hFile);
371
delete[]ppISH;
372
delete[]pDos;
373
delete[]pNT;
374
delete[]pSecH;
375
delete[]pDelta;
376
delete[]pPrevSec;
377
delete[]pAddSec;
378
return 0;
379
}
380
381
382
383
384
如果代码有什么谬误或你有更好的解决方案,请留言或者EmailToMe:xiaolu69soft@yahoo.com.cn
希望我的文章对你有所帮助。
rawdata