之前寫過乙個利用遠端執行緒注入dll的工具,大致過程如下:
1.使用openprocesstoken、lookupprivilegevalue、adjusttokenprivileges函式修改當前程序的的訪問令牌,獲得除錯許可權。
2.openprocess開啟目標程序,用virtualallocex在目標程序申請一段記憶體空間,writeprocessmemory將要注入dll的路徑字串寫入申請的記憶體裡。
3.最後呼叫getprocaddress獲取loadlibrarya(w)的位址,createremotethread執行遠端執行緒,成功在目標程序注入dll。
遠端注入的好處是動態的,它不修改檔案本身,所有的改動都是在記憶體裡,申請分配寫入銷毀,這就是說我們在注入dll的時候目標程式已經在執行中了,但有時又需要注入**執行在程式之前,有什麼辦法呢?很自然的想到通過修改本地pe檔案的相關資料從而達成我們的目的。在windows上所有exe、dll、ocx甚至sys都是pe檔案,所謂pe是微軟制定的一種可移植的檔案格式,其結構如圖:
dos頭的0x3c偏移處的dword值指向pe頭,對於win32程式,結構如下:
typedef struct _image_nt_headers image_nt_headers32, *pimage_nt_headers32;
typedef struct _image_file_header image_file_header, *pimage_file_header;
typedef struct _image_optional_header image_optional_header32, *pimage_optional_header32;
typedef struct _image_data_directory image_data_directory, *pimage_data_directory;
其中optionalheader.addressofentrypoint是程式入口點,是系統裝載程式完畢後跳轉執行第一條指令的位址,這是乙個記憶體偏移位址,程式基址由optionalheader.baseofcode指明。我們要做的就是修改oep,先執行我們的**,然後再跳轉回原oep,那麼這些**應該寫入在**?pe檔案中資料都是按節存放的,節中資料具有相同的屬性,如可讀可寫可執行等等,pe格式規定節的物理大小必須是optionalheader.filealignment(一般為512)的倍數,不足的用0補齊,這些用0對齊的資料就是**寫入的地方。fileheader.numberofsections表示節的數目,pe文頭後面緊跟著節頭資訊,結構如下:
typedef struct _image_section_header misc;
dword virtualaddress;
dword sizeofrawdata;
dword pointertorawdata;
dword pointertorelocations;
dword pointertolinenumbers;
word numberofrelocations;
word numberoflinenumbers;
dword characteristics;
} image_section_header, *pimage_section_header;
sizeofrawdata是對齊後的物理大小,misc.virtualsize是節的實際大小,兩者一減,就是磁碟上對齊0的數量,pointertorawdata是節的檔案偏移,characteristics是節屬性。好了,有了這些資訊就能遍歷節表,找到**節,計算節剩餘空間(即對齊的0資料),**如下:
// 節的數目
int sections = lpnthead->fileheader.numberofsections;
image_section_header *lpsections = (image_section_header*)((dword)&(lpnthead->optionalheader) + lpnthead->fileheader.sizeofoptionalheader);
dword lpcodeoffset = 0;
dword dwcodesize = 0;
dword dwfreesize = 0;
// 遍歷所有節頭
for(int i=0;idwcodesize) else
break;
}}
找到可用的**節,再判斷一下剩餘空間能否容下寫入**,如果符合條件就可以在lpcodeoffset + dwcodesize處寫入**了:呼叫loadlibrarya(w)函式,載入注入的dll檔案,然後跳轉回原oep程式繼續執行,類似下面的:
__asm
szdllname存放著dll名字,可以在**節剩餘空間裡分配,壓入棧的是字串的虛擬位址(rva+映像基址),這個我們轉換一下就行了,不過還有乙個小問題:exe和dll不同,總是能成功對映首選基址不存在基址衝突的,但從vista以後,系統出現一種新的「位址空間布局隨機化」機制,如果乙個exe程式存在基址重定位資訊並且沒有image_file_relocs_stripped標誌,exe基址會被隨機化,如此一來之前壓入的szdllname位址就不正確了,解決這問題最簡單的辦法就是強制exe程式必須對映到首選基址上,fileheader.characteristics |= image_file_relocs_stripped成功搞定!
image_data_directory *pimportdirectory = &(lpnthead->optionalheader.datadirectory[image_directory_entry_import]);
dword lpbase = pimportdirectory->virtualaddress;
lpbase = (dword)lpdoshead + rvatofileoffset(lpdoshead,lpbase);
image_import_descriptor *pimport = (image_import_descriptor*)lpbase;
char *buf;
dword *dwaddress;
dword lploadlibrarya,lploadlibraryw,lploadlibraryexa,lploadlibraryexw;
lploadlibrarya = lploadlibraryw = lploadlibraryexa = lploadlibraryexw = null;
for(int i=0;;i++)
buf = (char*)((dword)lpdoshead + rvatofileoffset(lpdoshead,pimport[i].name));
if(0 == stricmp(buf,"kernel32.dll"))
if(0 == strcmp(buf,"loadlibraryw"))
if(0 == strcmp(buf,"loadlibraryexa"))
if(0 == strcmp(buf,"loadlibraryexw"))
}dwaddress++;
pos++;
} break;
}}
最後,以此紀念我第一篇csdn博文。 Dll注入 修改PE檔案頭
dll注入,除了常見的遠執行緒注入,掛鉤和修改登錄檔以外還可以通過修改pe檔案頭來達到注入目的,廢話少說先上菜。pe檔案經常會呼叫外部dll檔案,而需要呼叫的dll檔案都會在pe檔案說明,通過 nt頭 可選頭 匯入表 可以找到匯入表,而匯入表就是對需要匯入的每個dll的說明,它實際上是乙個20個位元...
通過修改PE檔案匯入DLL
圖1由上圖我們可以得到以下資訊 idt的rva資訊在檔案偏移160h處,值為84cc idt的大小資訊在檔案偏移164h處,值為64h 1.1轉到idt處檢視具體資訊 轉到84cc也就是檔案偏移76cc 共有5個iid結構體 每個iid20個位元組,對應乙個dll相關資訊 最後乙個iid為null ...
C 實現DLL注入(一)實現
直接上 了 pragma once include include include int fmethod char c str bool loaddll dword dwprocessid,lptstr lpszdllname include fmethod.h int fmethod char ...