中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

利用pe添加節的方法添加代碼 實現簡單的加殼

發布時間:2020-05-20 19:19:53 來源:網絡 閱讀:1054 作者:天晴V587 欄目:安全技術

利用pe添加節的方法添加代碼 實現簡單的加殼

大致流程如下

要達到的目的是 添加一個新節 在新節中添加自己的代碼 讓程序運行時 先運行自己的代碼

而自己的代碼就是為了解開之前對程序進行的加密執行完后 再繼續運行原程序的路線。


詳細步驟

第一步

先寫程序將 采用文件映射的方法將待修改的exe加載進來 獲取所有我們需要的信息
CreateFile    CreateFileMapping  MapViewOfFile(返回 文件基地址 Pp_w_picpath)
GetFileSize(用于修改文件大小)

第二步

初始化pe頭信息 DOS=PIMAGE_DOS_HEADER(Pp_w_picpath); 其他初始化略
驗證pe的有效性 MZ 和 PE

第三步

開始加節 因為后邊要修改eop所在的節的內容
所以先將此節的屬性設置為 可讀可寫  IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE
(此處很關鍵 自己修改的事飛秋 結果修改完后一直不能運行 卡了很長時間 切記)

加節

1

找到最后一節的地址
PIMAGE_SECTION_HEADER lastsec = SECTION+(FILE->NumberOfSections-1);
 確定新加節的地址
PIMAGE_SECTION_HEADER newsec = lastsec+1;
 節表數目加1
FILE->NumberOfSections++;
驗證一下 在節表頭最后 到 第一個節內容開始 有沒有40個字節
(一般都有  沒有考慮不夠的情況)
驗證方法(主要明白SizeOfHeaders的真實含義)

NEWSIZE 計算的是 (dos + dos stub ) + nt +  新加節后的節表頭總大小(純粹大小 未對齊)
DWORD NEWSIZE = (DOS->e_lfanew)+sizeof(IMAGE_OPTIONAL_HEADER32)+sizeof(IMAGE_SECTION_HEADER)*NumberOfSections;
(不要忘記 dos stub  直接用(sizeof(IMAGE_DOS_HEADER))盡管沒有神馬影響 但是事實 必須這樣計算)

讓它跟原SizeOfHeaders比較
SizeOfHeaders是  dos+dos stub+nt+所有節表頭總大小(對齊后的)       可以用作第一個節內容的開始位置

2
大小滿足之后  對新加節的所有屬性進行初始化(UP函數是 用來對齊的 參數 1 大小 2 對齊粒度)

memcpy(newsec->Name,".NewSec",8);

newsec->Misc.VirtualSize=實際大小(size); 節內容的實際大小  SizeOfRawData 用到

newsec->SizeOfRawData=Up(size,pe.OPTION->FileAlignment); 文件中的大小

newsec->VirtualAddress 在內存中的RVA 重要 可以利用上一個節的數據得到

DWORD last =Up((lastsec->SizeOfRawData),pe.OPTION->SectionAlignment)+lastsec->VirtualAddress;
DWORD last =Up((LastSec->Misc.VirtualSize),pe.OPTION->SectionAlignment)+lastsec->VirtualAddress;

兩個last 相等 因為 SizeOfRawData 是Misc.VirtualSize按文件對齊得到的
文件對齊粒度512 內存對齊粒度4096 所以肯定相等
不過為了準確 采用后者
其實這個last 也就是 pe文件 載入內存后 經過SectionAlignment對齊后 的 總大小 SizeOfImage

newsec->PointerToRawData=lastsec->PointerToRawData+lastsec->SizeOfRawData;  同理
newsec->Characteristics=IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE; 可讀可寫

其他屬性沒有什么影響 故均設置為0  到此 初始化完畢

3

需要修改的其他地方的參數
a (必須)文件在磁盤上的總大小 即第一步中的GetFileSize返回的值 再加上一頁的大小4096
 用于CreateFileMapping創建文件映射對象函數 把大小設置為修改后的大小 即 加上4096后的值
b (必須)文件映射內存后的總大小
  OPTION->SizeOfImage+=Up(size,pe.OPTION->SectionAlignment);
c (不必須的)
  pe.DATA[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size=0;
  pe.DATA[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress=0;
  pe.OPTION->SizeOfCode+=Up(size,pe.OPTION->SectionAlignment);
  pe.OPTION->SizeOfInitializedData+=Up(size,pe.OPTION->SectionAlignment);

4 至此加節成功

第四步

取反
因為是對 eop所在節的內容取反 所以要找到 eop 所在節
方法 獲取eop= OPTION->AddressOfEntryPoint 然后循環遍歷各個節表頭的起始地址 進行比較
for (int i=0; i<FILE->NumberOfSections; i++)
{
PIMAGE_SECTION_HEADER sec = PIMAGE_SECTION_HEADER(SECTION+i);
if (eop>=sec->VirtualAddress   &&    eop<=(sec->VirtualAddress+sec->SizeOfRawData))
{return sec;}
}
找到所在節后  是要對在磁盤上此節的內容 進行修改 所以獲取
PVOID address = sec->PointerToRawData+p_w_picpath; //文件的地址
DWORD lenth   = sec->SizeOfRawData;          //文件的大小

取反函數
void  _stdcall QF(PVOID address,DWORD len)
{
DWORD i=0;
PBYTE buf=(PBYTE)address;
for ( i=0; i<len; i++)
{buf[i]=~buf[i];}
}
函數中有一個關鍵字 _stdcall  作用是 函數執行完后 自己跳轉到之前壓棧的地址 用于返回eop使用

好了 取反結束了 此時 磁盤上的 exe文件已經被 破壞 接下來是 解密

第五步

解密 比較復雜

首先說一下思路
解密其實是 exe在執行后 先執行自己的解密算法 在跳轉回去 繼續自己的程序
所以解密 就是當exe文件執行時 先執行自己的代碼 即將已取反加密的節再取反 即可正常運行
記住是當exe文件執行的時候所以 需要獲得當 exe文件加載進去后的 內存地址才行(重要)
并不是說將磁盤上的文件再改回來 這樣想是錯的 再怎么說文件執行了 再對它進行修改 肯定是不行的

獲得了待解密的節首地址 和 大小 此時解密函數參數已經解決了 接下來要做的 是讓程序運行的時候 先執行自己的代碼
也就是先執行自己的這個解密算法函數  一個函數運行的步驟是 先將參數從右到左依次入棧 再將代碼入棧 而我們還需要
執行完后 再跳轉回原eop入口地址 所以再將原eop入口地址入棧 待函數執行完后 返回到這個地址 怎么返回的? 這就用到
關鍵字 _stdcall   它的作用是  由被調的函數清除堆棧 它的反匯編是 ret 8 ;兩個字節的大小
(在這個程序中不用它也可以 用是最安全 省心的 至于原因 強哥解釋了 我沒太搞明白)

接下來就開始copy應該copy的內容到新加節的內容中

參數入棧 需要自己寫機器語言(因為是執行自己的函數所以自己調) 利用結構體 形成語句 然后再copy到新加節的開始
當執行新加節的內容時 先執行自己做的這個解密函數(參數入棧  原eop入棧 代碼入棧 ret 8)

1 獲得copy的首地址 即 新加節的文件地址
 PBYTE begin=(RVATORAW(newsec->VirtualAddress)+p_w_picpath);


再將 參數入棧的機器碼構成結構體 直接copy機器碼到新加節中

2 從右到左 copy參數 即先copy 節的長度length

先對之前自己做的結構體進行初始化
MOV_EBX.address=secofeop->SizeOfRawData;        //所在節的length
MOV_EAX.address=secofeop->VirtualAddress+pe.OPTION->ImageBase; //所在節的起始地址 va+400000
PUSH_OLD_EOP.address=pe.OPTION->AddressOfEntryPoint+pe.OPTION->ImageBase; //原eop+400000

再copy到新加節的內容中
memcpy(begin,&MOV_EBX,sizeof(mov_eax));                 //所在節的length
memcpy(begin+sizeof(mov_eax),&MOV_EAX,sizeof(mov_eax)); //所在節的起始地址 va+400000
memcpy(begin+sizeof(mov_eax)*2,&PUSH_OLD_EOP,sizeof(push_old_eop)); //原eop+400000

DWORD lenofcode=(DWORD)end_qf-(DWORD)start_qf;
//其中 start_qf  和  end_qf 是取反函數的首地址和末地址 用來計算代碼的長度 注意最后還得加上末地址后邊的幾個字節(重要)
//兩個數值是自己寫好程序后 調試程序時 手動找出來的 不知道怎么動態獲得 待大牛看后 指點迷津
//計算一下代碼需要的內存長度 再加上至少有返回的指令的長度 此時即為2
//多了也沒事 自動填充為 CC

memcpy(begin+sizeof(mov_eax)*2+sizeof(push_old_eop),(PVOID)start_qf,lenofcode+2);  //

重要一步 修改eop入口點地址為新加節的rva

OPTION->AddressOfEntryPoint=newsec->VirtualAddress;  //修改入口點地址到新加節的rva

此時解密也結束了

第六步

收尾工作

首先了解一點知識 摘在網絡

為了提高速度,系統將文件的數據頁面進行高速緩存,并且在對文件的映射視圖進行操作時不立即更新文件的磁盤映像。如果需要確保你的更新被寫入磁盤,可以強制系統將修改過的數據的一部分或全部重新寫入磁盤映像中,方法是調用F l u s h Vi e w O f F i l e函數:
BOOL FlushViewOfFile(
 PVOID pvAddress,
 SIZE_T dwNumberOfBytesToFlush);
第一個參數是包含在內存映射文件中的視圖的一個字節的地址。該函數將你在這里傳遞的地址圓整為一個頁面邊界值。第二個參數用于指明你想要刷新的字節數。系統將把這個數字向上圓整,使得字節總數是頁面的整數。

1 "對文件的映射視圖進行操作時不立即更新文件的磁盤映像" 那么何時更新?我程序正常退出前一定會更新吧?如果程序意外結束(比如電腦死機)那是不是就可能無法將更改寫入磁盤?
1、在UnmapViewOfFile、CloseHandle和系統回收物理內存的時候寫入磁盤。
當進程結束時(包括正常和異常),系統會自動關閉該進程打開的所有Handle,所以會寫入磁盤。除非是內核代碼異常,導致死機,這時才可能沒有寫入。

2 是不是只要程序不意外結束,我們就沒使用FlushViewOfFile的必要?否則請問在什么情況下有必要使用它?
2、FlushViewOfFile是為了實現程序自己控制寫入磁盤而提供的,當你真正遇到這種需求的時候才能體會到它的價值。


本程序實現的代碼如下
BOOL success = FlushViewOfFile(Pp_w_picpath,FileSize);  //將寫入文件映射緩沖區的所有數據都刷新到磁盤
if (!success)
{return false;}
success = UnmapViewOfFile(Pp_w_picpath); //在當前應用程序的內存地址空間解除對一個文件映射對象的映射
     //lpBaseAddress Long,指定要解除映射的一個文件映射的基準地址。這個地址是早先用MapViewOfFile函數獲得的
CloseHandle(hMap);
return true;

到此 結束了

程序架構主要是強哥的思路 好多問題也是強哥解決 我慢慢消化的 不過也有自己發現的一些新的問題和解決方法
利用pe添加節的方法添加代碼 實現簡單的加殼同時還感謝老牛孜孜不倦 累死不疲的淳淳教誨和督促 也幫我解決了不少的問題
感慨 團隊就是好


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

怀远县| 岑溪市| 新田县| 扶风县| 娱乐| 平江县| 温宿县| 松原市| 宝应县| 阿瓦提县| 石嘴山市| 英山县| 永年县| 华蓥市| 新巴尔虎右旗| 军事| 盘山县| 陆河县| 呼图壁县| 冀州市| 朝阳市| 天门市| 台山市| 荔波县| 报价| 娱乐| 湾仔区| 五原县| 永清县| 洛南县| 天峨县| 赤峰市| 永年县| 沐川县| 肥东县| 青龙| 石门县| 普兰店市| 红原县| 青浦区| 梁河县|