關於 Linux 上用 gdb 脫混淆後的 UPX 殼這檔事

Before all

一個難得的颱風連假後,突然冒出了一個對我這隻web狗(痾,好吧,是web鯨)頗困難的問題:

怎麼不用 IDA Pro 脫混淆後的 UPX 殼?

希望以下內容不是什麼已知用火的發言
放在這邊給自己當筆記,迷途的孩子也請多加利用w
水篇Blog的公開文章,我要回去做別的事了

LAB 建置

whale.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include"stdio.h"
#include"stdlib.h"
#include"string.h"
int main(){
char c[23];
int a[23]={47, 48, 57, 52, 61, 3, 11, 17, 21, 8, 20, 29, 39, 47, 47, 47, 39, 11, 16, 29, 20, 20, 5};
printf("Enter password : ");
scanf("%s", c);
for(int i=0;i<23;i++){
if (((int)c[i]^120)!=a[i]){
printf("Password Incorrect!!!\n");
return 0;
}
}
printf("Password Correct!!!\n");
return 0;
}

標準的 password checker

upx(或者upx-ucl)都能透過sudo apt安裝,這邊跳過

打指令編譯+上殼:

1
2
gcc whale.c -o whale
upx whale

但因為UPX是開源殼,只要一個 upx -d 就可以脫掉這時候的殼,所以把裡面的標誌都拔掉(這邊換成任何三個字符的內容都不影響)  
  
obfuscate.py

1
2
3
4
5
6
f=open('whale', 'rb')
data=f.read()
data=data.replace(b'UPX', b'WWW')
f=open('whale', 'wb')
f.write(data)
f.close()

最後跑一下這隻腳本就準備完成,可以確認看看執行檔跑不跑得起來

這時候先送到Ghidra一下:
image
好臭的程式碼喔(
這就是殼的威力!

開脫!

打開gdb(本人很喜歡pwndbg但無所謂)

1
gdb ./whale

打一下指令:

1
catch syscall write

這句指令是抓取所有write行為的syscall作為斷點,而write就是把內容輸出到terminal上這件事
原理是因為upx殼就是將本來的機械碼經過一系列轉換,變成只有在進入主程式時打開,加載到另一段記憶體跑。
所以接下來列列看process的memory map

1
info proc mappings

image

其實如果有用pwndbg或者peda可以vmmap,更方便
注意畫起來的這段,具有執行權限,而且不歸屬於任何檔案或者heap/stack資料,應該就是要找的內容。
利用dump指令對照剛剛info的內容把記憶體抓出來:

1
dump memory whale_output 0x7ffff7ff9000 0x7ffff7ffa000

抓到whale_output的檔案了
利用ghidra打開剛剛的內容,進到語言選擇的時候要挑一下:
image
點開內容,熟悉的畫面,痾…大致上出來了,剩下就是要自己判斷一些函數是什麼
不過畢竟這是CTF基礎練習,沒那麼複雜啦,XOR一刀解
image