原創:星綻紫輝(rawdata) http://www.shnenglu.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加區工具吧~~~
代碼清單如下: (平臺: console)
把其中的PE文件名該為你想加區的PE文件名就可以了。
后記:
原來的程序是只使用于raw和rva相等的情況,正確的修改如下:
把第295行修改為:
//Rva與raw不匹配的情況。。。
ppISH[i]->VirtualAddress = ppISH[i-1]->VirtualAddress +\
((ppISH[i-1]->SizeOfRawData/pINH->OptionalHeader.SectionAlignment)+1)*\
(pINH->OptionalHeader.SectionAlignment);
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


2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19



20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69



70

71

72

73

74

75

76

77

78



79

80

81

82

83

84

85

86

87

88

89



90

91

92

93

94

95

96

97

98



99

100

101

102

103

104

105

106

107

108

109

110

111



112

113

114

115

116

117

118

119

120

121

122

123

124

125



126

127

128

129

130

131

132

133



134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149



150

151

152



153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172



173

174

175

176

177

178

179

180

181

182

183



184

185

186

187

188

189

190

191

192

193

194

195

196

197

198



199

200



201

202

203

204

205

206

207

208

209

210

211

212

213

214

215



216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238



239

240



241

242

243

244

245

246

247

248

249

250

251

252

253

254



255

256

257

258

259

260

261

262

263

264



265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297



298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323



324

325

326

327

328

329

330

331

332



333

334

335

336

337

338

339

340



341

342

343

344

345

346

347



348

349

350

351

352

353

354

355



356

357

358

359

360

361

362



363

364

365

366

367

368

369

370

371

372

373

374

375

376

377

378

379

380

381

382

383

384

如果代碼有什么謬誤或你有更好的解決方案,請留言或者EmailToMe:xiaolu69soft@yahoo.com.cn
希望我的文章對你有所幫助。
rawdata