久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

EXE文件內(nèi)存加載

 Fengsq501u81r4 2021-12-02
文章圖片1

0x01 前言

作為一名安全菜鳥,,單純的了解某一個(gè)方面是并不合格的,,安全并不僅限于某一門語言、某一個(gè)OS,,現(xiàn)如今安全研究的技術(shù)棧要求的更深,、更廣。雖說 PE 文件內(nèi)存加載已經(jīng)是多年前的技術(shù),,但是招不在新,、有用就行,內(nèi)存加載技術(shù)仍然有非常廣泛的應(yīng)用(隱藏自身,,至于為什么要隱藏自身,,dddd),由于筆者之前認(rèn)知的偏差導(dǎo)致對(duì)PE相關(guān)的知識(shí)僅停留在知道的地步,,并沒有靜下心來去認(rèn)真分析學(xué)習(xí),,借此機(jī)會(huì)補(bǔ)足一下技術(shù)點(diǎn),同時(shí)順便為自己的惡意代碼分析的學(xué)習(xí)之旅開個(gè)頭,。

0x02 關(guān)鍵步驟

0x1 Section 對(duì)齊

因?yàn)閑xe以文件形式存儲(chǔ)的時(shí)候區(qū)段間的對(duì)齊方式與在內(nèi)存中的對(duì)齊方式不盡相同,,因此在手動(dòng)加載exe時(shí)不能單純的將文件格式的 exe 直接拷貝到內(nèi)存中,而是應(yīng)當(dāng)根據(jù)內(nèi)存區(qū)段(page size)的對(duì)齊方式做對(duì)齊處理,。

文章圖片2

為了驗(yàn)證一下,,隨便找一個(gè) exe 文件作為學(xué)習(xí)資料。

文章圖片3
文章圖片4

FileAlignment 為 0x200,,實(shí)際的Section也均是以 0x200 為單位進(jìn)行對(duì)齊的,,實(shí)際調(diào)試時(shí)就會(huì)發(fā)現(xiàn)section的對(duì)齊變?yōu)榱薙ectionAlignment的大?。?x1000

文章圖片5

0x2 導(dǎo)入表修復(fù)

導(dǎo)入表是PE文件從其它第三方程序中導(dǎo)入API,以供本程序調(diào)用的機(jī)制(與導(dǎo)出表對(duì)應(yīng)),,在exe運(yùn)行起來的時(shí), 加載器會(huì)遍歷導(dǎo)入表, 將導(dǎo)入表中所有dll 都加載到進(jìn)程中,,被加載的DLL的DllMain就會(huì)被調(diào)用,通過導(dǎo)入表可以知道程序使用了哪些函數(shù),,導(dǎo)入表是一個(gè)數(shù)組,,以全為零結(jié)尾。
要理解導(dǎo)入表,,首先要理解PE文件分為兩種編譯方式:動(dòng)態(tài)鏈接,、靜態(tài)鏈接。
靜態(tài)鏈接方式:在程序執(zhí)行之前完成所有的組裝工作,,生成一個(gè)可執(zhí)行的目標(biāo)文件(EXE文件),。
動(dòng)態(tài)鏈接方式:在程序已經(jīng)為了執(zhí)行被裝入內(nèi)存之后完成鏈接工作,并且在內(nèi)存中一般只保留該編譯單元的一份拷貝,。
靜態(tài)鏈接優(yōu)勢在于其可移植性較強(qiáng),,基本上不依賴于系統(tǒng)的dll(自己全打包好了),動(dòng)態(tài)鏈接的優(yōu)勢在于程序主體較小,,占用系統(tǒng)資源不多,。
動(dòng)態(tài)鏈接庫的兩種鏈接方法:
(1) 裝載時(shí)動(dòng)態(tài)鏈接(Load-time Dynamic Linking):這種用法的前提是在編譯之前已經(jīng)明確知道要調(diào)用DLL中的哪幾個(gè)函數(shù),編譯時(shí)在目標(biāo)文件中只保留必要的鏈接信息,,而不含DLL函數(shù)的代碼,;當(dāng)程序執(zhí)行時(shí),調(diào)用函數(shù)的時(shí)候利用鏈接信息加載DLL函數(shù)代碼并在內(nèi)存中將其鏈接入調(diào)用程序的執(zhí)行空間中(全部函數(shù)加載進(jìn)內(nèi)存),,其主要目的是便于代碼共享,。(動(dòng)態(tài)加載程序,處在加載階段,,主要為了共享代碼,,共享代碼內(nèi)存)
(2) 運(yùn)行時(shí)動(dòng)態(tài)鏈接(Run-time Dynamic Linking):這種方式是指在編譯之前并不知道將會(huì)調(diào)用哪些DLL函數(shù),完全是在運(yùn)行過程中根據(jù)需要決定應(yīng)調(diào)用哪個(gè)函數(shù),,將其加載到內(nèi)存中(只加載調(diào)用的函數(shù)進(jìn)內(nèi)存),,并標(biāo)識(shí)內(nèi)存地址,,其他程序也可以使用該程序,,并用LoadLibrary和GetProcAddress動(dòng)態(tài)獲得DLL函數(shù)的入口地址。(dll在內(nèi)存中只存在一份,,處在運(yùn)行階段)
相較于靜態(tài)鏈接所有函數(shù)均在一個(gè)exe文件里,,要調(diào)用某個(gè)函數(shù)時(shí)只需要按照寫死的偏移進(jìn)行調(diào)用,動(dòng)態(tài)鏈接就存在一個(gè)找函數(shù)的問題:
當(dāng)程序運(yùn)行起來需要某個(gè)系統(tǒng)函數(shù)時(shí),,哪個(gè)dll包含該函數(shù),?dll加載到內(nèi)存里之后地址是不確定的,,如何按照從內(nèi)存中定位到所需的函數(shù)地址。
PE文件中的導(dǎo)入表就可以解決上述問題,。

文章圖片6

要理解導(dǎo)入表首先要了解以下這幾個(gè)結(jié)構(gòu):

IMAGE_DATA_DIRECTORY

IMAGE_DATA_DIRECTORY 位于 IMAGE_Optional_header 中的最后一個(gè)字段,,是一個(gè)由16個(gè)_IMAGE_DATA_DIRECTORY 結(jié)構(gòu)體構(gòu)成的結(jié)構(gòu)體數(shù)組,每個(gè)結(jié)構(gòu)體由兩個(gè)字段構(gòu)成,,分別為VirtualAddress和Size字段:

  • VirtualAddress字段記錄了對(duì)應(yīng)數(shù)據(jù)結(jié)構(gòu)的RVA,。
  • Size字段記錄了該數(shù)據(jù)結(jié)構(gòu)的大小。
文章圖片7
Offset (PE/PE32 ) Description96/112 Export table address and size104/120 Import table address and size112/128 Resource table address and size120/136 Exception table address and size128/144 Certificate table address and size136/152 Base relocation table address and size144/160 Debugging information starting address and size152/168 Architecture-specific data address and size160/176 Global pointer register relative virtual address168/184 Thread local storage (TLS) table address and size176/192 Load configuration table address and size184/200 Bound import table address and size192/208 Import address table address and size200/216 Delay import descriptor address and size208/224 The CLR header address and size216/232 Reserved

根據(jù)微軟提供的信息,,IMAGE_DATA_DIRECTORY 的第二項(xiàng)指向的就是導(dǎo)入表了,。

IMAGE_IMPORT_DESCRIPTOR

既然已經(jīng)找到了導(dǎo)入表,就需要根據(jù)導(dǎo)入表內(nèi)的元素來加載對(duì)應(yīng)的dll,,獲取不同的函數(shù)地址了,,此時(shí)就需要用到 IMAGE_IMPORT_DESCRIPTOR 結(jié)構(gòu)了,該結(jié)構(gòu)的詳細(xì)內(nèi)容如下:

Offset    Size    Field0         4       Import Lookup Table RVA4         4       Time/Date Stamp8         4       Forwarder Chain12        4       Name RVA16        4       Import Address Table RVAtypedef struct _IMAGE_IMPORT_DESCRIPTOR {      union {          DWORD Characteristics;          DWORD OriginalFirstThunk;//(1) 指向?qū)朊Q表(INT)的RAV*       };      DWORD   TimeDateStamp;  // (2) 時(shí)間標(biāo)識(shí)      DWORD   ForwarderChain; // (3) 轉(zhuǎn)發(fā)鏈,,如果不轉(zhuǎn)發(fā)則此值為0     DWORD   Name;       // (4) 指向?qū)胗诚裎募拿?      DWORD   FirstThunk; // (5) 指向?qū)氲刂繁恚↖AT)的RAV*} IMAGE_IMPORT_DESCRIPTOR;

在修復(fù)IAT的過程中最重要的兩個(gè)字段就是 OriginalFirstThunk 和 FirstThunk了:
根據(jù)OriginalFirstThunk獲取要用到的函數(shù)名,,將獲取到的函數(shù)地址填到FirstThunk中。

0x03 具體分析

為了方便理解和記憶,,默認(rèn)讀取的 PE 文件格式不存在問題,,不做錯(cuò)誤處理。
相較于dll的內(nèi)存加載,,exe的內(nèi)存加載簡化了很多,,其中省略掉的一個(gè)大步驟就是導(dǎo)出表的修復(fù)。

文件讀取

文件讀取步驟基本上可以說條條大路通羅馬,,只要將 PE 文件完整的讀取到內(nèi)存中可供后續(xù)處理即可,,除了把一個(gè)文件放在目錄中進(jìn)行讀取以外還有很多種方式,比如將要加載的 exe 轉(zhuǎn)換成shellcode進(jìn)行加載,、將shellcode進(jìn)行簡單xor后在內(nèi)存xor回來再加載,。。,。

ifstream inFile('nc.exe', ios::in | ios::binary);stringstream tmp;tmp << inFile.rdbuf();unsigned char* content = (unsigned char*)tmp.str().c_str();

初始內(nèi)存分配

因?yàn)?exe 文件默認(rèn)有加載基址,,一般情況下在運(yùn)行 exe 的時(shí)候會(huì)首先嘗試加載到默認(rèn)地址上去,因此就要根據(jù) exe 的默認(rèn)加載基址和映像大?。╡xe加載到內(nèi)存后的大?。篠izeOfImage)來分配內(nèi)存

SIZE_T SizeOfImage = pFileNtHeader->OptionalHeader.SizeOfImage;// 獲取加載基址DWORD base = pFileNtHeader->OptionalHeader.ImageBase;// 分配內(nèi)存unsigned char* memExeBase = (unsigned char*)VirtualAlloc((LPVOID)base, SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);memcpy(memExeBase, content, pFileNtHeader->OptionalHeader.SizeOfHeaders);

分配內(nèi)存時(shí)的 VirtualAlloc指定的頁類型為 MEM_COMMIT|MEM_RESERVE這里是一個(gè)小小的延遲分配的知識(shí)點(diǎn),如果是 MEM_RESERVE的話只有當(dāng)對(duì)該段內(nèi)存進(jìn)行內(nèi)存操作時(shí)才會(huì)被真正Load進(jìn)入物理內(nèi)存中,。頁權(quán)限使用的是PAGE_EXECUTE_READWRITE,,這在實(shí)際編碼過程中是一個(gè)很不好的習(xí)慣,為了更清晰的理解 exe 內(nèi)存加載的核心流程,,就省略了根據(jù)section來確定內(nèi)存權(quán)限的步驟,。

拷貝Header

分配內(nèi)存完畢后首先要將 PE header 拷貝到相應(yīng)的地址空間去,,因?yàn)楹罄m(xù)的操作均需要用到。

memcpy(memExeBase, content, pFileNtHeader->OptionalHeader.SizeOfHeaders);PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)memExeBase;PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)(memExeBase pDosHeader->e_lfanew);

之后要根據(jù)新分配的內(nèi)存地址計(jì)算新的 DOS頭 和 NT頭,。

修復(fù)ImageBase

因?yàn)橐呀?jīng)根據(jù)ImageBase分配了內(nèi)存,,所以需要將拷貝后的OptionalHeader中的ImageBase字段根據(jù)實(shí)際內(nèi)存地址進(jìn)行更新,如果開啟了aslr的話需要根據(jù)實(shí)際的內(nèi)存地址更新ImageBase,,分配到默認(rèn)基址上的話沒有必要,。

pNtHeader->OptionalHeader.ImageBase = (DWORD)memExeBase;

拷貝區(qū)段

拷貝區(qū)段這部分是內(nèi)存加載的第一個(gè)關(guān)鍵點(diǎn),要根據(jù)內(nèi)存頁的大小來將原本的文件區(qū)段進(jìn)行處理,。在文件中Section通常以 0x200 進(jìn)行對(duì)齊,,內(nèi)存中頁大小單位為 0x1000, 因此內(nèi)存對(duì)齊單位為 0x1000,,所以當(dāng)PE文件加載到內(nèi)存中后需要對(duì)Section進(jìn)行變換,。

// 拷貝區(qū)段 PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(pNtHeader); int sectionSize; for (int i = 0; i < pNtHeader->FileHeader.NumberOfSections; i , section ) { if (section->SizeOfRawData == 0) { sectionSize = pNtHeader->OptionalHeader.SectionAlignment; // 最小內(nèi)存Seciton單位為 SectionAlignment的大小 } else { sectionSize = section->SizeOfRawData; } if (sectionSize > 0) { void* dest = memExeBase section->VirtualAddress; memcpy(dest, content section->PointerToRawData, sectionSize); } }

修復(fù)導(dǎo)入表

OriginalFirstChunk指向的INT表表項(xiàng)以4字節(jié)為單位,全0結(jié)尾,,如果最高位為1則代表是函數(shù)序號(hào),,反之則是一個(gè)RVA,指向IMAGE_IMPORT_BY_NAME結(jié)構(gòu),,INT表實(shí)際上的功能是獲取要導(dǎo)入的函數(shù)名,。目前沒有遇到最高位為1的情況。

typedef struct _IMAGE_IMPORT_BY_NAME {    WORD    Hint;                     CHAR   Name[1];               //函數(shù)名稱,0結(jié)尾.} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

IAT表項(xiàng)則直接是一個(gè)指向真實(shí)函數(shù)地址的指針,。

PIMAGE_IMPORT_DESCRIPTOR pImportDesc;bool result = true;PIMAGE_DATA_DIRECTORY pDataDir = (PIMAGE_DATA_DIRECTORY)(&pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]); // 獲取IMAGE_DATA_DIRECTORY 位置pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)(memExeBase pDataDir->VirtualAddress);// 獲取第一個(gè)IMAGE_IMPORT_DESCRIPTORfor (;!IsBadReadPtr(pImportDesc,sizeof(IMAGE_IMPORT_DESCRIPTOR)) && pImportDesc->Name;pImportDesc ) { uintptr_t* thunkRef; FARPROC* funcRef; HMODULE handle = LoadLibraryA((LPCSTR)(memExeBase pImportDesc->Name)); // 加載dll(此處也是可以手工加載的) if (pImportDesc->OriginalFirstThunk) { thunkRef = (uintptr_t*)(memExeBase pImportDesc->OriginalFirstThunk); funcRef = (FARPROC*)(memExeBase pImportDesc->FirstThunk); } else { thunkRef = (uintptr_t*)(memExeBase pImportDesc->FirstThunk); funcRef = (FARPROC*)(memExeBase pImportDesc->FirstThunk); } for (; *thunkRef; thunkRef , funcRef ) { if (IMAGE_SNAP_BY_ORDINAL(*thunkRef)) { // 判斷OriginalFirstThunk表項(xiàng)最高位為1的情況 *funcRef = GetProcAddress(handle, (LPCSTR)(IMAGE_ORDINAL(*thunkRef)));//修復(fù)導(dǎo)入表 } else { PIMAGE_IMPORT_BY_NAME thunkData = (PIMAGE_IMPORT_BY_NAME)(memExeBase (*thunkRef)); *funcRef = GetProcAddress(handle, (LPCSTR)&thunkData->Name); //修復(fù)導(dǎo)入表 } if (*funcRef == 0) { cout << ' error import ' << endl; exit(0); } }}

上述修復(fù)導(dǎo)入表的代碼實(shí)際完成的工作就是遍歷導(dǎo)入表中的 IMAGE_IMPORT_DESCRIPTOR結(jié)構(gòu),,根據(jù)dll名稱將對(duì)應(yīng)的dll加載到內(nèi)存中,并根據(jù)OriginalFirstThunk字段來獲取所需的函數(shù)名進(jìn)而使用GetProcAddress來獲取該函數(shù)在內(nèi)存中的實(shí)際地址填充到FirstThunk字段指向的空間中,。

獲取入口點(diǎn)啟動(dòng)程序

if (pNtHeader->OptionalHeader.AddressOfEntryPoint != 0) {    ExeEntryProc exeEntry = (ExeEntryProc)(LPVOID)(memExeBase   pNtHeader->OptionalHeader.AddressOfEntryPoint);    exeEntry();}

結(jié)語

至此exe的內(nèi)存加載就已經(jīng)結(jié)束了,,誘發(fā)我寫下這篇文章的一個(gè)主要原因是回憶起之前看過的幾篇APT相關(guān)的分析文章,涉及到主機(jī)的遠(yuǎn)控目前內(nèi)存加載已經(jīng)是標(biāo)配,,殺軟動(dòng)態(tài)檢測的對(duì)抗方式種類繁多,,靜態(tài)對(duì)抗的方法以內(nèi)存加載為王。

參考鏈接

https://www.cnblogs.com/iBinary/p/9740757.html
https://github.com/fancycode/MemoryModule
https://blog.csdn.net/Apollon_krj/article/details/77417063
https://www.cnblogs.com/tracylee/archive/2012/10/15/2723816.html

本文由D4ck原創(chuàng)發(fā)布
轉(zhuǎn)載,,請(qǐng)參考轉(zhuǎn)載聲明,,注明出處: https://www./post/id/260054
安全客 - 有思想的安全新媒體

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多