不賴猴的筆記,轉載請注明出處。
一、 Windows加載器
加載器讀取一個PE文件的過程如下:
1. 先讀入PE文件的DOS頭,PE頭和Section頭。
2. 然後根據PE頭裡的ImageBase所定義的加載地址是否可用,如果已被其他模塊占用,則重新分配一塊空間。
3. 根據Section頭部的信息,把文件的各個Section映射到分配的空間,並根據各個Section定義的數據來修改所映射的頁的屬性。
4. 如果文件被加載的地址不是ImageBase定義的地址,則重新修正ImageBase。
5. 根據PE文件的輸入表加載所需要的DLL到進程空間。
6. 然後替換IAT表內的數據為實際調用函數的地址。
7. 根據PE頭內的數據生成初始化的堆和棧。
8. 創建初始化線程,開始運行進程。
這裡要提的是加載PE文件所需DLL的過程是建立在六個底層的API上。
LdrpCheckForLoadedDll:檢查要加載的模塊是否已經存在。
LdrpMapDll:映射模塊和所需信息到內存。
LdrpWalkImportDescriptor:遍歷模塊的輸入表來加載其所需的其他模塊。
LdrpUpdateLoadCount:計數模塊的使用次數。
LdrpRunInitializeRoutines:初始化模塊。
LdrpClearLoadInProgress:清楚某些標志,表明加載已經完成。
二、 插入代碼到PE文件有三種方式可以插入代碼到PE文件:
1. 把代碼加入到一個存在的Section的未用空間裡。
2. 擴大一個存在的Section,然後把代碼加入。
3. 新增一個Section。
方法一、增加代碼到一個存在的Section。首先我們需要找到一個被映射到一個塊有執行權限的Section。最簡單的方式就是直接利用CODE Section。
然後我們需要查找這塊Section內的多余空間(也就是填滿了00h)。我們知道一個Section有兩個數據來表示其大小。VirtualSize和SizeOfRawData。這個VirtualSize代表Section裡代碼實際所占用的磁盤空間。SizeOfRawData代表根據磁盤對齊後所占的空間。通常SizeofRawData都會比VirtualSize要大。如下圖。