本文基于Windows平臺對PE文件加殼的項目,經過一個月的緩沖,決定復習總結及分享下的我的心得。
主要工具: 010Editor、VS2017、x64dbg、LordPE、OD
實驗平臺:win10 64位
實現功能:加殼,壓縮,對代碼段加密。
一、加殼原理
要想弄明白怎么對PE文件加殼,首先需要對PE文件比較熟悉,而最快的熟悉PE文件的方法就是自己寫一個PE解析工具和寫殼了。
先只用工具010Editor完成一個手工加殼,那么就明白加殼的原理了。
首先進行手工加殼
先用VS隨便生成一個exe文件,我們使用它進行實驗。
可以先使用010Editor、LordPE、OD等工具查看節區個數,我實驗程序的原始區段(節區)個數是8個。
1. 給PE文件添加一個新區段
修改文件頭的NumberOfSection
使用010Editor打開測試程序,按alt+4出現一個模板菜單找到NumberOfSection把該數字加1,這里改為了9。
2. 設置新的區段頭
添加保存之后, 重新運行010Editor的模板(或者重啟010),區段就增加了一個。
設置整個新增加的區段的數據,主要需要設置的字段如下:
① 區段名(可選)
② 區段數據的實際字節數Misc.VirtualSize
③ 區段的VirtualAddress(區段數據在內存中的RVA),此值必須是: 上一個區段的VirtualAddress + 上一個區段經內存對齊粒度對齊后的大小(內存對齊大小是0x1000的整數倍)
④ 區段以文件對齊粒度對齊后的大小SizeOfRawData(文件對齊大小是0x200的整數倍)
⑤ 區段的PointerToRawData(區段數據在文件中的偏移),此值必須是:上一個區段的PointerToRawData + 上一個區段的SizeOfRawData
⑥ 區段屬性主要設置區段為可讀可寫可執行如下圖
對比上一個區段修改新添加的區段里的字段。
3. 添加區段數據
區段頭內容雖然設置好了,但真正重要的區段里的數據還需要插入到文件中,以擴充文件的大小,因為區段頭只是一個相當于目錄的存在,如果只有目錄而沒有內容,就會造成這個文件成為一個無效的PE文件。
把010Editor里的數據頁滾動到最下面按Ctrl+shift+i添加200h個(16進制)字節
4. 修改PE文件的擴展頭的SizeofImage
現在PE文件已經被擴充了大小,擴展頭中的映像大小必須更新,否則當PE文件加載到內存后,新區段的數據將無法得到正常加載。
這個字段的值記錄的是一個PE文件在內存中的大小,可以將之設置為: 最后一個區段在內存中的位置 + 最后一個區段在內存中的大小,即:
OptionalHeader.SizeofImage = 最后一個區段.VirtualAddress + 最后一個區段.SizeOfRawData按內存對齊粒度對齊的大小
保存之后,運行該程序,就能正常運行(中間某些環節操作錯了就會導致該文件無法正常運行)到此添加區段成功了。那么加殼也就成功了90%,這個新區段之后稱為殼代碼段。
5. 添加殼代碼
先找到擴展頭的DLL屬性字段,去掉隨機基址,把40 81改為 00 81后保存。
在這里為了方便,就使用LordPE來操作剩下的步驟了,先記錄原始的OEP入口點為11055,把他改為新區段的RVA 1F000然后點擊保存。
然后再使用OD打開,進入到入口點就是41F000,因為默認加載基址是0x400000, 發現全是00 00 00的字節,沒用內容。把第一行代碼改為跳轉到原來的入口點jmp 0x411055,然后打一個補丁,程序就能正常運行了。
這就是一個完整的殼流程了,雖然這個殼的內容只有一條跳轉到原入口點的代碼,但萬丈高樓平地起。基礎的東西弄懂了后面才能少遇見一些坑!
二、為什么用C++寫殼?
我的答案是簡單、便捷、方便新手入門。
很多常見的殼都用匯編寫的,確實,匯編確實可以寫出很多短小精悍、騷操作的代碼,這是C++所沒有的,但是C++支持內聯匯編,在一定程度上彌補了它的不足。
使用DLL動態庫文件保存殼代碼,我們稱它為存根部分(stub),直接把這個文件里的內容移植到我們新添加的區段里面,因為PE文件涉及到重定位,而DLL也是一個PE文件,移植后里面的數據就變得很容易修復了。
三、C++加殼流程
1. 處理加殼程序
在加殼過程中,有一個加殼器程序和stub.dll兩個文件,加殼器程序會把原文件(要加殼的文件)以文件方式讀取到堆內存,它還是以文件對齊粒度(200h)對齊的,而stub.dll是以不處理的方式讀取到了內存中,它是以內存粒度(1000h)對齊的。
使用LoadLibraryExA加載DLL并且第三個參數使用DONT_RESOLVE_DLL_REFERENCES的時候,他就不會對這個文件進行重定位等操作,是以原始形態加載到內存。
//將DLL以不會執行代碼的標志加載到進程中.
HMODULE hStubDll = LoadLibraryExA("Stub.dll", 0,
DONT_RESOLVE_DLL_REFERENCES);
再自定義一個共享頭文件share.h,這個文件保存一些加殼程序和stub.dll中都會用到的一些數據,封裝的函數,及共用的結構體!
流程如下:
① 使用加殼器給被加殼程序添加新區段。
② 加密/壓縮被加殼程序。
③ 將stub的代碼段移植到新區段。
④ 將被加殼程序的OEP記錄到share.h中。
⑤ 將被加殼程序的EP設置到新區段。
⑥ 去掉隨機基址。
⑦ 保存為新文件。
移植數據到新區段,把整個stub.dll的代碼段.text移植到目標文件新添加的區段中,這樣就完成了最簡單加殼操作。
當然事實上并沒有那么簡單,stub.dll里的.text段里面的數據需要先進行重定位修復,修復完成后再移植過去,這樣殼區段才能正常運行起來。
首先根據stub.dll的重定位表獲取出stub.dll中.text段需要重定位的數據,然后把該數據
① 減去原始基址
② 減去原始代碼段Rva
③ 加上新基址(exe目標文件)
④ 加上新Rva (exe中新添加的區段RVA)
用C++寫代碼,首先封裝了很多常用的函數,如獲取DOS頭和NT頭,區段頭等。這樣會節省后面大量敲代碼的時間。
//獲取DOS頭
PIMAGE_DOS_HEADER GetDosHeader(char* pBase)
{
return (PIMAGE_DOS_HEADER)pBase;
}
//獲取NT頭
PIMAGE_NT_HEADERS GetNtHeader(char* pBase)
{
return (PIMAGE_NT_HEADERS)
(GetDosHeader(pBase)->e_lfanew + (DWORD)pBase);
}
例如獲取NT頭:
auto pNt = (PIMAGE_NT_HEADERS)GetNtHeader(pBase);
C++里auto的功能是自動獲取后面數據類型,這也體現了C++的強大之處。
完整重定位代碼:
//修復stub的重定位
void FixStubReloc(char* pTarBuff, char*& hModule,DWORD dwNewBase,DWORD dwNewSecRva)
{
//獲取sutb.dll重定位va
auto pReloc = (PIMAGE_BASE_RELOCATION)
(GetOptHeader(hModule)->DataDirectory[5].VirtualAddress
+ hModule);
//獲取stub.dll的.text區段的Rva
DWORD dwTextRva = (DWORD)GetSecHeader(hModule, ".text")->VirtualAddress;
//修復重定位
while (pReloc->SizeOfBlock)
{
struct TypeOffset
{
WORD offset : 12;
WORD type : 4;
};
TypeOffset* pTyOf = (TypeOffset*)(pReloc + 1);
DWORD dwCount = (pReloc->SizeOfBlock - 8) / 2;
for (size_t i = 0; i < dwCount; i++)
{
if(pTyOf[i].type != 3)
continue;
//要修復的Rva
DWORD dwFixRva = pTyOf[i].offset + pReloc->VirtualAddress;
//要修復的地址
DWORD* pFixAddr = (DWORD*)(dwFixRva + (DWORD)hModule);
DWORD dwOldProc;
VirtualProtect(pFixAddr, 4, PAGE_READWRITE, &dwOldProc);
*pFixAddr -= (DWORD)hModule; //減去原始基址
*pFixAddr -= dwTextRva; //減去原始代碼段Rva
*pFixAddr += dwNewBase; //加上新基址
*pFixAddr += dwNewSecRva; //加上新Rva
VirtualProtect(pFixAddr, 4, dwOldProc, &dwOldProc);
}
//指向下一個重定位塊
pReloc = (PIMAGE_BASE_RELOCATION)
((DWORD)pReloc + pReloc->SizeOfBlock);
}
}
現在只是暫時搭建一個殼框架所以先不處理隨機基址的問題,所以要去掉隨機基址,后期再來解決隨機基址的問題。
-
WINDOWS
+關注
關注
4文章
3551瀏覽量
88841 -
C++
+關注
關注
22文章
2110瀏覽量
73697 -
PE文件
+關注
關注
0文章
4瀏覽量
5457
發布評論請先 登錄
相關推薦
評論