程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> xp下用戶程序空間分配(4):加載主程序

xp下用戶程序空間分配(4):加載主程序

編輯:關於C++

這個是主程序,它的模塊信息:

名稱 基址 大小 入口點 f:\embed\etools\Debug\bin\bash.exe 00400000 0006f000 0045bb30

對應的內存塊:

這些塊的類型都是MEM_IMAGE,且分配時的保護標志都是PAGE_EXECUTE_WRITECOPY,MSDN這樣解釋這 個標志位:

Enables execute, read, and write access to the committed region of image file code pages. The pages are shared read-on-write and copy-on-write.

這幾個內存塊的分配基址 都是一樣的,猜測windows是為整個文件申請了一塊大的空間,然後將文件裡面的section分別寫入到不 同的區域裡面去。

用下面的命令行將所有的信息dump出來。

dumpbin /all bash.exe

再把它們和內存裡的數據進行比較。

1.1 文件頭

先看從原始文件中dump出來的文件頭:

FILE HEADER VALUES
14C machine (x86)
5 number of sections
4A910052 time date stamp Sun Aug 23 16:39:46 2009
0 file pointer to symbol table
0 number of symbols
E0 size of optional header
102 characteristics
Executable
32 bit word machine

一共有5個section,但是上 面有6個塊,怎麼就對應不上呢,想來0x0040 0000這個塊應該是文件頭信息:

0x00400000  4d 5a 90 00 03 00 00 00 04 00 00 00 ff ff 00 00  MZ..............
0x00400010  b8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00  ........@.......
0x00400020  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0x00400030  00 00 00 00 00 00 00 00 00 00 00 00 e0 00 00 00  ................
0x00400040  0e 1f ba 0e 00 b4 09 cd 21 b8 01 4c cd 21 54 68  ........!..L.!Th
0x00400050  69 73 20 70 72 6f 67 72 61 6d 20 63 61 6e 6e 6f  is program canno
0x00400060  74 20 62 65 20 72 75 6e 20 69 6e 20 44 4f 53 20  t be run in DOS
0x00400070  6d 6f 64 65 2e 0d 0d 0a 24 00 00 00 00 00 00 00  mode....$.......
0x00400080  b0 80 2d 3c f4 e1 43 6f f4 e1 43 6f f4 e1 43 6f   .€-<..Co..Co..Co
0x00400090  49 ae d5 6f f9 e1 43 6f ea b3 d6 6f ff e1 43 6f  I..o..Co...o..Co
0x004000A0  ea b3 c7 6f f3 e1 43 6f ea b3 d0 6f f0 e1 43 6f  ...o..Co...o..Co
0x004000B0  f4 e1 42 6f 5f e1 43 6f d3 27 38 6f f3 e1 43 6f  ..Bo_.Co.'8o..Co
0x004000C0  ea b3 c0 6f 88 e1 43 6f ea b3 d2 6f f5 e1 43 6f  ...o..Co...o..Co
0x004000D0  52 69 63 68 f4 e1 43 6f 00 00 00 00 00 00 00 00  Rich..Co........
0x004000E0  50 45 00 00 4c 01 05 00 49 a8 94 4a 00 00 00 00  PE..L...I..J....
0x004000F0  00 00 00 00 e0 00 02 01 0b 01 09 00 00 be 05 00  ................
0x00400100  00 e2 00 00 00 00 00 00 30 bb 05 00 00 10 00 00  ........0.......
0x00400110  00 d0 05 00 00 00 40 00 00 10 00 00 00 02 00 00  ......@.........
0x00400120  05 00 00 00 00 00 00 00 05 00 00 00 00 00 00 00  ................
0x00400130  00 f0 06 00 00 04 00 00 60 40 07 00 03 00 40 81  ........`@....@.
0x00400140  00 00 10 00 00 10 00 00 00 00 10 00 00 10 00 00  ................
0x00400150  00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00  ................

這些內存數據和原始文件頭裡面的數據是完全相同的。

在c運行庫裡提 供了一個叫__ImageBase的全局變量,存放這個變量的地址就在0x0040 0000,下面給出這個結構體成員 的一些值:

e_magic 0x5a4d unsigned short e_cblp 0x0090 unsigned short e_cp 0x0003 unsigned short e_crlc 0x0000 unsigned short e_cparhdr 0x0004 unsigned short e_minalloc 0x0000 unsigned short e_maxalloc 0xffff unsigned short e_ss 0x0000 unsigned short e_sp 0x00b8 unsigned short e_csum 0x0000 unsigned short e_ip 0x0000 unsigned short e_cs 0x0000 unsigned short e_lfarlc 0x0040 unsigned short e_ovno 0x0000 unsigned short e_res 0x0040001c "" unsigned short [4] e_oemid 0x0000 unsigned short e_oeminfo 0x0000 unsigned short e_res2 0x00400028 "" unsigned short [10] e_lfanew 0x000000e0 long

注意系統對這個區域的保護:

這個區域將是只讀的。

根據PE文件的規定,在0x3c這個偏移量的位置(也就是 __ImageBase.e_lfanew這個成員)指明了IMAGE_FILE_HEAD的偏移量。我們直接用一個IMAGE_FILE_HEAD 指針指向這個位置,就可以看到IMAGE_FILE_HEAD的值了:

Machine 0x014c unsigned short NumberOfSections 0x0005 unsigned short TimeDateStamp 0x4a94cfc5 unsigned long PointerToSymbolTable 0x00000000 unsigned long NumberOfSymbols 0x00000000 unsigned long SizeOfOptionalHeader 0x00e0 unsigned short Characteristics 0x0102 unsigned short

再按照這個結構體得到的SizeOfOptionalHeader,我們將得以遍歷所有的section head。

緊接著 IMAGE_FILE_HEAD之後的是一個叫IMAGE_OPTIONAL_HEAD的結構體,我們直接用一個指針指向這個位置並 得到實際的值:

把它和從文件裡面DUMP出來的數據比較,可以發現它們是一致的:

OPTIONAL HEADER VALUES
10B magic # (PE32)
9.00 linker version
5BE00 size of code
E200 size of initialized data
0 size of uninitialized data
5BB60 entry point (0045BB60) _mainCRTStartup
1000 base of code
5D000 base of data
400000 image base (00400000 to 0046EFFF)
1000 section alignment
200 file alignment
5.00 operating system version
0.00 image version
5.00 subsystem version
0 Win32 version
6F000 size of image
400 size of headers
6F1FE checksum
3 subsystem (Windows CUI)
8140 DLL characteristics
Dynamic base
NX compatible
Terminal Server Aware
100000 size of stack reserve
1000 size of stack commit
100000 size of heap reserve
1000 size of heap commit
0 loader flags
10 number of directories
0 [       0] RVA [size] of Export Directory
63354 [      78] RVA [size] of Import Directory
68000 [     2B4] RVA [size] of Resource Directory
0 [       0] RVA [size] of Exception Directory
0 [       0] RVA [size] of Certificates Directory
69000 [    5844] RVA [size] of Base Relocation Directory
5D2E0 [      1C] RVA [size] of Debug Directory
0 [       0] RVA [size] of Architecture Directory
0 [        0] RVA [size] of Global Pointer Directory
0 [       0] RVA [size] of Thread Storage Directory
62EE0 [      40] RVA [size] of Load Configuration Directory
0 [       0] RVA [size] of Bound Import Directory
5D000 [     2C0] RVA [size] of Import Address Table Directory
0 [       0] RVA [size] of Delay Import Directory
0 [       0] RVA [size] of COM Descriptor Directory
0 [       0] RVA [size] of Reserved Directory

1.2 代碼段

先看看從bash.exe裡面dump出來的信息:

SECTION HEADER #1
.text name
5BC4E virtual size
1000 virtual address (00401000 to 0045CC4D)
5BE00 size of raw data
400 file pointer to raw data (00000400 to 0005C1FF)
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
60000020 flags
Code
Execute Read

它請求的地 址是0x0040 1000,看看在內存裡的section head:

下面是windows為這個段分配的內存塊:

顯然windows是滿足文件的請求了。

再比較dump出來的代碼段的原始數據和內存裡的數據:

0x00401000  55 8b ec 81 ec d4 00 00 00 53 56 57 8d bd 2c ff  U........SVW..,.
0x00401010  ff ff b9 35 00 00 00 b8 cc cc cc cc f3 ab 8b 45  ...5...........E
0x00401020  14 83 e0 01 89 45 f8 8b 45 08 0f be 08 83 f9 3d  .....E..E......=

可以發現它們的內容是一致的。

在vs2008裡面可以看到這段代碼反匯編的結果:

int
binary_test (op, arg1, arg2, flags)
char *op, *arg1, *arg2;
int flags;
{
00401000 55               push        ebp 
00401001 8B EC            mov         ebp,esp
00401003 81 EC D4 00 00 00 sub          esp,0D4h
00401009 53               push        ebx 
0040100A 56               push        esi 
0040100B 57               push        edi 
0040100C 8D BD 2C FF FF FF lea         edi,[ebp-0D4h]
00401012 B9 35 00 00 00   mov         ecx,35h
00401017 B8 CC CC CC CC   mov         eax,0CCCCCCCCh
0040101C F3 AB            rep stos    dword ptr es:[edi]
int patmatch;
………………

由此可見windows應該是把這個段的 內容原封不動地讀進來了,執行時PC指針將指向這塊內存的數據。

1.3 只讀數據段

這是exe裡面的第二個段,看看它的section head:

  .rdata name
6FD0 virtual size
5D000 virtual address (0045D000 to 00463FCF)
7000 size of raw data
5C200 file pointer to raw data (0005C200 to 000631FF)
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
40000040 flags
Initialized Data
Read Only

再看內存裡面 的section head:

同樣,滿足了文件的要求。

這個只讀數據段的絕大部分數據與文件中讀出的一致,但是對於導入 表之類的數據,在加載到內存之後將由windows動態更改。

1.4 數據段

先看看從文件中dump出來的section head:

SECTION HEADER #3
.data name
352C virtual size
64000 virtual address (00464000 to 0046752B)
1400 size of raw data
63200 file pointer to raw data (00063200 to 000645FF)
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
C0000040 flags
Initialized Data
Read Write

再看看內存裡面的section head:

從這裡可以看到,實際上這個段的內存是分為兩部分的,第一個部分用於存放Relocation table,第 二個部分才是程序裡的全局變量。因為第二個部分是允許在程序中修改的,因此它的保護標志設置成了 PAGE_READWRITE。

隨便在程序裡面找個全局變量,看一下地址,的確是落在這個范圍的,呵呵。前幾 天還使勁在想怎麼取得數據段的首地址,得來全不費工夫!用VirtualQuery足矣!

1.5 .rsrc

先看看從bash.exe裡面dump出來的section head:

SECTION HEADER #4
.rsrc name
2B4 virtual size
68000 virtual address (00468000 to 004682B3)
400 size of raw data
64600 file pointer to raw data (00064600 to 000649FF)
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
40000040 flags
Initialized Data
Read Only

再看看內存裡面的section head:

這一塊的內容和從文件中讀取的內容完全一致。

1.6 .reloc

先看看從文件中dump出來的頭:

SECTION HEADER #5
.reloc name
58D0 virtual size
69000 virtual address (00469000 to 0046E8CF)
5A00 size of raw data
64A00 file pointer to raw data (00064A00 to 0006A3FF)
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
42000040 flags
Initialized Data
Discardable
Read Only

再看看內存裡面的section head:

比較發現它在內存中的數據和從文件中讀取出來的原始數據是一致的。Reloc的過程暫且不管,再看 看其它的東西。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved