目錄
- 修改記事本PE結構彈計算器Shellcode
- 0x00 前言
- 0x01 添加新節
- 修改節數量
- 節表位置
- 添加新節表資訊
- 0x02 添加彈計算器Shellcode
- 修改代碼
- 0x03 修改入口點
- 計算跳轉OEP偏移
- 0x04 bug修復
- 0x05 驗證結果
修改記事本PE結構彈計算器Shellcode
0x00 前言
在上一篇文章中介紹了PE節表的分析,這篇文章主要是對其進行手動實驗來加深對節表的理解,并且這里用一個記事本的例子做演示,我們用Winhex軟體通過修改、添加十六進制資料讓記事本一啟動就能彈出計算器,
整體的思路是:給記事本添加一個節,節內添加彈計算器Shellcode十六進制+jmp到原OEP(程式入口點),修改OEP指向->新區段位置,運行記事本讓其彈計算器,
0x01 添加新節
首先需要找一個32位的記事本,我這里用的是xp系統下的notepad.exe,
修改節數量
第一步我們先修改節數量,之前都有介紹節數量在標準PE頭中的NT標識后4個位元組,這里原本是3我們將其改成4,

節表位置
節表位置在可選PE頭下面,所以我們先找到可選PE頭,并且找到可選PE頭的大小就能找到節表位置了,可選PE頭大小在NT標識開始0x14位元組位置,

添加新節表資訊
新節資訊的位置應該在節表數量*3的位置即:節表開始處+(3 x 0x28=0x78處),一個節資訊固定大小0x28,
然后我們將熒游標中的資料覆寫成我們新節的資訊,

新節名就叫.hack把,hack節哈哈挺酷,然后節在記憶體中大小就設成0x1000,新節在記憶體中的位置為0x13000,
這個0x13000即新節位置是根據:之前最后一個節(記憶體中節位置+對其后節大小)計算出來的,可以根據我們上篇文章寫的工具來進行分析,
0xb000+0x8000等于0x13000,所以這是新節位置,這里一定不要算錯了要不然程式會崩潰,

接著是檔案中節的大小即對其后節的大小0x1000剛好對其,所以也設定成0x1000,接著是新節在檔案中的位置,這里同樣我們得到之前最后一個節在檔案中的偏移,然后再加上檔案中節大小就是其新節位置了,
(新節在檔案中的位置)0x8400+0x8000=0x10400,然后其余還有4各成員資料默認都設定成0x00,最后一個比較關鍵之前也講過他是節的屬性,決定了改節是否可讀、寫、執行,
在這里我們直接將他設定成代碼段的屬性(包含可執行代碼),(可讀),(可執行):0x60000020,這里不懂的可以復習下PE節表的詳細分析,
| 新節資訊 | 值 |
|---|---|
| Name | .hack |
| VirtualSize(記憶體中大小) | 0x1000 |
| VirtualAddress(記憶體中偏移) | 0x13000 |
| SizeOfRawData(檔案中大小) | 0x1000 |
| PointerToRawData(檔案中偏移) | 0x10400 |
| PointerToRelocations | 0x00000000 |
| PointerToLinenumbers | 0x00000000 |
| NumberOfRelocations | 0x0000 |
| NumberOfLinenumbers | 0x0000 |
| Characteristics(標志節屬性) | 0x60000020 |
最后在0x104000位置添加0x1000資料,也就是檔案末尾處我們添加0x1000個0的資料,
先用Winhex新建一個0x1000的檔案

然后復制資料到notepad.exe檔案末尾處,


至此新節添加完畢,我們可以來添加shellcode了,
0x02 添加彈計算器Shellcode
好了到這里我們可以來添加我們的Shellcode了,首先我們需要用匯撰寫一個彈計算器的代碼,然后將其轉換成十六進制,
.386
.model flat,stdcall
; 代碼區域
.code
main:
push ebp
mov ebp,esp
sub esp,20h; 開辟堆疊空間
;獲取Kernel32基址
assume fs:nothing
mov eax,[fs:30h]; peb結構所在地址
mov eax,[eax+0Ch]; Ldr
mov eax,[eax+1Ch]; 指向ntdll
mov eax,[eax]; 指向kernelbase
mov eax,[eax]; 指向kernel32
mov eax,[eax+08h]; BaseAddress
;遍歷kernel32匯出函式
;初始化堆疊空間用來保存變數
mov DWORD PTR[ebp-04h],0; 用來存放匯出函式“地址表”
mov DWORD PTR[ebp-08h],0; 用來存放匯出函式“名稱表”
mov DWORD PTR[ebp-0Ch],0; 用來存放匯出函式“序號表”
; 決議PE結構獲取匯出表結構實際地址
mov ebx,DWORD PTR[eax + 3Ch] ; NT頭偏移地址
lea ebx,DWORD PTR[ebx + eax] ; NT頭VA
mov ebx,DWORD PTR[ebx + 78h] ; 匯出表結構VirtualAddress
lea edx,DWORD PTR[ebx + eax] ; 匯出表結構實際地址
; 獲取匯出函式地址表VA
mov ebx,DWORD PTR[edx + 1Ch] ; AddressOfFunctions 偏移
lea ebx,DWORD PTR[ebx + eax] ; AddressOfFunctions 實際地址
mov DWORD PTR[ebp - 04h],ebx ; 保存到區域變數
; 獲取匯出函式名稱表VA
mov ebx,DWORD PTR[edx + 20h] ; AddressOfNames 偏移
lea ebx,DWORD PTR[ebx + eax] ; AddressOfNames 實際地址
mov DWORD PTR[ebp - 08h],ebx ; 保存到區域變量
; 獲取匯出函式序號表VA
mov ebx,DWORD PTR[edx + 24h] ; AddressOfNameOrdinals 偏移
lea ebx,DWORD PTR[ebx + eax] ; AddressOfNameOrdinals 實際地址
mov DWORD PTR[ebp - 0Ch],ebx ; 保存到區域變數
; 開始遍歷三張表,找到目標函式地址
mov edi,DWORD PTR[edx + 18h] ; NumberOfNames回圈次數
xor ecx,ecx ; 清空ecx,作為回圈計數
mov esi,DWORD PTR[ebp - 08h] ; 暫存匯出函式名稱表 實際地址
_ExportName:
mov ebx,DWORD PTR[esi + ecx * 4];函式名稱 偏移地址
lea ebx,DWORD PTR[ebx + eax]; 獲取第n個匯出函式的名稱 實際地址
; 判斷函式名稱
mov ebx,[ebx]
cmp ebx,456E6957h;判斷是否WinE
je _FindFunc
;自增1,開始下一次遍歷
inc ecx;
jmp _ExportName
_FindFunc:
;找到目標函式,獲取該函式地址VA
mov ebx,DWORD PTR[ebp - 0Ch] ; 序號表 實際地址
xor edx,edx ; 注意序號表是2位元組陣列
mov dx,WORD PTR[ebx + ecx * 2] ; 獲取對應序號表中保存的值
mov ebx,DWORD PTR[ebp - 04h] ; 地址表 實際地址
mov ebx,DWORD PTR[ebx + edx * 4]; 地址表中,目標函式地址 偏移地址
lea eax,DWORD PTR[ebx + eax] ; 目標函式實際地址;
; 呼叫函式
jmp _gotFunc
g_str db "calc.exe"
g_stop db 0
_gotFunc: call $+5
pop ebx;獲取eip
sub ebx,0Eh
push 5h
push ebx
call eax
; 恢復函式堆疊幀
mov esp,ebp
pop ebp
ret
end main
end
用MASM套件中的ml將其編譯成可執行檔案,這里我推薦用RadASM這工具來寫Windows匯編代碼,他是一個專門用來寫匯編的IDE非常好用 YYDS!


然后我們用Winhex打開這個編譯好的exe提取他代碼段中的資料作為Shellcode,

修改代碼
然后我們需要將代碼在改一改,比如在shellcode的最后一個地方C3這里對應的匯編代碼是ret這樣會讓程式回傳到呼叫的地方,這里我需要將其改成nop即:0x90,
0040101D| C3 ret
;C3改為如下90
0040101D| 90 nop
然后我們還要跳回到原來的入口點,這樣程式才能正常執行他原本的功能,
跳轉的代碼是jmp,然后我們需要計算出當前位置距離OEP的位置,目前還不知道距離所以先寫jmp 0x0000000來代替即E9 00 00 00 00
我們先把Shellcode覆寫到新節的位置,利用WinHex的寫入hex資料來覆寫之前的0資料,


覆寫后的shellcode,

0x03 修改入口點
在最后我們需要修改入口點來使的notepad.exe一開始就先執行我們的shellcode代碼,不知道怎么改入口點的讀者可以看看我之前寫的文章PE頭詳細分析,
原來的入口點地址為:0x0000739D,

修改為shellcode處的入口點:0x00010400

計算跳轉OEP偏移
好了在最后我們需要把E9 00000000中的資料給填上,才能真正的完成,計算公式為:(原OEP)-((當前地址)+5)
先把游標停在E9處,然后Winhex中顯示地址為0x1049F,那么我們可以把公式中的當前地址改成0x1049F,即(0x0000739D)-((0x1049F)+5)

最后利用Python來計算下偏移,算出來是負數的因為他要往上跳,正常是應該為負數,

然后用最終用計算器將其轉換成十六進制,并且我們取他的4位元組就行,

最后我們把地址給填上,收工完成,

0x04 bug修復
哈哈哈哈果然沒有那么幸運,我一運行時候發現程式報錯了,

然后仔細研究后發現,SizeofImage這個值我沒有改,得把他改成添加節后的大小0x14000,
還有就是入口點偏移沒算對,因為我發現新的段在記憶體中不在0x14000,而是在0x13000,應該是我們沒有把之前那個段填對其,導致我們新加的段被他對其,所以地址就變成了0x13000,

這里我計算出新的偏移:0xFFFF42F9


修復后winhex中的地址,

最后把入口點也修復成:0x13000,

0x05 驗證結果


歡迎各位加群:

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/350710.html
標籤:其他
上一篇:PE節表詳細分析
下一篇:seq2seq之雙向解碼
