原創(chuàng):星綻紫輝(rawdata) http://m.shnenglu.com/rawdata 2009-1-20
轉(zhuǎn)載請注明出處
關(guān)鍵字: PE 增加 區(qū)段 section 文件格式
現(xiàn)在我要給一PE文件增加區(qū)段(section),但是增加區(qū)段后我不希望影響PE文件的正常使用,那么應(yīng)該怎么
做呢?我寫這個(gè)教程的目的,希望能幫學(xué)習(xí)PE格式,當(dāng)然也作為我以后參考的筆記。
簡單地說:PE文件和普通文件沒有什么區(qū)別,只是存在格式上的差異。另外,當(dāng)你雙擊某個(gè).exe文件
時(shí),Windows Shell 程序?qū)?huì)嘗試解析文件并運(yùn)行它的PE代碼。所以第一步,你必須對PE格式比較熟悉。現(xiàn)在
網(wǎng)上的PE教程我認(rèn)為最好的就是羅云斌主頁上的匯編教程了,我在這里長話短說,只是討論和我們要解決的
問題相關(guān)的方面。
一般來講,PE由以下幾個(gè)部分依次排列下來:
1. Dos 頭
2. Dos stub (通常你不必關(guān)心它的內(nèi)容,重建PE只需完全拷貝即可)
3. NT 頭
4. 節(jié)表
5. 文件對齊間隙
6. 第一節(jié)
7. 第二節(jié)
8. ...
9. 第 n 節(jié) (文件結(jié)尾)
對于PE文件,如果沒有文件對齊和內(nèi)存對齊,那將是非常簡單了。(但是,太簡單了就不安全了,不是
嗎?對于這種格式,當(dāng)初的設(shè)計(jì)者還是動(dòng)了不少腦筋的,呵呵~)。我們可以用非常簡單的讀文件函數(shù),讀取
各部分結(jié)構(gòu),然后把它重組還原PE。如果你是初次接觸,建議你這樣實(shí)踐一下。
然后我們討論一下如何增加區(qū)段,我們將盡量保證維持原來的PE結(jié)構(gòu)的數(shù)據(jù),然后在此基礎(chǔ)上增加我們
的數(shù)據(jù)。現(xiàn)在我把這個(gè)過程步驟化:
一、讀取Dos頭
二、讀取Dos stub
三、讀取NT頭,根據(jù)Dos頭定位到此
四、讀取NT頭
五、讀取節(jié)表
六、遍歷讀取所有節(jié)塊
現(xiàn)在,我們把一個(gè)PE文件讀到緩沖區(qū)了。然后我們進(jìn)行修改:試驗(yàn)證明,只需要某些特征項(xiàng)即可,而不
必對所有參數(shù)進(jìn)行修改,這樣PE文件(如.exe)還是能正常運(yùn)行。對于具體的節(jié)塊,我們必須給某些關(guān)鍵的
參數(shù)賦值,否則將破壞PE結(jié)構(gòu),導(dǎo)致不能運(yùn)行。
在開始修改前,有一些非常關(guān)鍵的東西我們必須知道:文件對齊和內(nèi)存對齊。實(shí)際上,所有的section區(qū)
段都是文件對齊的(你把每一節(jié)當(dāng)成一個(gè)塊,具有起始文件位置和塊大小),比如:第一節(jié)的文件偏移為
1024KB,節(jié)塊大小為1000KB,那么第二節(jié)的文件偏移將是2048KB,而不是2024KB(文件偏移即是節(jié)塊的開始
位置)。但這其實(shí)不是一成不變的。你可以修改它,只要滿足文件對齊,但是帶來的麻煩是,你必須同時(shí)也
修改它的定位目錄----->節(jié)表里的PointerToRawData文件指針,否則將由于找不到對應(yīng)的節(jié)塊而產(chǎn)生錯(cuò)誤。
我常常思考這樣一個(gè)問題,到底要不要把PE裝載到內(nèi)存,然后在內(nèi)存中增加區(qū)段,然后把PE內(nèi)存dump成
新的PE文件達(dá)到增加區(qū)段的目的。實(shí)際上,這是完全可行的。但是,直接修改PE文件也是可以的,可以不把
PE裝載到內(nèi)存。因?yàn)槲覀儍H僅是增加區(qū)段,不需要修改引入表之類的東西。在我增加區(qū)段成功后,對比發(fā)
現(xiàn),節(jié)表里面的Virtual Address 實(shí)際上等于PointerToRawData,節(jié)表里面的Virtual Size 實(shí)際上等于SizeofRawData
(呵呵,我的網(wǎng)名就是rawdata)。于是,我想,這樣的設(shè)計(jì)實(shí)際上是為了簡化PE程序的設(shè)計(jì)的復(fù)雜性。內(nèi)存對
齊轉(zhuǎn)化為文件對齊,一旦設(shè)計(jì)好文件對齊,那么內(nèi)存對齊就設(shè)計(jì)好了。但是,你千萬不要認(rèn)為兩者一定總是相
等的,實(shí)際它有很大的靈活性,你可以隨意設(shè)計(jì),只要滿足NT頭里面的指定的內(nèi)存對齊值參數(shù)。
還有一個(gè)關(guān)鍵的要注意的地方:必須重新修改NT頭里面的pINH->OptionalHeader.SizeOfImage值。即整個(gè)PE
在內(nèi)存的全部的映像的大小。我們可以這樣給它賦予新的值:增加1個(gè)新的區(qū)段,就在原來的SizeOfImage值基
礎(chǔ)上再加上該節(jié)塊大小的文件對齊值,增加了幾個(gè)區(qū)段,就累加幾次,你應(yīng)該明白了吧?
如果你感覺我的語言表達(dá)很糟糕,請你諒解。不過,請你放心,我后面會(huì)給出源代碼。其實(shí)主要做的工
作就是在文件尾加上一些數(shù)據(jù),然后修改文件頭的一些參數(shù),僅此而已,沒有什么神奇的地方,還等什么?
趕快去寫一個(gè)PE加區(qū)工具吧~~~
代碼清單如下: (平臺(tái): console)
把其中的PE文件名該為你想加區(qū)的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
//------------------- 主要緩沖區(qū)定義 ----------------------
21
22
BYTE* pDos = NULL; //Dos頭和Stub區(qū)
23
DWORD dwSizeDos = 0; //Dos頭 大小
24
DWORD dwSizeStub = 0; //Dos Stub區(qū)大小
25
26
BYTE* pNT = NULL; //NT頭
27
DWORD dwSizeNT = 0; //該區(qū)大小
28
29
BYTE* pSecH = NULL; //節(jié)表
30
DWORD dwSizeSecH = 0; //該區(qū)大小
31
WORD dwSizeAdd = 3; //增加的節(jié)的個(gè)數(shù)
32
33
BYTE* pDelta = NULL; //文件對齊填充數(shù)據(jù)
34
DWORD dwSizeDelta = 0; //該區(qū)大小
35
36
BYTE* pPrevSec = NULL; //節(jié)塊
37
DWORD dwSizePrevSec = 0;//該區(qū)大小
38
39
BYTE* pAddSec = NULL; //新增的節(jié)塊
40
DWORD dwSizeAddSec = 0; //該區(qū)大小
41
42
//---------------------- 其他臨時(shí)定義 --------------------
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; //節(jié)表
50
51
DWORD dwRealRead = 0; //實(shí)際每次文件讀取的字節(jié)數(shù)
52
DWORD dwMiniPointer = 0; //第一個(gè)section的位置
53
BOOL bNeedModify = FALSE; //是否有必要需要修改節(jié)塊的文件指針
54
55
DWORD dwRawDataSize = 10*1024; //增加區(qū)段的數(shù)據(jù)大小
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指針,效驗(yàn)
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<<"錯(cuò)誤的PE文件格式!"<<endl;
135
goto Error;
136
}
137
138
//節(jié)表
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
//節(jié)塊
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
//數(shù)據(jù)填補(bǔ)、修改部分
194
//================================================================================
195
196
//第一個(gè)節(jié)塊的位置
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
//空白填充區(qū)大小 ,先計(jì)算好
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
//修改原來節(jié)表頭的文件指針
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
//填充增加的節(jié)表頭
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
//增加的文件區(qū)段
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頭,可選,不設(shè)置也能正常運(yùn)行,但是為保證數(shù)據(jù)準(zhǔn)確,還是寫上
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
//節(jié)表 (包括新加的)
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
//填充空白數(shù)據(jù)
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
//原來的節(jié)塊
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
//增加的節(jié)塊
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