這裡嘗試用熟悉的 Helloworld 來解析 UPX 是如何脫殼的。
這一章我一行一行的檢查,然後猜測……由於經驗不足我無法確定我是正確的,所以程式流程的解說不一定是正確的。
https://github.com/Dinlon5566/IT_Reverse_Engineering/tree/main/Dx12
使用 x64dbg
進入 EP
,但這裡只是解壓縮器的 EP
,而且位置是在 UPX[ 1 ]
區域。但還不是原本程式的 OEP
( Original Entry Point
)。
第一行的 pushad
會將 EAX
~EDI
暫存器都存進 Stack
。
第二行把 第二個 Section
(放壓縮檔的區塊) 起始點設到 ESI
。
第三行把 EDI
設到第一個區塊的起始位置。
既然把傳輸位置 ( ESI
& EDI
)的起始點與終點設成這樣,就可以預見資料會從第二區塊解壓縮到第一區塊,而指令碼始終只會在記憶體中。
ctrl + F8
來連續執行程序,在開始後我發現了循環中的 009A7E03
會將 ESI
貼到 EDI
,也是 009A1000
( Base of UPX[0]
)009A7EBA
設停止點
讓他脫離循環,可以發現指令和 009A6000
的 INT
被貼上來了,觀察 EDI
發現他複製到 009A65D4
( 雖然中間一大部分是空的 )009A7EC2
到 009A7EEE
的循環,可以發現 call
跟 jmp
的目的位置被修復了。009A7F39
的循環會根據之前第一次循環設好的名稱等把 ITA
設好。009A7F39
到 009A7F67
會將字串與 Function Name
附到正確的位置上。009A7F96
,popad
與 pushad
對應。把 stack
推回去後就可以由 009A7FA4
跳到 OEP
了之後就是快快樂樂地原本的 Helloworld,透過這次實驗也了解了經過 UPX 如何破殼而出。
可以發現在 EP
後有一個 pushad
,推測他保存的值會留給原本的程式,所以只需要找到 popad
後的 jmp
就可以知道原本的 OEP
在哪裡。 在 x64dbg
中可以到 EP
後使用 alt+F
搜尋 popad
就可以快速搜尋到該指令。