




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、一種保護(hù)應(yīng)用程序的方法 模擬Windows PE加載某天睡覺醒來,我發(fā)現(xiàn)我會開機(jī)了方法,過程,目標(biāo),成就是時(shí)候起兵作反了不要太多感情posts-787,comments-225,trackbacks-0,articles-1【轉(zhuǎn)載】一種保護(hù)應(yīng)用程序的方法模擬Windows PE加載器,從內(nèi)存資源中加載DLL編程2008-07-27 21:23:47閱讀375 1、前言目前很多敏感和重要的DLL(Dynamic-link library)都沒有提供靜態(tài)版本供編譯器進(jìn)行靜態(tài)連接(.lib文件),即使提供了靜態(tài)版本也因?yàn)榧嫒菪詥栴}導(dǎo)致無法使用,而只提供DLL版本,并且很多專業(yè)軟件的授權(quán)部分的API,
2、都是單獨(dú)提供一個(gè)DLL來完成,而主模塊通過調(diào)用DLL中的接口來完成授權(quán)功能。雖然這些軟件一般都采用了加殼和反調(diào)試等保護(hù),但是一旦這些功能失去作用,比如脫殼,反反調(diào)試,HOOK API或者干脆寫一個(gè)仿真的授權(quán)DLL(模擬授權(quán)DLL的所有導(dǎo)出函數(shù)接口),然后仿真的DLL再調(diào)用授權(quán)DLL,這樣所有的輸入首先被仿真DLL截獲再傳遞給授權(quán)DLL,而授權(quán)DLL的輸出也首先傳遞給仿真DLL再傳遞給主程序,這樣就可以輕易的監(jiān)視二者之間的輸入輸出之間的關(guān)系,從而輕易的截獲DLL中的授權(quán)信息進(jìn)行修改再返回給主程序。2、目前隱式調(diào)用敏感DLL中可能存在的安全隱患以下通過兩個(gè)軟件的授權(quán)DLL來說明這種問題的嚴(yán)重性。如
3、下是兩個(gè)軟件中授權(quán)DLL的部分信息,如下圖所示:(圖1)通過工具OllyICE可以輕易的看出IoMonitor.exe調(diào)用授權(quán)DLL(XKeyAPI.DLL),這樣就很容易在調(diào)用這些API的地方設(shè)置斷點(diǎn),然后判斷輸入輸出的關(guān)系,從而達(dá)到破解的目的。(圖2)通過工具OllyICE可以輕易的看出sfeng.DLL中導(dǎo)出了很多函數(shù),其中含義也很明顯。GetHDID獲取硬盤的ID,GetCpuId獲取cpu的ID,WinAntiDebug反調(diào)試接口。而這些都是主程序需要調(diào)用的,比如:主程序通過GetHDID來獲取硬盤編碼,以這個(gè)硬盤ID的偽碼來生成授權(quán)碼,破解者很容易修改這些接口的輸出值或者干脆寫一個(gè)
4、sfeng.DLL來導(dǎo)出跟目標(biāo)sfeng.DLL一模一樣的導(dǎo)出函數(shù),而主程序卻完全不知曉。只要用戶有一套授權(quán)碼就可以讓GetHDID不管什么機(jī)器都返回一樣的值,從而達(dá)到任何機(jī)器都可以使用同一套授權(quán)碼。(圖3)如上圖所示,直接修改DLL中函數(shù)GetHDID(RVA地址:0093FF3C開始)的實(shí)現(xiàn),讓它直接返回固定的硬盤ID就可以達(dá)到一個(gè)授權(quán)到處使用的目的。其中:"WD-Z=AM9N 086529ksaiy"為需要返回的已經(jīng)授權(quán)的硬盤ID,我們直接返回這個(gè)值即可。把原來0093FF3C部分的代碼用nop替換掉,添加Call 008FFF60,后面添加字符串"WD-Z
5、=AM9N 086529ksaiy",Call 008FFF60之后,ESP=Call后的返回地址(Call指令的下一行),也就是字符串"WD-Z=AM9N 086529ksaiy"的首地址,然后pop EAX后,返回值就是字符串的首地址,通過這種簡單的修改就可以達(dá)到破解的目的,說明這種隱式的調(diào)用是非常危險(xiǎn)的。3、模擬Windows PE加載器,從資源中加載DLL本文主要介紹將DLL文件進(jìn)行加密壓縮后存放在程序的資源段,然后在程序中讀取資源段數(shù)據(jù)進(jìn)行解壓和解密工作后,從內(nèi)存中加載這個(gè)DLL,然后模擬PE加載器完成DLL的加載過程。本文主要以Visual C+6.0
6、為工具進(jìn)行介紹,其它開發(fā)工具實(shí)現(xiàn)過程與此類似。這樣作的好處也很明顯,DLL文件存放在主程序的資源段,而且經(jīng)過了加密壓縮處理,破解者很難找到下斷點(diǎn)的地方,也不能輕易修改資源DLL,因?yàn)橹挥兄鞒绦蛲瓿山鈮汉徒饷芄ぷ?,完成PE加載工作后此DLL才開始工作。我們知道,要顯式加載一個(gè)DLL,并取得其中導(dǎo)出的函數(shù)地址一般是通過如下步驟:(1)用LoadLibrary加載DLL文件,獲得該DLL的模塊句柄;(2)定義一個(gè)函數(shù)指針類型,并聲明一個(gè)變量;(3)用GetProcAddress取得該DLL中目標(biāo)函數(shù)的地址,賦值給函數(shù)指針變量;(4)調(diào)用函數(shù)指針變量。這個(gè)方法要求DLL文件位于硬盤上面,而我們的DLL
7、現(xiàn)在在內(nèi)存中?,F(xiàn)在假設(shè)我們的DLL已經(jīng)位于內(nèi)存中,比如通過脫殼、解密或者解壓縮得到,能不能不把它寫入硬盤文件,而直接從內(nèi)存加載呢?答案是肯定的,方法就是完成跟Windows PE加載器同樣的工作即可。加載過程大致包括以下幾個(gè)部分:1、調(diào)用API讀取DLL資源數(shù)據(jù)拷貝到內(nèi)存中2、調(diào)用解壓和解密函數(shù)對內(nèi)存中的DLL進(jìn)行處理3、檢查DOS頭和PE頭判斷是否為合法的PE格式4、計(jì)算加載該DLL所需的虛擬地址空間大小5、向操作系統(tǒng)申請指定大小的虛擬地址空間并提交6、將DLL數(shù)據(jù)復(fù)制到所分配的虛擬內(nèi)存塊中,注意文件段對齊方式和內(nèi)存段對齊方式7、對每個(gè)DLL文件來說都存在一個(gè)重定位節(jié)(.reloc),用于記
8、錄DLL文件的重定位信息,需要處理重定位信息8、讀取DLL的引入表部分,加載引入表部分需要的DLL,并填充需要的函數(shù)入口的真實(shí)地址9、根據(jù)DLL每個(gè)節(jié)的屬性設(shè)置其對應(yīng)內(nèi)存頁的讀寫屬性10、調(diào)用入口函數(shù)DLLMain,完成初始化工作11、保存DLL的基地址(即分配的內(nèi)存塊起始地址),用于查找DLL的導(dǎo)出函數(shù)12、不需要DLL的時(shí)候,釋放所分配的虛擬內(nèi)存,釋放所有動(dòng)態(tài)申請的內(nèi)存以下部分分別介紹這幾個(gè)步驟,以改造過的網(wǎng)上下載的CMemLoadDLL類為例程(原類存在幾個(gè)錯(cuò)誤的地方)A.調(diào)用API讀取DLL資源數(shù)據(jù)拷貝到內(nèi)存中/加載資源DLL#define strKey(char)0x15 char
9、DLLtype4='D'strKey,'l'strKey,'l'strKey,0x00;HINSTANCE hinst=AfxGetInstanceHandle();HRSRC hr=NULL;HGLOBAL hg=NULL;/對資源名稱字符串進(jìn)行簡單的異或操作,達(dá)到不能通過外部字符串參考下斷點(diǎn)for(int i=0;i sizeof(DLLtype)-1;i+)DLLtypei=strKey;hr=FindResource(hinst,MAKEINTRESOURCE(IDR_DLL),TEXT(DLLtype);if(NULL=hr)retur
10、n FALSE;/獲取資源的大小DWORD dwSize=SizeofResource(hinst,hr);if(0=dwSize)return FALSE;hg=LoadResource(hinst,hr);if(NULL=hg)return FALSE;/鎖定資源LPVOID pBuffer=(LPSTR)LockResource(hg);if(NULL=pBuffer)return FALSE;FreeResource(hg);/在資源使用完畢后我們不需要使用UnlockResource和FreeResource來手動(dòng)地釋放資源,因?yàn)樗鼈兌际?6位Windows遺留下來的,在Win32中
11、,在使用完畢后系統(tǒng)會自動(dòng)回收B.調(diào)用解壓和解密函數(shù)對內(nèi)存總的DLL進(jìn)行處理對于上面獲取的pBuffer可以進(jìn)行解壓和解密操作,算法應(yīng)該跟你加入的資源采取的算法進(jìn)行逆變換即可,具體算法可以自己選擇,此處省略。C.檢查DOS頭和PE頭判斷是否為合法的PE格式/CheckDataValide函數(shù)用于檢查緩沖區(qū)中的數(shù)據(jù)是否有效的DLL文件/是一個(gè)可執(zhí)行的DLL TRUE,否則返回FALSE。/lpFileData:存放DLL數(shù)據(jù)的內(nèi)存緩沖區(qū)/DataLength:DLL文件的長度BOOL CMemLoadDLL:CheckDataValide(void*lpFileData,int DataLengt
12、h)/檢查長度if(DataLength sizeof(IMAGE_DOS_HEADER)return FALSE;pDosHeader=(PIMAGE_DOS_HEADER)lpFileData;/DOS頭/檢查dos頭的標(biāo)記if(pDosHeader-e_magic!=IMAGE_DOS_SIGNATURE)return FALSE;/0*5A4D:MZ/檢查長度if(DWORD)DataLength(pDosHeader-e_lfanew+sizeof(IMAGE_NT_HEADERS)return FALSE;/取得pe頭pNTHeader=(PIMAGE_NT_HEADERS)(un
13、signed long)lpFileData+pDosHeader-e_lfanew);/PE頭/檢查pe頭的合法性if(pNTHeader-Signature!=IMAGE_NT_SIGNATURE)return FALSE;/0*00004550:PE00 if(pNTHeader-FileHeader.Characteristics&IMAGE_FILE_DLL)=0)/0*2000:File is aDLL return FALSE;if(pNTHeader-FileHeader.Characteristics&IMAGE_FILE_EXECUTABLE_IMAGE)=
14、0)/0*0002:指出文件可以運(yùn)行return FALSE;if(pNTHeader-FileHeader.SizeOfOptionalHeader!=sizeof(IMAGE_OPTIONAL_HEADER)return FALSE;/取得節(jié)表(段表)pSectionHeader=(PIMAGE_SECTION_HEADER)(int)pNTHeader+sizeof(IMAGE_NT_HEADERS);/驗(yàn)證每個(gè)節(jié)表的空間for(int i=0;i pNTHeader-FileHeader.NumberOfSections;i+)if(pSectionHeaderi.PointerToR
15、awData+pSectionHeaderi.SizeOfRawData)(DWORD)DataLength)return FALSE;return TRUE;D.計(jì)算加載該DLL所需的虛擬地址空間大小計(jì)算整個(gè)DLL映像文件的尺寸,最大映像尺寸應(yīng)該為VOffset最大的一個(gè)段的VOffset+VSize,然后補(bǔ)齊段對齊即可。如下圖中,最大映像尺寸應(yīng)該為0x0000D000+0x00000DA6,然后按段對齊(如為:0x1000對齊)則結(jié)果為0x0000E000。其中DOS Header和PE Header就占用0x1000字節(jié),代碼段.text從0x1000開始占用了0x7000字節(jié)。段名稱虛
16、擬地址虛擬大小物理地址物理大小標(biāo)志int CMemLoadDLL:CalcTotalImageSize()int Size;if(pNTHeader=NULL)return 0;int nAlign=pNTHeader-OptionalHeader.SectionAlignment;/段對齊字節(jié)數(shù)/計(jì)算所有頭的尺寸。包括dos,coff,pe頭和段表的大小Size=GetAlignedSize(pNTHeader-OptionalHeader.SizeOfHeaders,nAlign);/計(jì)算所有節(jié)的大小for(int i=0;i pNTHeader-FileHeader.NumberOfSe
17、ctions;+i)/得到該節(jié)的大小int CodeSize=pSectionHeaderi.Misc.VirtualSize;int LoadSize=pSectionHeaderi.SizeOfRawData;int MaxSize=(LoadSize CodeSize)?(LoadSize):(CodeSize);int SectionSize=GetAlignedSize(pSectionHeaderi.VirtualAddress+MaxSize,nAlign);if(Size SectionSize)Size=SectionSize;/Use the Max;return Size
18、;/計(jì)算對齊邊界int CMemLoadDLL:GetAlignedSize(int Origin,int Alignment)return(Origin+Alignment-1)/Alignment*Alignment;E.向操作系統(tǒng)申請指定大小的虛擬地址空間并提交調(diào)用操作系統(tǒng)API VirtualAlloc保留指定大小的虛擬內(nèi)存并提交內(nèi)存,VirtualAlloc的第一個(gè)參數(shù)不能指定地址,如果指定地址已經(jīng)被占用或者指定地址后面沒有足夠的連續(xù)的地址空間來滿足提交的大小則會調(diào)用失敗,而我們也沒有必要獲取指定地址空間,這樣第一個(gè)參數(shù)必須保留為NULL(0)。void*pMemoryAddress
19、=VirtualAlloc(LPVOID)NULL,ImageSize,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE);if(pMemoryAddress=NULL)return FALSE;F.將DLL數(shù)據(jù)復(fù)制到所分配的虛擬內(nèi)存塊中,注意文件段對齊方式和內(nèi)存段對齊方式拷貝內(nèi)存DLL到提交的虛擬地址空間,拷貝的部分包括PE文件的所有部分,DOS Header、PE Header、Section Table、Section 1Section N,如下圖所示:DOS MZ header DOS stub PE header Section table
20、Section 1Section 2Section.Section n/CopyDLLDatas函數(shù)將DLL數(shù)據(jù)復(fù)制到指定內(nèi)存區(qū)域,并對齊所有節(jié)/pSrc:存放DLL數(shù)據(jù)的原始緩沖區(qū)/pDest:目標(biāo)內(nèi)存地址void CMemLoadDLL:CopyDLLDatas(void*pDest,void*pSrc)/計(jì)算需要復(fù)制的PE頭+段表字節(jié)數(shù)int HeaderSize=pNTHeader-OptionalHeader.SizeOfHeaders;int SectionSize=pNTHeader-FileHeader.NumberOfSections*sizeof(IMAGE_SECTION
21、_HEADER);int MoveSize=HeaderSize+SectionSize;/復(fù)制頭和段信息memmove(pDest,pSrc,MoveSize);/復(fù)制每個(gè)節(jié)for(int i=0;i pNTHeader-FileHeader.NumberOfSections;+i)if(pSectionHeaderi.VirtualAddress=0|pSectionHeaderi.SizeOfRawData=0)continue;/定位該節(jié)在內(nèi)存中的位置void*pSectionAddress=(void*)(unsigned long)pDest+pSectionHeaderi.Vir
22、tualAddress);/復(fù)制段數(shù)據(jù)到虛擬內(nèi)存memmove(void*)pSectionAddress,(void*)(DWORD)pSrc+pSectionHeaderi.PointerToRawData),pSectionHeaderi.SizeOfRawData);/修正指針,指向新分配的內(nèi)存/新的dos頭pDosHeader=(PIMAGE_DOS_HEADER)pDest;/新的pe pNTHeader=(PIMAGE_NT_HEADERS)(int)pDest+(pDosHeader-e_lfanew);/新的節(jié)表地址pSectionHeader=(PIMAGE_SECTION
23、_HEADER)(int)pNTHeader+sizeof(IMAGE_NT_HEADERS);return;G.每個(gè)DLL文件來說都存在一個(gè)重定位節(jié)(.reloc),用于記錄DLL文件的重定位信息,需要處理重定位信息Windows加載DLL時(shí)就可以按照該節(jié)的信息對需要重定位的地址進(jìn)行修正,在32位代碼中,凡涉及到直接尋址的指令都是需要重定位的,而PE文件的的(.reloc)段則是可選的,因?yàn)镻E文件一般都可以加載到默認(rèn)地址(如:0x 00400000)。當(dāng)然系統(tǒng)的DLL其默認(rèn)加載地址都能滿足要求,因?yàn)檫@些DLL都在系統(tǒng)加載其它程序前首先被加載(如:Kernel32.DLL,User32.DL
24、L)等。對于操作系統(tǒng)來說,其任務(wù)就是在對可執(zhí)行程序透明的情況下完成重定位操作,在現(xiàn)實(shí)中,重定位信息是在編譯的時(shí)候由編譯器生成并被保留在可執(zhí)行文件中的,在程序被執(zhí)行前由操作系統(tǒng)根據(jù)重定位信息修正代碼,這樣在開發(fā)程序的時(shí)候就不用考慮重定位問題了。重定位信息在DLL文件中被存放在重定位表中,重定位的算法可以描述為:將直接尋址指令中的雙字地址加上模塊實(shí)際裝入地址與模塊建議裝入地址之差。為了進(jìn)行這個(gè)運(yùn)算,需要有3個(gè)數(shù)據(jù),首先是需要修正的機(jī)器碼地址;其次是模塊的建議裝入地址;最后是模塊的實(shí)際裝入地址。在這3個(gè)數(shù)據(jù)中,模塊的建議裝入地址已經(jīng)在PE文件頭中定義了(編譯后就已經(jīng)確定),而模塊的實(shí)際裝入地址是Wi
25、ndows裝載器確定的,到裝載文件的時(shí)候自然會知道,所以被保存在重定位表中的僅僅是需要修正的代碼的地址。事實(shí)上正是如此,DLL文件的重定位表中保存的就是一大堆需要修正的代碼的地址。重定位表一般會被單獨(dú)存放在一個(gè)可丟棄的以".reloc"命名的節(jié)中,但是這并不是必然的,因?yàn)橹囟ㄎ槐矸旁谄渌?jié)中也是合法的,惟一可以肯定的是,假如重定位表存在的話,它的地址肯定可以在DLL文件頭中的數(shù)據(jù)目錄中找到。重定位表的位置和大小可以從數(shù)據(jù)目錄中的第6個(gè)IMAGE_DATA_DIRECTORY結(jié)構(gòu)中獲取,雖然重定位表中的有用數(shù)據(jù)是那些需要重定位機(jī)器碼的地址指針,但為了節(jié)省空間,DLL文件對存放
26、的方式做了一些優(yōu)化。在正常的情況下,每個(gè)32位的指針占用4個(gè)字節(jié),假如有n個(gè)重定位項(xiàng),那么重定位表的總大小是4×n字節(jié)大小。直接尋址指令在程序中還是比較多的,在比較靠近的重定位表項(xiàng)中,32位指針的高位地址總是相同的,假如把這些相近表項(xiàng)的高位地址統(tǒng)一表示,那么就可以省略一部分的空間,當(dāng)按照一個(gè)內(nèi)存頁來分割時(shí),在一個(gè)頁面中尋址需要的指針位數(shù)是12位(一頁等于4096字節(jié),等于2的12次方),假如將這12位湊齊16位放入一個(gè)字類型的數(shù)據(jù)中,并用一個(gè)附加的雙字來表示頁的起始指針,另一個(gè)雙字來表示本頁中重定位項(xiàng)數(shù)的話,那么占用的總空間會是4+4+2×n字節(jié)大小,計(jì)算一下就可以發(fā)現(xiàn),當(dāng)
27、某個(gè)內(nèi)存頁中的重定位項(xiàng)多于4項(xiàng)的時(shí)候,后一種方法的占用空間就會比前面的方法要小。/重定向PE用到的地址void CMemLoadDLL:DoRelocation(void*NewBase)/*重定位表的結(jié)構(gòu):/DWORD sectionAddress,DWORD size(包括本節(jié)需要重定位的數(shù)據(jù)/例如1000節(jié)需要修正5個(gè)重定位數(shù)據(jù)的話,重定位表的數(shù)據(jù)是/00 10 00 00 14 00 00 00 xxxx xxxx xxxx xxxx xxxx 0000/-/給出節(jié)的偏移總尺寸=8+6*2需要修正的地址用于對齊4字節(jié)/重定位表是若干個(gè)相連,如果address和size都是0表示結(jié)束/需
28、要修正的地址是12位的,高4位是形態(tài)字,intel cpu下是3*/假設(shè)NewBase是0×600000,而文件中設(shè)置的缺省ImageBase是0×400000,則修正偏移量就是0×200000 DWORD Delta=(DWORD)NewBase-pNTHeader-OptionalHeader.ImageBase;/注意重定位表的位置可能和硬盤文件中的偏移地址不同,應(yīng)該使用加載后的地址PIMAGE_BASE_RELOCATION pLoc=(PIMAGE_BASE_RELOCATION)(unsigned long)NewBase+pNTHeader-Opti
29、onalHeader.DataDirectoryIMAGE_DIRECTORY_ENTRY_BASERELOC.VirtualAddress);while(pLoc-VirtualAddress+pLoc-SizeOfBlock)!=0)/開始掃描重定位表WORD*pLocData=(WORD*)(int)pLoc+sizeof(IMAGE_BASE_RELOCATION);/計(jì)算本節(jié)需要修正的重定位項(xiàng)(地址)的數(shù)目int NumberOfReloc=(pLoc-SizeOfBlock-sizeof(IMAGE_BASE_RELOCATION)/sizeof(WORD);for(int i=0
30、;i NumberOfReloc;i+)if(DWORD)(pLocDatai&0xF000)=0x 00003000)/這是一個(gè)需要修正的地址/舉例:/pLoc-VirtualAddress=0×1000;/pLocDatai=0×313E;表示本節(jié)偏移地址0×13E處需要修正/因此pAddress=+0×113E/里面的內(nèi)容是A1(0c d4 02 10)匯編代碼是:mov eax,1002d40c/需要修正1002d40c這個(gè)地址DWORD*pAddress=(DWORD*)(unsigned long)NewBase+pLoc-Virtu
31、alAddress+(pLocDatai&0x0FFF);*pAddress+=Delta;/轉(zhuǎn)移到下一個(gè)節(jié)進(jìn)行處理pLoc=(PIMAGE_BASE_RELOCATION)(DWORD)pLoc+pLoc-SizeOfBlock);H.讀取DLL的引入表部分,加載引入表部分需要的DLL,并填充需要的函數(shù)入口的真實(shí)地址對引入表中的DLL,通過GetModuleHandle獲得其加載基地址,如果這些DLL在加載本DLL之前還沒有加載,那么先調(diào)用LoadLibrary進(jìn)行加載,如果加載失敗則不能繼續(xù)處理直接報(bào)錯(cuò),說明找不到依賴的DLL。/填充引入地址表BOOL CMemLoadDLL:Fi
32、llRavAddress(void*pImageBase)/引入表實(shí)際上是一個(gè)IMAGE_IMPORT_DESCRIPTOR結(jié)構(gòu)數(shù)組,全部是0表示結(jié)束/數(shù)組定義如下:/DWORD OriginalFirstThunk;/0表示結(jié)束,否則指向未綁定的IAT結(jié)構(gòu)數(shù)組/DWORD TimeDateStamp;/DWORD ForwarderChain;/-1 if no forwarders/DWORD Name;/給出DLL的名字/DWORD FirstThunk;/指向IAT結(jié)構(gòu)數(shù)組的地址綁定后,這些IAT里面就是實(shí)際的函數(shù)地址unsigned long Offset=pNTHeader-Opt
33、ionalHeader.DataDirectoryIMAGE_DIRECTORY_ENTRY_IMPORT.VirtualAddress;if(Offset=0)return TRUE;/No Import Table PIMAGE_IMPORT_DESCRIPTOR pID=(PIMAGE_IMPORT_DESCRIPTOR)(unsigned long)pImageBase+Offset);while(pID-Characteristics!=0)PIMAGE_THUNK_DATA pRealIAT=(PIMAGE_THUNK_DATA)(unsigned long)pImageBase+
34、pID-FirstThunk);PIMAGE_THUNK_DATA pOriginalIAT=(PIMAGE_THUNK_DATA)(unsigned long)pImageBase+pID-OriginalFirstThunk);/獲取DLL的名字char buf256;/DLL name;/修改,需要將buf清零,否則DLL名稱不對memset(buf,0,sizeof(buf);BYTE*pName=(BYTE*)(unsigned long)pImageBase+pID-Name);for(int i=0;i 256;i+)if(pNamei=0)break;bufi=pNamei;H
35、MODULE hDLL=GetModuleHandle(buf);if(hDLL=NULL)hDLL=LoadLibrary(buf);/有可能依賴的DLL還沒有加載,如果沒有加載加載后再判斷是否加載成功if(hDLL=NULL)return FALSE;/NOT FOUND DLL/獲取DLL中每個(gè)導(dǎo)出函數(shù)的地址,填入IAT/每個(gè)IAT結(jié)構(gòu)是/unionPBYTE ForwarderString;/PDWORD Function;/DWORD Ordinal;/PIMAGE_IMPORT_BY_NAME AddressOfData;/u1;/長度是一個(gè)DWORD,正好容納一個(gè)地址。for(i
36、=0;i+)if(pOriginalIATi.u1.Function=0)break;FARPROC lpFunction=NULL;if(pOriginalIATi.u1.Ordinal&IMAGE_ORDINAL_FLAG)/這里的值給出的是導(dǎo)出序號lpFunction=GetProcAddress(hDLL,(LPCSTR)(pOriginalIATi.u1.Ordinal&0x0000FFFF);else/按照名字導(dǎo)入/獲取此IAT項(xiàng)所描述的函數(shù)名稱PIMAGE_IMPORT_BY_NAME pByName=(PIMAGE_IMPORT_BY_NAME)(DWORD)p
37、ImageBase+(DWORD)(pOriginalIATi.u1.AddressOfData);/if(pByName-Hint!=0)/lpFunction=GetProcAddress(hDLL,(LPCSTR)pByName-Hint);/else lpFunction=GetProcAddress(hDLL,(char*)pByName-Name);if(lpFunction!=NULL)/找到了!pRealIATi.u1.Function=(PDWORD)lpFunction;else return FALSE;/move to next pID=(PIMAGE_IMPORT_D
38、ESCRIPTOR)(DWORD)pID+sizeof(IMAGE_IMPORT_DESCRIPTOR);return TRUE;I.根據(jù)DLL每個(gè)節(jié)的屬性設(shè)置其對應(yīng)內(nèi)存頁的讀寫屬性修改段屬性。應(yīng)該根據(jù)每個(gè)段的屬性單獨(dú)設(shè)置其對應(yīng)內(nèi)存頁的屬性。這里簡化一下。統(tǒng)一設(shè)置成一個(gè)屬性PAGE_EXECUTE_READWRITE,如果代碼段沒有執(zhí)行屬性,調(diào)用的時(shí)候會產(chǎn)生異常,頁屬性的設(shè)置單位至少為一個(gè)頁。unsigned long old;VirtualProtect(pMemoryAddress,ImageSize,PAGE_EXECUTE_READWRITE,&old);J.調(diào)用入口函數(shù)DLL
39、Main,完成初始化工作接下來要調(diào)用一下DLL的入口函數(shù),做初始化工作,每個(gè)PE文件都有一個(gè)OEP,它就是AddressOfEntryPoint,一切代碼都是從這里開始,OEP+DLL基地址就是其真實(shí)入口地址,當(dāng)然這個(gè)入口地址一般都不是你所寫的main或者DLLMain,而是運(yùn)行庫提供的一段代碼,先完成全局變量的一些初始化和庫函數(shù)相關(guān)的初始化等,而這段代碼最后會調(diào)用真正的main或者DLLMain。pDLLMain=(ProcDLLMain)(pNTHeader-OptionalHeader.AddressOfEntryPoint+(DWORD)pMemoryAddress);BOOL Ini
40、tResult=pDLLMain(HINSTANCE)pMemoryAddress,DLL_PROCESS_ATTACH,0);if(!InitResult)/初始化失敗pDLLMain(HINSTANCE)pMemoryAddress,DLL_PROCESS_DETACH,0);VirtualFree(pMemoryAddress,0,MEM_RELEASE);pDLLMain=NULL;return FALSE;K.保存DLL的基地址(即分配的內(nèi)存塊起始地址),用于查找DLL的導(dǎo)出函數(shù)/修正基地址pNTHeader-OptionalHeader.ImageBase=(DWORD)pMemo
41、ryAddress;/MemGetProcAddress函數(shù)從dll中獲取指定函數(shù)的地址/成功返回函數(shù)地址,失敗返回NULL/lpProcName:要查找函數(shù)的名字或者序號FARPROC CMemLoadDll:MemGetProcAddress(LPCSTR lpProcName)if(pNTHeader-OptionalHeader.DataDirectoryIMAGE_DIRECTORY_ENTRY_EXPORT.VirtualAddress=0|pNTHeader-OptionalHeader.DataDirectoryIMAGE_DIRECTORY_ENTRY_EXPORT.Size
42、=0)return NULL;if(!isLoadOk)return NULL;DWORD OffsetStart=pNTHeader-OptionalHeader.DataDirectoryIMAGE_DIRECTORY_ENTRY_EXPORT.VirtualAddress;DWORD Size=pNTHeader-OptionalHeader.DataDirectoryIMAGE_DIRECTORY_ENTRY_EXPORT.Size;PIMAGE_EXPORT_DIRECTORY pExport=(PIMAGE_EXPORT_DIRECTORY)(DWORD)pImageBase+pN
43、THeader-OptionalHeader.DataDirectoryIMAGE_DIRECTORY_ENTRY_EXPORT.VirtualAddress);int iBase=pExport-Base;int iNumberOfFunctions=pExport-NumberOfFunctions;int iNumberOfNames=pExport-NumberOfNames;/=iNumberOfFunctions LPDWORD pAddressOfFunctions=(LPDWORD)(pExport-AddressOfFunctions+pImageBase);LPWORD p
44、AddressOfOrdinals=(LPWORD)(pExport-AddressOfNameOrdinals+pImageBase);LPDWORD pAddressOfNames=(LPDWORD)(pExport-AddressOfNames+pImageBase);int iOrdinal=-1;if(DWORD)lpProcName&0xFFFF0000)=0)/IT IS AORDINAL!iOrdinal=(DWORD)lpProcName&0x0000FFFF-iBase;else/use nameint iFound=-1;for(int i=0;i iNu
45、mberOfNames;i+)char*pName=(char*)(pAddressOfNamesi+pImageBase);if(strcmp(pName,lpProcName)=0)iFound=i;break;if(iFound=0)iOrdinal=(int)(pAddressOfOrdinalsiFound);if(iOrdinal 0|iOrdinal=iNumberOfFunctions)return NULL;elseDWORD pFunctionOffset=pAddressOfFunctionsiOrdinal;if(pFunctionOffset OffsetStart&
46、amp;&pFunctionOffset(OffsetStart+Size)/maybe Export Forwarding return NULL;else return(FARPROC)(pFunctionOffset+pImageBase);L.不需要DLL的時(shí)候,釋放所分配的虛擬內(nèi)存,釋放所有動(dòng)態(tài)申請的內(nèi)存CMemLoadDll:CMemLoadDll()if(isLoadOk)ASSERT(pImageBase!=NULL);ASSERT(pDllMain!=NULL);/脫鉤,準(zhǔn)備卸載dll pDllMain(HINSTANCE)pImageBase,DLL_PROCESS
47、_DETACH,0);VirtualFree(LPVOID)pImageBase,0,MEM_RELEASE);4、全部詳細(xì)代碼/以下代碼經(jīng)過Win2k Sp4/WinXp Sp2下測試通過/MemLoadDll.h:interface for the CMemLoadDll class./#if!defined(AFX_MEMLOADDLL_H_E1F5150A_B534_4940_9FBF_1E6CA0E50576_INCLUDED_)#define AFX_MEMLOADDLL_H_E1F5150A_B534_4940_9FBF_1E6CA0E50576_INCLUDED_#if _MS
48、C_VER 1000#pragma once#endif/_MSC_VER 1000 typedef BOOL(_stdcall*ProcDllMain)(HINSTANCE,DWORD,LPVOID);class CMemLoadDllpublic:CMemLoadDll();virtualCMemLoadDll();BOOL MemLoadLibrary(void*lpFileData,int DataLength);/Dll file data buffer FARPROC MemGetProcAddress(LPCSTR lpProcName);private:BOOL isLoadO
49、k;BOOL CheckDataValide(void*lpFileData,int DataLength);int CalcTotalImageSize();void CopyDllDatas(void*pDest,void*pSrc);BOOL FillRavAddress(void*pBase);void DoRelocation(void*pNewBase);int GetAlignedSize(int Origin,int Alignment);private:ProcDllMain pDllMain;private:DWORD pImageBase;PIMAGE_DOS_HEADE
50、R pDosHeader;PIMAGE_NT_HEADERS pNTHeader;PIMAGE_SECTION_HEADER pSectionHeader;#endif/!defined(AFX_MEMLOADDLL_H_E1F5150A_B534_4940_9FBF_1E6CA0E50576_INCLUDED_)/MemLoadDll.cpp:implementation of the CMemLoadDll class./#include"stdafx.h"#include"MemLoadDll.h"#ifdef _DEBUG#undef THIS_
51、FILE static char THIS_FILE=_FILE_;#define new DEBUG_NEW#endif/Construction/Destruction/CMemLoadDll:CMemLoadDll()isLoadOk=FALSE;pImageBase=NULL;pDllMain=NULL;CMemLoadDll:CMemLoadDll()if(isLoadOk)ASSERT(pImageBase!=NULL);ASSERT(pDllMain!=NULL);/脫鉤,準(zhǔn)備卸載dll pDllMain(HINSTANCE)pImageBase,DLL_PROCESS_DETA
52、CH,0);VirtualFree(LPVOID)pImageBase,0,MEM_RELEASE);/MemLoadLibrary函數(shù)從內(nèi)存緩沖區(qū)數(shù)據(jù)中加載一個(gè)dll到當(dāng)前進(jìn)程的地址空間,缺省位置0×10000000/成功返回TRUE,失敗返回FALSE/lpFileData:存放dll文件數(shù)據(jù)的緩沖區(qū)/DataLength:緩沖區(qū)中數(shù)據(jù)的總長度BOOL CMemLoadDll:MemLoadLibrary(void*lpFileData,int DataLength)if(pImageBase!=NULL)return FALSE;/已經(jīng)加載一個(gè)dll,還沒有釋放,不能加載新的d
53、ll/檢查數(shù)據(jù)有效性,并初始化if(!CheckDataValide(lpFileData,DataLength)return FALSE;/計(jì)算所需的加載空間int ImageSize=CalcTotalImageSize();if(ImageSize=0)return FALSE;/分配虛擬內(nèi)存/void*pMemoryAddress=VirtualAlloc(LPVOID)0x 10000000,ImageSize,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE);/修改,不指定dll基址申請內(nèi)存void*pMemoryAddress=Virt
54、ualAlloc(LPVOID)NULL,ImageSize,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE);if(pMemoryAddress=NULL)return FALSE;elseCopyDllDatas(pMemoryAddress,lpFileData);/復(fù)制dll數(shù)據(jù),并對齊每個(gè)段/重定位信息if(pNTHeader-OptionalHeader.DataDirectoryIMAGE_DIRECTORY_ENTRY_BASERELOC.VirtualAddress 0&&pNTHeader-OptionalHead
55、er.DataDirectoryIMAGE_DIRECTORY_ENTRY_BASERELOC.Size 0)DoRelocation(pMemoryAddress);/填充引入地址表if(!FillRavAddress(pMemoryAddress)/修正引入地址表失敗VirtualFree(pMemoryAddress,0,MEM_RELEASE);return FALSE;/修改頁屬性。應(yīng)該根據(jù)每個(gè)頁的屬性單獨(dú)設(shè)置其對應(yīng)內(nèi)存頁的屬性。這里簡化一下。/統(tǒng)一設(shè)置成一個(gè)屬性PAGE_EXECUTE_READWRITE unsigned long old;VirtualProtect(pMemoryAddress,ImageSize,PAGE_EXECUTE_READWRITE,&old);/修正基地址pNTHeader-OptionalHeader.ImageBase=(
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 工程技術(shù)咨詢合同
- 出租車公司轉(zhuǎn)讓合同
- 房地產(chǎn)團(tuán)購協(xié)議合同
- 場化清運(yùn)作業(yè)承包合同書
- 2025年新鄉(xiāng)a2貨運(yùn)從業(yè)資格證考試
- 建房施工安全責(zé)任協(xié)議書
- 醫(yī)藥行業(yè)客戶關(guān)系管理策略
- 食堂供貨商供貨合同協(xié)議書
- 手房改房轉(zhuǎn)讓合同
- 2025年西藏駕校考試客貨運(yùn)從業(yè)資格證考試題庫
- 行為規(guī)范教育中學(xué)校長在國旗下講話:嚴(yán)格要求自己規(guī)范自己的行為
- 2024年12月廣東廣州市港務(wù)局直屬事業(yè)單位引進(jìn)緊缺專業(yè)人才8人筆試歷年典型考題(歷年真題考點(diǎn))解題思路附帶答案詳解
- DBJ50-T-100-2022 建筑邊坡工程施工質(zhì)量驗(yàn)收標(biāo)準(zhǔn)
- 2025年寧夏工商職業(yè)技術(shù)學(xué)院高職單招職業(yè)適應(yīng)性測試近5年??及鎱⒖碱}庫含答案解析
- DB11-T 1004-2023 房屋建筑使用安全檢查評定技術(shù)規(guī)程
- 《藝術(shù)與傳播》課件
- 烹飪安全知識培訓(xùn)課件
- 2024年廣東職業(yè)技術(shù)學(xué)院高職單招語文歷年參考題庫含答案解析
- 2025年湖北宜昌枝江金潤源集團(tuán)招聘17人高頻重點(diǎn)提升(共500題)附帶答案詳解
- 2023CSCO兒童及青少年白血病診療指南
- 第一單元 閱讀綜合實(shí)踐(同步課件)【知識精研】七年級語文下冊高效課堂(統(tǒng)編版)
評論
0/150
提交評論