???????
?
???????原創:星綻紫輝(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加區工具吧~~~?
???? 代碼清單如下:??? (平臺: 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