0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

C++寫(xiě)殼詳細(xì)教程(上)

jf_78858299 ? 來(lái)源:看雪論壇九陽(yáng)道人 ? 作者:看雪論壇九陽(yáng)道人 ? 2023-03-17 14:49 ? 次閱讀

本文基于Windows平臺(tái)對(duì)PE文件加殼的項(xiàng)目,經(jīng)過(guò)一個(gè)月的緩沖,決定復(fù)習(xí)總結(jié)及分享下的我的心得。

主要工具: 010Editor、VS2017、x64dbg、LordPE、OD

實(shí)驗(yàn)平臺(tái):win10 64位

實(shí)現(xiàn)功能:加殼,壓縮,對(duì)代碼段加密。

一、加殼原理

要想弄明白怎么對(duì)PE文件加殼,首先需要對(duì)PE文件比較熟悉,而最快的熟悉PE文件的方法就是自己寫(xiě)一個(gè)PE解析工具和寫(xiě)殼了。

先只用工具010Editor完成一個(gè)手工加殼,那么就明白加殼的原理了。

首先進(jìn)行手工加殼

先用VS隨便生成一個(gè)exe文件,我們使用它進(jìn)行實(shí)驗(yàn)。

可以先使用010Editor、LordPE、OD等工具查看節(jié)區(qū)個(gè)數(shù),我實(shí)驗(yàn)程序的原始區(qū)段(節(jié)區(qū))個(gè)數(shù)是8個(gè)。

1. 給PE文件添加一個(gè)新區(qū)段

修改文件頭的NumberOfSection

使用010Editor打開(kāi)測(cè)試程序,按alt+4出現(xiàn)一個(gè)模板菜單找到NumberOfSection把該數(shù)字加1,這里改為了9。

圖片

2. 設(shè)置新的區(qū)段頭

添加保存之后, 重新運(yùn)行010Editor的模板(或者重啟010),區(qū)段就增加了一個(gè)。

圖片

設(shè)置整個(gè)新增加的區(qū)段的數(shù)據(jù),主要需要設(shè)置的字段如下:

圖片

① 區(qū)段名(可選)

② 區(qū)段數(shù)據(jù)的實(shí)際字節(jié)數(shù)Misc.VirtualSize

③ 區(qū)段的VirtualAddress(區(qū)段數(shù)據(jù)在內(nèi)存中的RVA),此值必須是: 上一個(gè)區(qū)段的VirtualAddress + 上一個(gè)區(qū)段經(jīng)內(nèi)存對(duì)齊粒度對(duì)齊后的大?。▋?nèi)存對(duì)齊大小是0x1000的整數(shù)倍)

④ 區(qū)段以文件對(duì)齊粒度對(duì)齊后的大小SizeOfRawData(文件對(duì)齊大小是0x200的整數(shù)倍)

⑤ 區(qū)段的PointerToRawData(區(qū)段數(shù)據(jù)在文件中的偏移),此值必須是:上一個(gè)區(qū)段的PointerToRawData + 上一個(gè)區(qū)段的SizeOfRawData

⑥ 區(qū)段屬性主要設(shè)置區(qū)段為可讀可寫(xiě)可執(zhí)行如下圖

圖片

對(duì)比上一個(gè)區(qū)段修改新添加的區(qū)段里的字段。

圖片

3. 添加區(qū)段數(shù)據(jù)

區(qū)段頭內(nèi)容雖然設(shè)置好了,但真正重要的區(qū)段里的數(shù)據(jù)還需要插入到文件中,以擴(kuò)充文件的大小,因?yàn)閰^(qū)段頭只是一個(gè)相當(dāng)于目錄的存在,如果只有目錄而沒(méi)有內(nèi)容,就會(huì)造成這個(gè)文件成為一個(gè)無(wú)效的PE文件。

把010Editor里的數(shù)據(jù)頁(yè)滾動(dòng)到最下面按Ctrl+shift+i添加200h個(gè)(16進(jìn)制)字節(jié)

圖片

圖片

4. 修改PE文件的擴(kuò)展頭的SizeofImage

現(xiàn)在PE文件已經(jīng)被擴(kuò)充了大小,擴(kuò)展頭中的映像大小必須更新,否則當(dāng)PE文件加載到內(nèi)存后,新區(qū)段的數(shù)據(jù)將無(wú)法得到正常加載。

這個(gè)字段的值記錄的是一個(gè)PE文件在內(nèi)存中的大小,可以將之設(shè)置為: 最后一個(gè)區(qū)段在內(nèi)存中的位置 + 最后一個(gè)區(qū)段在內(nèi)存中的大小,即:

OptionalHeader.SizeofImage = 最后一個(gè)區(qū)段.VirtualAddress + 最后一個(gè)區(qū)段.SizeOfRawData按內(nèi)存對(duì)齊粒度對(duì)齊的大小

圖片

保存之后,運(yùn)行該程序,就能正常運(yùn)行(中間某些環(huán)節(jié)操作錯(cuò)了就會(huì)導(dǎo)致該文件無(wú)法正常運(yùn)行)到此添加區(qū)段成功了。那么加殼也就成功了90%,這個(gè)新區(qū)段之后稱為殼代碼段。

5. 添加殼代碼

先找到擴(kuò)展頭的DLL屬性字段,去掉隨機(jī)基址,把40 81改為 00 81后保存。

圖片

在這里為了方便,就使用LordPE來(lái)操作剩下的步驟了,先記錄原始的OEP入口點(diǎn)為11055,把他改為新區(qū)段的RVA 1F000然后點(diǎn)擊保存。

圖片

然后再使用OD打開(kāi),進(jìn)入到入口點(diǎn)就是41F000,因?yàn)槟J(rèn)加載基址是0x400000, 發(fā)現(xiàn)全是00 00 00的字節(jié),沒(méi)用內(nèi)容。把第一行代碼改為跳轉(zhuǎn)到原來(lái)的入口點(diǎn)jmp 0x411055,然后打一個(gè)補(bǔ)丁,程序就能正常運(yùn)行了。

圖片

這就是一個(gè)完整的殼流程了,雖然這個(gè)殼的內(nèi)容只有一條跳轉(zhuǎn)到原入口點(diǎn)的代碼,但萬(wàn)丈高樓平地起?;A(chǔ)的東西弄懂了后面才能少遇見(jiàn)一些坑!

二、為什么用C++寫(xiě)殼?

我的答案是簡(jiǎn)單、便捷、方便新手入門(mén)。

很多常見(jiàn)的殼都用匯編寫(xiě)的,確實(shí),匯編確實(shí)可以寫(xiě)出很多短小精悍、騷操作的代碼,這是C++所沒(méi)有的,但是C++支持內(nèi)聯(lián)匯編,在一定程度上彌補(bǔ)了它的不足。

使用DLL動(dòng)態(tài)庫(kù)文件保存殼代碼,我們稱它為存根部分(stub),直接把這個(gè)文件里的內(nèi)容移植到我們新添加的區(qū)段里面,因?yàn)镻E文件涉及到重定位,而DLL也是一個(gè)PE文件,移植后里面的數(shù)據(jù)就變得很容易修復(fù)了。

三、C++加殼流程

1. 處理加殼程序

在加殼過(guò)程中,有一個(gè)加殼器程序和stub.dll兩個(gè)文件,加殼器程序會(huì)把原文件(要加殼的文件)以文件方式讀取到堆內(nèi)存,它還是以文件對(duì)齊粒度(200h)對(duì)齊的,而stub.dll是以不處理的方式讀取到了內(nèi)存中,它是以內(nèi)存粒度(1000h)對(duì)齊的。

使用LoadLibraryExA加載DLL并且第三個(gè)參數(shù)使用DONT_RESOLVE_DLL_REFERENCES的時(shí)候,他就不會(huì)對(duì)這個(gè)文件進(jìn)行重定位等操作,是以原始形態(tài)加載到內(nèi)存。

//將DLL以不會(huì)執(zhí)行代碼的標(biāo)志加載到進(jìn)程中.
HMODULE hStubDll = LoadLibraryExA("Stub.dll", 0,
DONT_RESOLVE_DLL_REFERENCES);

再自定義一個(gè)共享頭文件share.h,這個(gè)文件保存一些加殼程序和stub.dll中都會(huì)用到的一些數(shù)據(jù),封裝的函數(shù),及共用的結(jié)構(gòu)體!

流程如下:

① 使用加殼器給被加殼程序添加新區(qū)段。

② 加密/壓縮被加殼程序。

③ 將stub的代碼段移植到新區(qū)段。

④ 將被加殼程序的OEP記錄到share.h中。

⑤ 將被加殼程序的EP設(shè)置到新區(qū)段。

⑥ 去掉隨機(jī)基址。

⑦ 保存為新文件。

移植數(shù)據(jù)到新區(qū)段,把整個(gè)stub.dll的代碼段.text移植到目標(biāo)文件新添加的區(qū)段中,這樣就完成了最簡(jiǎn)單加殼操作。

圖片

當(dāng)然事實(shí)上并沒(méi)有那么簡(jiǎn)單,stub.dll里的.text段里面的數(shù)據(jù)需要先進(jìn)行重定位修復(fù),修復(fù)完成后再移植過(guò)去,這樣殼區(qū)段才能正常運(yùn)行起來(lái)。

首先根據(jù)stub.dll的重定位表獲取出stub.dll中.text段需要重定位的數(shù)據(jù),然后把該數(shù)據(jù)

① 減去原始基址

② 減去原始代碼段Rva

③ 加上新基址(exe目標(biāo)文件)

④ 加上新Rva (exe中新添加的區(qū)段RVA)

用C++寫(xiě)代碼,首先封裝了很多常用的函數(shù),如獲取DOS頭和NT頭,區(qū)段頭等。這樣會(huì)節(jié)省后面大量敲代碼的時(shí)間。

//獲取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的功能是自動(dòng)獲取后面數(shù)據(jù)類型,這也體現(xiàn)了C++的強(qiáng)大之處。

完整重定位代碼:

//修復(fù)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區(qū)段的Rva
DWORD dwTextRva = (DWORD)GetSecHeader(hModule, ".text")->VirtualAddress;

//修復(fù)重定位
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;
//要修復(fù)的Rva
DWORD dwFixRva = pTyOf[i].offset + pReloc->VirtualAddress;
//要修復(fù)的地址
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);
}
//指向下一個(gè)重定位塊
pReloc = (PIMAGE_BASE_RELOCATION)
((DWORD)pReloc + pReloc->SizeOfBlock);
}
}

現(xiàn)在只是暫時(shí)搭建一個(gè)殼框架所以先不處理隨機(jī)基址的問(wèn)題,所以要去掉隨機(jī)基址,后期再來(lái)解決隨機(jī)基址的問(wèn)題。

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • WINDOWS
    +關(guān)注

    關(guān)注

    4

    文章

    3551

    瀏覽量

    88864
  • C++
    C++
    +關(guān)注

    關(guān)注

    22

    文章

    2111

    瀏覽量

    73704
  • PE文件
    +關(guān)注

    關(guān)注

    0

    文章

    4

    瀏覽量

    5457
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    C++寫(xiě)一個(gè)http服務(wù)器

    本篇文章不會(huì)涉及到很多復(fù)雜的概念,也沒(méi)有寫(xiě)很難讀懂的模板函數(shù),代碼簡(jiǎn)單可讀,本篇文章送給每一個(gè)想自己用C++寫(xiě)一個(gè)http服務(wù)器的小伙伴!高手們、大佬們當(dāng)然可以不用看的啦!
    發(fā)表于 09-30 10:47 ?2249次閱讀

    詳細(xì)講解C++串口的相關(guān)知識(shí)

    大家可以先參考一下這篇blog,C++串口通信里面詳細(xì)講解了C++串口的相關(guān)知識(shí),以及一些函數(shù)的講解。下面我也會(huì)根據(jù)他的blog再講解。二、實(shí)現(xiàn)過(guò)程1、打開(kāi)串口:使用函數(shù):HANDLE CreateFile();HANDLE C
    發(fā)表于 08-24 06:56

    詳述不用c++寫(xiě)網(wǎng)頁(yè)的理由

    C++在web開(kāi)發(fā)中地位如何,進(jìn)來(lái)一探究竟吧。
    的頭像 發(fā)表于 12-22 10:07 ?5962次閱讀

    基于fpgrowth的c++實(shí)現(xiàn)詳細(xì)資料免費(fèi)下載

    本文檔的主要內(nèi)容詳細(xì)介紹的是基于fpgrowth的c++實(shí)現(xiàn)詳細(xì)資料免費(fèi)下載
    發(fā)表于 08-02 08:00 ?1次下載

    如何提高cc++的安全編程能力?《CC++安全編碼》帶你詳細(xì)學(xué)習(xí)

    ,既詳細(xì)闡述了C/C++語(yǔ)言及其相關(guān)庫(kù)固有的安全問(wèn)題和陷阱,系統(tǒng)總結(jié)了導(dǎo)致軟件漏洞的各種常見(jiàn)編碼錯(cuò)誤,并給出了應(yīng)對(duì)錯(cuò)誤的解決方案;又對(duì)C/C++
    發(fā)表于 08-28 08:00 ?0次下載

    如何進(jìn)行高質(zhì)量的C、C++編程?高質(zhì)量C++、C編程指南詳細(xì)資料免費(fèi)下載

    本文檔的作用內(nèi)容詳細(xì)介紹的是如何進(jìn)行高質(zhì)量的CC++編程?高質(zhì)量C++、C編程指南詳細(xì)資料免費(fèi)
    發(fā)表于 09-10 08:00 ?30次下載

    VISUAL C++教程之VISUAL C++的安裝和使用方法

    本文檔的主要內(nèi)容詳細(xì)介紹的是VISUAL C++教程之VISUAL C++的安裝和使用方法資料免費(fèi)下載。
    發(fā)表于 12-27 16:32 ?19次下載
    VISUAL <b class='flag-5'>C++</b>教程之VISUAL <b class='flag-5'>C++</b>的安裝和使用方法

    C++的cast最完整最詳細(xì)的解釋資料說(shuō)明

    本文檔的主要內(nèi)容詳細(xì)介紹的是C++的cast最完整最詳細(xì)的解釋資料說(shuō)明。
    發(fā)表于 01-29 15:26 ?0次下載
    <b class='flag-5'>C++</b>的cast最完整最<b class='flag-5'>詳細(xì)</b>的解釋資料說(shuō)明

    C++程序設(shè)計(jì)教程之C++的初步知識(shí)的詳細(xì)資料說(shuō)明

    C++程序設(shè)計(jì)教程之C++的初步知識(shí)的詳細(xì)資料說(shuō)明包括了:1. 從CC++,2 . 最簡(jiǎn)單的C++
    發(fā)表于 03-14 14:48 ?31次下載
    <b class='flag-5'>C++</b>程序設(shè)計(jì)教程之<b class='flag-5'>C++</b>的初步知識(shí)的<b class='flag-5'>詳細(xì)</b>資料說(shuō)明

    C++程序設(shè)計(jì)教程之C++工具的詳細(xì)資料說(shuō)明

    本文檔的詳細(xì)介紹的是C++程序設(shè)計(jì)教程之C++工具的詳細(xì)資料說(shuō)明主要內(nèi)容包括了:1. 異常處理,2. 命名空間,3. 使用早期的函數(shù)庫(kù)
    發(fā)表于 03-14 16:39 ?4次下載
    <b class='flag-5'>C++</b>程序設(shè)計(jì)教程之<b class='flag-5'>C++</b>工具的<b class='flag-5'>詳細(xì)</b>資料說(shuō)明

    C++程序設(shè)計(jì)的基礎(chǔ)知識(shí)初步了解C++的資料免費(fèi)下載

    本文檔的主要內(nèi)容詳細(xì)介紹的是C++程序設(shè)計(jì)的基礎(chǔ)知識(shí)初步了解C++的資料免費(fèi)下載包括了:1 認(rèn)識(shí)C++,2 C++的現(xiàn)狀和發(fā)展,3
    發(fā)表于 06-10 08:00 ?25次下載
    <b class='flag-5'>C++</b>程序設(shè)計(jì)的基礎(chǔ)知識(shí)初步了解<b class='flag-5'>C++</b>的資料免費(fèi)下載

    C++語(yǔ)言編碼規(guī)范詳細(xì)說(shuō)明

    本文檔的主要內(nèi)容詳細(xì)介紹的是C++語(yǔ)言編碼規(guī)范詳細(xì)說(shuō)明。
    發(fā)表于 01-07 16:19 ?14次下載
    <b class='flag-5'>C++</b>語(yǔ)言編碼規(guī)范<b class='flag-5'>詳細(xì)</b>說(shuō)明

    C語(yǔ)言和C++的特點(diǎn)與用法詳細(xì)說(shuō)明

    本文檔的主要內(nèi)容詳細(xì)介紹的是C語(yǔ)言和C++的特點(diǎn)與用法詳細(xì)說(shuō)明。
    的頭像 發(fā)表于 12-26 10:58 ?4434次閱讀

    qt用C++寫(xiě)的2048小游戲源代碼

    qt用C++寫(xiě)的2048小游戲源代碼
    發(fā)表于 09-27 11:48 ?1次下載

    C++寫(xiě)詳細(xì)教程(下)

    本文基于Windows平臺(tái)對(duì)PE文件加的項(xiàng)目,經(jīng)過(guò)一個(gè)月的緩沖,決定復(fù)習(xí)總結(jié)及分享下的我的心得。
    的頭像 發(fā)表于 03-17 14:49 ?597次閱讀
    <b class='flag-5'>C++</b><b class='flag-5'>寫(xiě)</b><b class='flag-5'>殼</b><b class='flag-5'>詳細(xì)</b>教程(下)