青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

S.l.e!ep.¢%

像打了激速一樣,以四倍的速度運(yùn)轉(zhuǎn),開心的工作
簡(jiǎn)單、開放、平等的公司文化;尊重個(gè)性、自由與個(gè)人價(jià)值;
posts - 1098, comments - 335, trackbacks - 0, articles - 1
  C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

【轉(zhuǎn)載】一種保護(hù)應(yīng)用程序的方法 模擬Windows PE加載器,從內(nèi)存資源中加載DLL

編程 2008-07-27 21:23:47 閱讀375 評(píng)論0 字號(hào):

來自 老實(shí)和尚博客

1、前言

目前很多敏感和重要的DLL(Dynamic-link library) 都沒有提供靜態(tài)版本供編譯器進(jìn)行靜態(tài)連接(.lib文件),即使提供了靜態(tài)版本也因?yàn)榧嫒菪詥栴}導(dǎo)致無法使用,而只提供DLL版本,并且很多專業(yè)軟件的授權(quán)部分的API,都是單獨(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)重性。如下是兩個(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è)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=AM9N086529ksaiy”為需要返回的已經(jīng)授權(quán)的硬盤ID,我們直接返回這個(gè)值即可。把原來0093FF3C 部分的代碼用nop替換掉,添加Call 008FFF60,后面添加字符串”WD-Z=AM9N086529ksaiy”,Call 008FFF60之后,ESP=Call后的返回地址(Call指令的下一行),也就是字符串”WD-Z=AM9N086529ksaiy”的首地址,然后pop EAX 后,返回值就是字符串的首地址,通過這種簡(jiǎn)單的修改就可以達(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為工具進(jìn)行介紹,其它開發(fā)工具實(shí)現(xiàn)過程與此類似。

這樣作的好處也很明顯,DLL文件存放在主程序的資源段,而且經(jīng)過了加密壓縮處理,破解者很難找到下斷點(diǎn)的地方,也不能輕易修改資源DLL,因?yàn)橹挥兄鞒绦蛲瓿山鈮汉徒饷芄ぷ鳎瓿蒔E加載工作后此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現(xiàn)在在內(nèi)存中。現(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ù)對(duì)內(nèi)存中的DLL 進(jìn)行處理

3 、檢查DOS 頭和PE 頭判斷是否為合法的PE 格式

4 、計(jì)算加載該DLL 所需的虛擬地址空間大小

5 、向操作系統(tǒng)申請(qǐng)指定大小的虛擬地址空間并提交

6 、將DLL 數(shù)據(jù)復(fù)制到所分配的虛擬內(nèi)存塊中,注意文件段對(duì)齊方式和內(nèi)存段對(duì)齊方式

7 、對(duì)每個(gè) DLL 文件來說都存在一個(gè)重定位節(jié)(.reloc) ,用于記錄DLL 文件的重定位信息,需要處理重定位信息

8 、讀取DLL 的引入表部分,加載引入表部分需要的DLL ,并填充需要的函數(shù)入口的真實(shí)地址

9 、根據(jù)DLL 每個(gè)節(jié)的屬性設(shè)置其對(duì)應(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)申請(qǐng)的內(nèi)存

以下部分分別介紹這幾個(gè)步驟,以改造過的網(wǎng)上下載的CMemLoadDLL類為例程(原類存在幾個(gè)錯(cuò)誤的地方)

A. 調(diào)用 API 讀取 DLL 資源數(shù)據(jù)拷貝到內(nèi)存中

// 加載資源 DLL

#define strKey (char)0x15

char DLLtype[4]={'D' ^ strKey ,'l'^ strKey,'l'^ strKey,0x00};

HINSTANCE hinst=AfxGetInstanceHandle();

HRSRC hr=NULL;

HGLOBAL hg=NULL;

// 對(duì)資源名稱字符串進(jìn)行簡(jiǎn)單的異或操作,達(dá)到不能通過外部字符串參考下斷點(diǎn)

for(int i=0;i<sizeof(DLLtype)-1;i++)

{

DLLtype[i]^=strKey;

}

hr=FindResource(hinst,MAKEINTRESOURCE(IDR_DLL),TEXT(DLLtype));

if (NULL == hr) return 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)樗鼈兌际?/b> 16 Windows 遺留下來的,在 Win32 中,在使用完畢后系統(tǒng)會(huì)自動(dòng)回收

B. 調(diào)用解壓和解密函數(shù)對(duì)內(nèi)存總的 DLL 進(jìn)行處理

對(duì)于上面獲取的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 DataLength)

{

// 檢查長度

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)( (unsigned 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 a DLL

return FALSE;

if((pNTHeader->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) == 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((pSectionHeader[i].PointerToRawData + pSectionHeader[i].SizeOfRawData) > (DWORD)DataLength)return FALSE;

}

return TRUE;

}

D. 計(jì)算加載該 DLL 所需的虛擬地址空間大小

計(jì)算整個(gè)DLL映像文件的尺寸,最大映像尺寸應(yīng)該為VOffset最大的一個(gè)段的VOffset+VSize,然后補(bǔ)齊段對(duì)齊即可。如下圖中,最大映像尺寸應(yīng)該為0x0000D000+0x00000DA6,然后按段對(duì)齊(如為:0x1000對(duì)齊)則結(jié)果為0x0000E000。其中DOS Header和PE Header就占用0x1000字節(jié),代碼段.text從0x1000開始占用了0x7000字節(jié)。

段名稱   虛擬地址  虛擬大小  物理地址 物理大小  標(biāo)志

?

int CMemLoadDLL::CalcTotalImageSize()

{

int Size;

if(pNTHeader == NULL)return 0;

int nAlign = pNTHeader->OptionalHeader.SectionAlignment; // 段對(duì)齊字節(jié)數(shù)

// 計(jì)算所有頭的尺寸。包括 dos, coff, pe 段表的大小

Size = GetAlignedSize(pNTHeader->OptionalHeader.SizeOfHeaders, nAlign);

// 計(jì)算所有節(jié)的大小

for(int i=0; i < pNTHeader->FileHeader.NumberOfSections; ++i)

{

// 得到該節(jié)的大小

int CodeSize = pSectionHeader[i].Misc.VirtualSize ;

int LoadSize = pSectionHeader[i].SizeOfRawData;

int MaxSize = (LoadSize > CodeSize)?(LoadSize):(CodeSize);

int SectionSize = GetAlignedSize(pSectionHeader[i].VirtualAddress + MaxSize, nAlign);

if(Size < SectionSize)

Size = SectionSize; //Use the Max;

}

return Size;

}

// 計(jì)算對(duì)齊邊界

int CMemLoadDLL::GetAlignedSize(int Origin, int Alignment)

{

return (Origin + Alignment - 1) / Alignment * Alignment;

}

E. 向操作系統(tǒng)申請(qǐng)指定大小的虛擬地址空間并提交

調(diào)用操作系統(tǒng)API VirtualAlloc保留指定大小的虛擬內(nèi)存并提交內(nèi)存,VirtualAlloc的第一個(gè)參數(shù)不能指定地址,如果指定地址已經(jīng)被占用或者指定地址后面沒有足夠的連續(xù)的地址空間來滿足提交的大小則會(huì)調(diào)用失敗,而我們也沒有必要獲取指定地址空間,這樣第一個(gè)參數(shù)必須保留為NULL(0)。

void *pMemoryAddress=VirtualAlloc((LPVOID)NULL, ImageSize,MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE);

if(pMemoryAddress == NULL)

{

return FALSE;

}

F. DLL 數(shù)據(jù)復(fù)制到所分配的虛擬內(nèi)存塊中,注意文件段對(duì)齊方式和內(nèi)存段對(duì)齊方式

拷貝內(nèi)存DLL到提交的虛擬地址空間,拷貝的部分包括PE文件的所有部分,DOS Header、 PE Header 、Section Table、Section 1~Section N,如下圖所示:

DOS MZ header

DOS stub

PE header

Section table

Section 1

Section 2

Section ...

Section n

//CopyDLLDatas 函數(shù)將 DLL 數(shù)據(jù)復(fù)制到指定內(nèi)存區(qū)域,并對(duì)齊所有節(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_HEADER);

int MoveSize = HeaderSize + SectionSize;

// 復(fù)制頭和段信息

memmove(pDest, pSrc, MoveSize);

// 復(fù)制每個(gè)節(jié)

for(int i=0; i < pNTHeader->FileHeader.NumberOfSections; ++i)

{

if(pSectionHeader[i].VirtualAddress == 0 || pSectionHeader[i].SizeOfRawData == 0) continue;

// 定位該節(jié)在內(nèi)存中的位置

void *pSectionAddress = (void *)((unsigned long)pDest + pSectionHeader[i].VirtualAddress);

// 復(fù)制段數(shù)據(jù)到虛擬內(nèi)存

memmove((void *)pSectionAddress,

(void *)((DWORD)pSrc + pSectionHeader[i].PointerToRawData),

pSectionHeader[i].SizeOfRawData);

}

// 修正指針,指向新分配的內(nèi)存

// 新的 dos

pDosHeader = (PIMAGE_DOS_HEADER)pDest;

// 新的 pe 頭地址

pNTHeader = (PIMAGE_NT_HEADERS)((int)pDest + (pDosHeader->e_lfanew));

// 新的節(jié)表地址

pSectionHeader = (PIMAGE_SECTION_HEADER)((int)pNTHeader + sizeof(IMAGE_NT_HEADERS));

return ;

}

G. 每個(gè) DLL 文件來說都存在一個(gè)重定位節(jié)( .reloc) ,用于記錄 DLL 文件的重定位信息,需要處理重定位信息

Windows加載DLL時(shí)就可以按照該節(jié)的信息對(duì)需要重定位的地址進(jìn)行修正,在32位代碼中,凡涉及到直接尋址的指令都是需要重定位的,而PE文件的的(.reloc)段則是可選的,因?yàn)镻E文件一般都可以加載到默認(rèn)地址(如:0x00400000)。當(dāng)然系統(tǒng)的DLL其默認(rèn)加載地址都能滿足要求,因?yàn)檫@些DLL都在系統(tǒng)加載其它程序前首先被加載(如:Kernel32.DLL,User32.DLL)等。

對(duì)于操作系統(tǒng)來說,其任務(wù)就是在對(duì)可執(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í)際裝入地址是Windows裝載器確定的,到裝載文件的時(shí)候自然會(huì)知道,所以被保存在重定位表中的僅僅是需要修正的代碼的地址。

事實(shí)上正是如此,DLL文件的重定位表中保存的就是一大堆需要修正的代碼的地址。

重定位表一般會(huì)被單獨(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文件對(duì)存放的方式做了一些優(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ù)的話,那么占用的總空間會(huì)是4+4+2×n字節(jié)大 小,計(jì)算一下就可以發(fā)現(xiàn),當(dāng)某個(gè)內(nèi)存頁中的重定位項(xiàng)多于4項(xiàng)的時(shí)候,后一種方法的占用空間就會(huì)比前面的方法要小。

// 重定向 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 需要修正的地址 用于對(duì)齊 4 字節(jié)

// 重定位表是若干個(gè)相連,如果 address size 都是 0 表示結(jié)束

// 需要修正的地址是 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->OptionalHeader.DataDirectory[IMAGE_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 ; i < NumberOfReloc; i++)

{

if( (DWORD)(pLocData[i] & 0xF000) == 0x00003000) // 這是一個(gè)需要修正的地址

{

// 舉例:

// pLoc->VirtualAddress = 0×1000;

// pLocData[i] = 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->VirtualAddress + (pLocData[i] & 0x0FFF));

*pAddress += Delta;

}

}

// 轉(zhuǎn)移到下一個(gè)節(jié)進(jìn)行處理

pLoc = (PIMAGE_BASE_RELOCATION)((DWORD)pLoc + pLoc->SizeOfBlock);

}

}

H. 讀取 DLL 的引入表部分,加載引入表部分需要的 DLL ,并填充需要的函數(shù)入口的真實(shí)地址

對(duì)引入表中的DLL,通過GetModuleHandle獲得其加載基地址,如果這些DLL在加載本DLL之前還沒有加載,那么先調(diào)用LoadLibrary進(jìn)行加載,如果加載失敗則不能繼續(xù)處理直接報(bào)錯(cuò),說明找不到依賴的DLL。

// 填充引入地址表

BOOL CMemLoadDLL::FillRavAddress(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->OptionalHeader.DataDirectory[IMAGE_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 + pID->FirstThunk);

PIMAGE_THUNK_DATA pOriginalIAT = (PIMAGE_THUNK_DATA)((unsigned long)pImageBase + pID->OriginalFirstThunk);

// 獲取 DLL 的名字

char buf[256]; //DLL name;

// 修改 , 需要將 buf 清零 , 否則 DLL 名稱不對(duì)

memset(buf,0,sizeof(buf));

BYTE* pName = (BYTE*)((unsigned long)pImageBase + pID->Name);

for(int i=0;i<256;i++)

{

if(pName[i] == 0)break;

buf[i] = pName[i];

}

HMODULE 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)是

// union { PBYTE ForwarderString;

// PDWORD Function;

// DWORD Ordinal;

// PIMAGE_IMPORT_BY_NAME AddressOfData;

// } u1;

// 長度是一個(gè) DWORD ,正好容納一個(gè)地址。

for(i=0; ;i++)

{

if(pOriginalIAT[i].u1.Function == 0) break;

FARPROC lpFunction = NULL;

if(pOriginalIAT[i].u1.Ordinal & IMAGE_ORDINAL_FLAG) // 這里的值給出的是導(dǎo)出序號(hào)

{

lpFunction = GetProcAddress(hDLL, (LPCSTR)(pOriginalIAT[i].u1.Ordinal & 0x0000FFFF));

}

else // 按照名字導(dǎo)入

{

// 獲取此 IAT 項(xiàng)所描述的函數(shù)名稱

PIMAGE_IMPORT_BY_NAME pByName = (PIMAGE_IMPORT_BY_NAME)

((DWORD)pImageBase + (DWORD)(pOriginalIAT[i].u1.AddressOfData));

// if(pByName->Hint !=0)

// lpFunction = GetProcAddress(hDLL, (LPCSTR)pByName->Hint);

// else

lpFunction = GetProcAddress(hDLL, (char *)pByName->Name);

}

if(lpFunction != NULL) // 找到了!

{

pRealIAT[i].u1.Function = (PDWORD) lpFunction;

}

else return FALSE;

}

//move to next

pID = (PIMAGE_IMPORT_DESCRIPTOR)( (DWORD)pID + sizeof(IMAGE_IMPORT_DESCRIPTOR));

}

return TRUE;

}

I. 根據(jù) DLL 每個(gè)節(jié)的屬性設(shè)置其對(duì)應(yīng)內(nèi)存頁的讀寫屬性

修改段屬性。應(yīng)該根據(jù)每個(gè)段的屬性單獨(dú)設(shè)置其對(duì)應(yīng)內(nèi)存頁的屬性。這里簡(jiǎn)化一下。

統(tǒng)一設(shè)置成一個(gè)屬性PAGE_EXECUTE_READWRITE,如果代碼段沒有執(zhí)行屬性,調(diào)用的時(shí)候會(huì)產(chǎn)生異常,頁屬性的設(shè)置單位至少為一個(gè)頁。

unsigned long old;

VirtualProtect(pMemoryAddress, ImageSize, PAGE_EXECUTE_READWRITE,&old);

J. 調(diào)用入口函數(shù) DLLMain ,完成初始化工作

接下來要調(diào)用一下DLL的入口函數(shù),做初始化工作,每個(gè)PE文件都有一個(gè)OEP, 它就是AddressOfEntryPoint,一切代碼都是從這里開始,OEP+DLL基地址就是其真實(shí)入口地址,當(dāng)然這個(gè)入口地址一般都不是你所寫的main或者DLLMain,而是運(yùn)行庫提供的一段代碼,先完成全局變量的一些初始化和庫函數(shù)相關(guān)的初始化等,而這段代碼最后會(huì)調(diào)用真正的main或者DLLMain。

pDLLMain = (ProcDLLMain)(pNTHeader->OptionalHeader.AddressOfEntryPoint +(DWORD) pMemoryAddress);

BOOL InitResult = 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)pMemoryAddress;

//MemGetProcAddress 函數(shù)從 dll 中獲取指定函數(shù)的地址

// 返回值: 成功返回函數(shù)地址 , 失敗返回 NULL

//lpProcName: 要查找函數(shù)的名字或者序號(hào)

FARPROC CMemLoadDll::MemGetProcAddress(LPCSTR lpProcName)

{

if(pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress == 0 ||

pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size == 0)

return NULL;

if(!isLoadOk) return NULL;

DWORD OffsetStart = pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;

DWORD Size = pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;

PIMAGE_EXPORT_DIRECTORY pExport = (PIMAGE_EXPORT_DIRECTORY)((DWORD)pImageBase + pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);

int iBase = pExport->Base;

int iNumberOfFunctions = pExport->NumberOfFunctions;

int iNumberOfNames = pExport->NumberOfNames; //<= iNumberOfFunctions

LPDWORD pAddressOfFunctions = (LPDWORD)(pExport->AddressOfFunctions + pImageBase);

LPWORD pAddressOfOrdinals = (LPWORD)(pExport->AddressOfNameOrdinals + pImageBase);

LPDWORD pAddressOfNames = (LPDWORD)(pExport->AddressOfNames + pImageBase);

int iOrdinal = -1;

if(((DWORD)lpProcName & 0xFFFF0000) == 0) //IT IS A ORDINAL!

{

iOrdinal = (DWORD)lpProcName & 0x0000FFFF - iBase;

}

else //use name

{

int iFound = -1;

for(int i=0;i<iNumberOfNames;i++)

{

char* pName= (char* )(pAddressOfNames[i] + pImageBase);

if(strcmp(pName, lpProcName) == 0)

{

iFound = i; break;

}

}

if(iFound >= 0)

{

iOrdinal = (int)(pAddressOfOrdinals[iFound]);

}

}

if(iOrdinal < 0 || iOrdinal >= iNumberOfFunctions ) return NULL;

else

{

DWORD pFunctionOffset = pAddressOfFunctions[iOrdinal];

if(pFunctionOffset > OffsetStart && pFunctionOffset < (OffsetStart+Size))//maybe Export Forwarding

return NULL;

else return (FARPROC)(pFunctionOffset + pImageBase);

}

}

L. 不需要 DLL 的時(shí)候,釋放所分配的虛擬內(nèi)存,釋放所有動(dòng)態(tài)申請(qǐng)的內(nèi)存

CMemLoadDll::~CMemLoadDll()

{

if(isLoadOk)

{

ASSERT(pImageBase != NULL);

ASSERT(pDllMain != NULL);

// 脫鉤,準(zhǔn)備卸載 dll

pDllMain((HINSTANCE)pImageBase,DLL_PROCESS_DETACH,0);

VirtualFree((LPVOID)pImageBase, 0, MEM_RELEASE);

}

}

4、全部詳細(xì)代碼

// 以下代碼經(jīng)過Win2k Sp4/WinXp Sp2 下測(cè)試通過

// 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 _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

typedef BOOL (__stdcall *ProcDllMain)(HINSTANCE, DWORD, LPVOID );

class CMemLoadDll

{

public:

CMemLoadDll();

virtual ~CMemLoadDll();

BOOL MemLoadLibrary( void* lpFileData , int DataLength); // Dll file data buffer

FARPROC MemGetProcAddress(LPCSTR lpProcName);

private:

BOOL isLoadOk;

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_HEADER 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_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_DETACH,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 ,還沒有釋放,不能加載新的dll

}

// 檢查數(shù)據(jù)有效性,并初始化

if(!CheckDataValide(lpFileData, DataLength))return FALSE;

// 計(jì)算所需的加載空間

int ImageSize = CalcTotalImageSize();

if(ImageSize == 0) return FALSE;

// 分配虛擬內(nèi)存

//void *pMemoryAddress = VirtualAlloc((LPVOID)0x10000000, ImageSize,MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE);

// 修改, 不指定dll 基址申請(qǐng)內(nèi)存

void *pMemoryAddress = VirtualAlloc((LPVOID)NULL, ImageSize,MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE);

if(pMemoryAddress == NULL)

{

return FALSE;

}

else

{

CopyDllDatas(pMemoryAddress, lpFileData); // 復(fù)制dll 數(shù)據(jù),并對(duì)齊每個(gè)段

// 重定位信息

if(pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress >0

&& pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size>0)

{

DoRelocation(pMemoryAddress);

}

// 填充引入地址表

if(!FillRavAddress(pMemoryAddress)) // 修正引入地址表失敗

{

VirtualFree(pMemoryAddress,0,MEM_RELEASE);

return FALSE;

}

// 修改頁屬性。應(yīng)該根據(jù)每個(gè)頁的屬性單獨(dú)設(shè)置其對(duì)應(yīng)內(nèi)存頁的屬性。這里簡(jiǎn)化一下。

// 統(tǒng)一設(shè)置成一個(gè)屬性PAGE_EXECUTE_READWRITE

unsigned long old;

VirtualProtect(pMemoryAddress, ImageSize, PAGE_EXECUTE_READWRITE,&old);

}

// 修正基地址

pNTHeader->OptionalHeader.ImageBase = (DWORD)pMemoryAddress;

// 接下來要調(diào)用一下dll 的入口函數(shù),做初始化工作。

pDllMain = (ProcDllMain)(pNTHeader->OptionalHeader.AddressOfEntryPoint +(DWORD) pMemoryAddress);

BOOL InitResult = 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;

}

isLoadOk = TRUE;

pImageBase = (DWORD)pMemoryAddress;

return TRUE;

}

//MemGetProcAddress 函數(shù)從dll 中獲取指定函數(shù)的地址

// 返回值: 成功返回函數(shù)地址 , 失敗返回NULL

//lpProcName: 要查找函數(shù)的名字或者序號(hào)

FARPROC CMemLoadDll::MemGetProcAddress(LPCSTR lpProcName)

{

if(pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress == 0 ||

pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size == 0)

return NULL;

if(!isLoadOk) return NULL;

DWORD OffsetStart = pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;

DWORD Size = pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;

PIMAGE_EXPORT_DIRECTORY pExport = (PIMAGE_EXPORT_DIRECTORY)((DWORD)pImageBase + pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);

int iBase = pExport->Base;

int iNumberOfFunctions = pExport->NumberOfFunctions;

int iNumberOfNames = pExport->NumberOfNames; //<= iNumberOfFunctions

LPDWORD pAddressOfFunctions = (LPDWORD)(pExport->AddressOfFunctions + pImageBase);

LPWORD pAddressOfOrdinals = (LPWORD)(pExport->AddressOfNameOrdinals + pImageBase);

LPDWORD pAddressOfNames = (LPDWORD)(pExport->AddressOfNames + pImageBase);

int iOrdinal = -1;

if(((DWORD)lpProcName & 0xFFFF0000) == 0) //IT IS A ORDINAL!

{

iOrdinal = (DWORD)lpProcName & 0x0000FFFF - iBase;

}

else //use name

{

int iFound = -1;

for(int i=0;i<iNumberOfNames;i++)

{

char* pName= (char* )(pAddressOfNames[i] + pImageBase);

if(strcmp(pName, lpProcName) == 0)

{

iFound = i; break;

}

}

if(iFound >= 0)

{

iOrdinal = (int)(pAddressOfOrdinals[iFound]);

}

}

if(iOrdinal < 0 || iOrdinal >= iNumberOfFunctions ) return NULL;

else

{

DWORD pFunctionOffset = pAddressOfFunctions[iOrdinal];

if(pFunctionOffset > OffsetStart && pFunctionOffset < (OffsetStart+Size))//maybe Export Forwarding

return NULL;

else return (FARPROC)(pFunctionOffset + pImageBase);

}

}

// 重定向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 需要修正的地址 用于對(duì)齊4 字節(jié)

// 重定位表是若干個(gè)相連,如果address 和 size 都是0 表示結(jié)束

// 需要修正的地址是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->OptionalHeader.DataDirectory[IMAGE_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 ; i < NumberOfReloc; i++)

{

if( (DWORD)(pLocData[i] & 0xF000) == 0x00003000) // 這是一個(gè)需要修正的地址

{

// 舉例:

// pLoc->VirtualAddress = 0×1000;

// pLocData[i] = 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->VirtualAddress + (pLocData[i] & 0x0FFF));

*pAddress += Delta;

}

}

// 轉(zhuǎn)移到下一個(gè)節(jié)進(jìn)行處理

pLoc = (PIMAGE_BASE_RELOCATION)((DWORD)pLoc + pLoc->SizeOfBlock);

}

}

// 填充引入地址表

BOOL CMemLoadDll::FillRavAddress(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->OptionalHeader.DataDirectory[IMAGE_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 + pID->FirstThunk);

PIMAGE_THUNK_DATA pOriginalIAT = (PIMAGE_THUNK_DATA)((unsigned long)pImageBase + pID->OriginalFirstThunk);

// 獲取dll 的名字

char buf[256]; //dll name;

// 修改, 需要buf 清零, 否則dll 名稱不對(duì)

memset(buf,0,sizeof(buf));

BYTE* pName = (BYTE*)((unsigned long)pImageBase + pID->Name);

for(int i=0;i<256;i++)

{

if(pName[i] == 0)break;

buf[i] = pName[i];

}

HMODULE 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)是

// union { PBYTE ForwarderString;

// PDWORD Function;

// DWORD Ordinal;

// PIMAGE_IMPORT_BY_NAME AddressOfData;

// } u1;

// 長度是一個(gè)DWORD ,正好容納一個(gè)地址。

for(i=0; ;i++)

{

if(pOriginalIAT[i].u1.Function == 0) break;

FARPROC lpFunction = NULL;

if(pOriginalIAT[i].u1.Ordinal & IMAGE_ORDINAL_FLAG) // 這里的值給出的是導(dǎo)出序號(hào)

{

lpFunction = GetProcAddress(hDll, (LPCSTR)(pOriginalIAT[i].u1.Ordinal & 0x0000FFFF));

}

else // 按照名字導(dǎo)入

{

// 獲取此IAT 項(xiàng)所描述的函數(shù)名稱

PIMAGE_IMPORT_BY_NAME pByName = (PIMAGE_IMPORT_BY_NAME)

((DWORD)pImageBase + (DWORD)(pOriginalIAT[i].u1.AddressOfData));

// if(pByName->Hint !=0)

// lpFunction = GetProcAddress(hDll, (LPCSTR)pByName->Hint);

// else

lpFunction = GetProcAddress(hDll, (char *)pByName->Name);

}

if(lpFunction != NULL) // 找到了!

{

pRealIAT[i].u1.Function = (PDWORD) lpFunction;

}

else return FALSE;

}

//move to next

pID = (PIMAGE_IMPORT_DESCRIPTOR)( (DWORD)pID + sizeof(IMAGE_IMPORT_DESCRIPTOR));

}

return TRUE;

}

//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 DataLength)

{

// 檢查長度

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)( (unsigned 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 a DLL

return FALSE;

if((pNTHeader->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) == 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((pSectionHeader[i].PointerToRawData + pSectionHeader[i].SizeOfRawData) > (DWORD)DataLength)return FALSE;

}

return TRUE;

}

// 計(jì)算對(duì)齊邊界

int CMemLoadDll::GetAlignedSize(int Origin, int Alignment)

{

return (Origin + Alignment - 1) / Alignment * Alignment;

}

// 計(jì)算整個(gè)dll 映像文件的尺寸

int CMemLoadDll::CalcTotalImageSize()

{

int Size;

if(pNTHeader == NULL)return 0;

int nAlign = pNTHeader->OptionalHeader.SectionAlignment; // 段對(duì)齊字節(jié)數(shù)

// 計(jì)算所有頭的尺寸。包括dos, coff, pe 段表的大小

Size = GetAlignedSize(pNTHeader->OptionalHeader.SizeOfHeaders, nAlign);

// 計(jì)算所有節(jié)的大小

for(int i=0; i < pNTHeader->FileHeader.NumberOfSections; ++i)

{

// 得到該節(jié)的大小

int CodeSize = pSectionHeader[i].Misc.VirtualSize ;

int LoadSize = pSectionHeader[i].SizeOfRawData;

int MaxSize = (LoadSize > CodeSize)?(LoadSize):(CodeSize);

int SectionSize = GetAlignedSize(pSectionHeader[i].VirtualAddress + MaxSize, nAlign);

if(Size < SectionSize)

Size = SectionSize; //Use the Max;

}

return Size;

}

//CopyDllDatas 函數(shù)將dll 數(shù)據(jù)復(fù)制到指定內(nèi)存區(qū)域,并對(duì)齊所有節(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_HEADER);

int MoveSize = HeaderSize + SectionSize;

// 復(fù)制頭和段信息

memmove(pDest, pSrc, MoveSize);

// 復(fù)制每個(gè)節(jié)

for(int i=0; i < pNTHeader->FileHeader.NumberOfSections; ++i)

{

if(pSectionHeader[i].VirtualAddress == 0 || pSectionHeader[i].SizeOfRawData == 0) continue;

// 定位該節(jié)在內(nèi)存中的位置

void *pSectionAddress = (void *)((unsigned long)pDest + pSectionHeader[i].VirtualAddress);

// 復(fù)制段數(shù)據(jù)到虛擬內(nèi)存

memmove((void *)pSectionAddress,

(void *)((DWORD)pSrc + pSectionHeader[i].PointerToRawData),

pSectionHeader[i].SizeOfRawData);

}

// 修正指針,指向新分配的內(nèi)存

// 新的dos

pDosHeader = (PIMAGE_DOS_HEADER)pDest;

// 新的pe 頭地址

pNTHeader = (PIMAGE_NT_HEADERS)((int)pDest + (pDosHeader->e_lfanew));

// 新的節(jié)表地址

pSectionHeader = (PIMAGE_SECTION_HEADER)((int)pNTHeader + sizeof(IMAGE_NT_HEADERS));

return ;

}

// 加載資源 DLL

#define strKey (char)0x15

char DLLtype[4]={'D' ^ strKey ,'l'^ strKey,'l'^ strKey,0x00};

HINSTANCE hinst=AfxGetInstanceHandle();

HRSRC hr=NULL;

HGLOBAL hg=NULL;

// 對(duì)資源名稱字符串進(jìn)行簡(jiǎn)單的異或操作,達(dá)到不能通過外部字符串參考下斷點(diǎn)

for(int i=0;i<sizeof(DLLtype)-1;i++)

{

DLLtype[i]^=strKey;

}

hr=FindResource(hinst,MAKEINTRESOURCE(IDR_DLL),TEXT(DLLtype));

if (NULL == hr) return 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;

// 對(duì) pBuffer 進(jìn)行處理

pMemLoadDll=new CMemLoadDll();

if(pMemLoadDll->MemLoadLibrary(pBuffer, dwSize)) // 加載 dll 到當(dāng)前進(jìn)程的地址空間

{

for(int i=0;i<sizeof(dllname)-1;i++)

{

dllname[i]^=strKey;

}

SENSE3 = (DllSENSE3)pMemLoadDll->MemGetProcAddress(dllname);

if(SENSE3 == NULL)

{

return TRUE;

}

}

FreeResource(hg); // 在資源使用完畢后我們不需要使用 UnlockResource FreeResource 來手動(dòng)地釋放資源,因?yàn)樗鼈兌际?/b> 16 Windows 遺留下來的,在 Win32 中,在使用完畢后系統(tǒng)會(huì)自動(dòng)回收。

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美成人激情视频| 国产综合欧美| 亚洲特级毛片| 99国内精品| 亚洲午夜91| 午夜精品美女久久久久av福利| 中日韩美女免费视频网址在线观看| 亚洲精品永久免费| 一区二区三区久久久| 亚洲一区二区成人| 久久精品夜色噜噜亚洲a∨| 久久久久成人精品| 欧美二区不卡| 国产精品盗摄久久久| 国产美女精品人人做人人爽| 国产亚洲aⅴaaaaaa毛片| 在线观看国产一区二区| 亚洲毛片播放| 亚洲综合精品| 免费在线观看日韩欧美| 亚洲精选在线观看| 午夜精品影院| 欧美精品一区二| 国产欧美日韩亚洲| 亚洲精品小视频| 久久gogo国模啪啪人体图| 欧美高清在线播放| 亚洲欧美日韩高清| 欧美99在线视频观看| 国产精品免费一区豆花| 亚洲黄色视屏| 久久精品国产亚洲一区二区| 亚洲欧洲精品天堂一级| 亚洲欧美激情精品一区二区| 欧美激情二区三区| 在线播放亚洲一区| 午夜精品剧场| 亚洲精品国产精品久久清纯直播| 性欧美8khd高清极品| 欧美日本一区二区三区| 亚洲福利视频网| 久久久精品国产免大香伊| 一本色道久久综合亚洲精品高清 | 99ri日韩精品视频| 久久婷婷色综合| 国产伦理一区| 亚洲视频精品在线| 亚洲国产清纯| 久久在线免费| 激情一区二区三区| 欧美在线视频一区| 亚洲深夜影院| 欧美日韩一区二区三区| 99精品欧美一区二区蜜桃免费| 久久综合久久美利坚合众国| 欧美一区二区久久久| 国产精品亚洲综合天堂夜夜| 欧美在线关看| 在线一区免费观看| 欧美1区视频| 在线观看成人网| 免费在线观看日韩欧美| 久久久久久久久久码影片| 韩日精品中文字幕| 久久成人精品一区二区三区| 亚洲伊人观看| 国产农村妇女精品| 久久gogo国模裸体人体| 欧美一级淫片aaaaaaa视频| 国产乱子伦一区二区三区国色天香| 亚洲欧美日韩天堂| 午夜亚洲一区| 亚洲成人在线免费| 亚洲国产欧美久久| 欧美精选一区| 亚洲欧美经典视频| 欧美有码在线视频| 亚洲国产精品传媒在线观看 | 欧美伊人精品成人久久综合97| 国产精品日韩欧美一区| 久久久久.com| 久久综合电影| 99精品国产99久久久久久福利| 亚洲精一区二区三区| 国产精品一区二区久激情瑜伽| 久久大综合网| 欧美+日本+国产+在线a∨观看| 一本色道久久综合亚洲精品婷婷 | 亚洲午夜未删减在线观看| 国产精品一区二区三区四区五区| 久久蜜桃av一区精品变态类天堂| 久久久久免费| 亚洲视频欧洲视频| 久久精品一本| 亚洲一区二区视频| 久久精品亚洲国产奇米99| 亚洲精品一区在线| 午夜精品成人在线视频| 亚洲欧洲精品一区二区精品久久久 | 欧美成人一区在线| 国产精品久久久久久久久久ktv| 欧美在线观看视频| 欧美激情免费在线| 欧美一区二区免费视频| 美女国内精品自产拍在线播放| 一区二区国产精品| 久久久久国产成人精品亚洲午夜| 一区二区欧美在线| 久久久久亚洲综合| 小处雏高清一区二区三区 | 国产精品夜夜夜| 久久中文字幕导航| 久久精品观看| 久久综合色婷婷| 亚洲少妇最新在线视频| 久久久精品网| 午夜精品福利在线| 欧美激情精品久久久久久变态| 久久xxxx精品视频| 欧美三级中文字幕在线观看| 蜜臀91精品一区二区三区| 国产精品视频专区| 一区二区三区高清在线| 亚洲精品人人| 麻豆精品在线播放| 六月天综合网| 狠狠色综合一区二区| 亚洲欧美成人| 亚洲欧美国产不卡| 国产精品久久久91| 一区二区三区四区五区在线 | 亚洲一二三区在线观看| 欧美黄色片免费观看| 欧美1区3d| 亚洲电影av在线| 久久久久综合网| 麻豆精品精品国产自在97香蕉| 国产一区二区三区成人欧美日韩在线观看 | 欧美激情综合亚洲一二区 | 亚洲男人的天堂在线观看| 欧美日本视频在线| 亚洲精品乱码久久久久久按摩观 | 99国产精品国产精品毛片| 日韩一级免费| 欧美日韩的一区二区| 亚洲乱码国产乱码精品精可以看| 亚洲每日更新| 欧美日韩视频免费播放| 亚洲精品乱码久久久久| 亚洲午夜av电影| 欧美性猛交xxxx乱大交退制版| 这里只有精品在线播放| 欧美在线视频免费播放| 一区二区在线不卡| 美女主播精品视频一二三四| 欧美黑人多人双交| 一区二区精品在线| 国产精品美女www爽爽爽视频 | 欧美全黄视频| 日韩午夜在线观看视频| 午夜亚洲一区| 国产一区二区激情| 欧美www在线| 亚洲精品一品区二品区三品区| 日韩亚洲一区在线播放| 国产丝袜一区二区| 久久久久久69| 亚洲精品一区二区三区99| 亚洲欧美日韩在线不卡| 国产亚洲一区二区三区在线观看| 欧美在线视频网站| 亚洲电影免费观看高清完整版在线 | 精品不卡在线| 欧美高清视频一区| 亚洲欧美日韩另类| 最新中文字幕一区二区三区| 欧美一区久久| 亚洲精品欧美| 国产在线一区二区三区四区| 欧美激情精品久久久久久黑人| 宅男噜噜噜66国产日韩在线观看| 六十路精品视频| 亚洲男女自偷自拍| 亚洲经典一区| 国产一区美女| 国产精品qvod| 欧美成人精品在线观看| 午夜精品国产精品大乳美女| 亚洲电影专区| 久久久99久久精品女同性| 一区二区高清视频| 亚洲国产天堂久久综合网| 国产精品美女| 欧美日韩国产美| 免费在线观看一区二区| 久久精品99无色码中文字幕| 99国产一区| 91久久夜色精品国产九色| 欧美成人午夜视频| 美女主播一区|