最近一直在忙着寫論文。突然領導又分配任務,幫寫個自動提取shellcode的腳本工具。因為之前,我們都是用objdump查看后,把shellcode一個個添加進去,很麻煩,害怕寫錯。所以說我們寫這個工具還是挺有必要的。首先我們要先了解幾個用到的命令。objdump,od,dd.這幾個對於提取shellcode很有用。
objdump 有點象那個快速查看之類的工具,就是以一種可閱讀的格式讓你更多地了解二進制文件可能帶有的附加信息。這里我們講用到-d -F 選項。-d disassemble. 反匯編 那些應該還有指令機器碼的section。-F fileoffset.顯示文件偏移量。是為了我們能夠定位到出我們想要的shellcode。
od 命令。dump files in octal and other formats. 就是可以以各種格式輸出文件。 -t 輸入格式,我選x1,表示十六進制一個字節為一個單位。
dd命令。Copy a file converting and formatting according the operands.我用這個命令來提取shellcode。-bs選項,是每次讀取的字節數。-if,輸入文件。-of,輸出文件。-skip,跳過的字節數,就是從objdump活得的偏移量。-count 復制的數量,這個我們通過計算獲得。
首先我們看下用來測試的execve2.asm:
Section .text global _start _start: jmp short GotoCall shellcode: pop esi xor eax,eax mov byte [esi + 7], al lea ebx,[esi] mov long [esi + 8],ebx mov long [esi + 12],eax mov byte al,0x0b mov ebx,esi lea ecx,[esi + 8] lea edx,[esi + 12] int 0x80 GotoCall: call shellcode db '/bin/shJAAAAKKKK'
用nasm -f elf execve2.asm 會把文件'execve2.asm'匯編成'ELF'格式 的文件'execve2.o
然后我們用 objdump -d -F execve2.o 來查看。
<shellcode>與<GotoCall>之間的就是我們要提取的shellcode。首先我們看到<shellcode>和<GotoCall>的偏移量:0x112,0x12c。那么這個值就可以作為我們dd命令的skip值。我們要怎么提取這個偏移量呢。。。首先想到了awk工具,那么我們可以看看,這個偏移地址總是在最后一行,那么我們就可以先用grep命令把<shellcode>這行提取出來,然后再用awk把最后一個字段提取出來,得到0x112): 。然后我們在用字符串處理把)和:去掉就得到0x112。這是得到的是字符串,然后我們再用(())這個運算符來進行數值運算。就可以把0x112轉換成十進制數字了。這樣就可以得到我們想要的skip值。對於<GotoCall>的偏移量我們同理可得,然后用0x12c-0x112就可以得到我們要提取的字節數,也就是dd命令的count值。具體的我們來看我寫的腳本吧。
extract_shellcode.sh
總共有5個輸入參數,第一個是輸入的文件,execve2.o, 第二個是輸出文件的格式execv2.raw,第三個是shellcode開始的標識,我們這里的開始標示是<shellcode>,第四個是結束標識<GotoCall>。第五個是選擇我們要輸出的格式,r表示只輸出shellcode本身,c表示輸出帶有C語言的。即unsigned int shellcode[] ="";格式的。
#!/bin/bash BEGIN=$(objdump -d -F $1 | grep “<$3>” | awk 'NR==1 {print $NF ;}') BEGIN=${BEGIN%)*} ((BEGIN=BEGIN+0x0)) echo $BEGIN END=$(objdump -d -F $1 | grep "<$4>" | awk 'NR==1 {print $NF ;}') END=${END%)*} ((END=END+0x0)) echo $END ((VAR=END-BEGIN)) echo $VAR dd bs=1 if=$1 of=$2 skip=$BEGIN count=$VAR if [ "$5" = "c" ]; then TMP=tmp; touch $TMP; echo "unsigned int shellcode[] =" > $TMP; od -t x1 $2 | awk '{$1="";print;}' | sed 's/\ /\\x/g' | sed '/^$/d;s/^/\"/g;s/$/\"/g' >> $TMP; cat $TMP | awk '{print;} END{print ";";}' > $2; rm $TMP; fi
下面是我獲得的execve2.raw格式的。
下面是生成C語言格式的:
下面是生成的execve2.c:
提取的結果和我們前面用objdump 看的execve2.o里面的是完全一樣的。大功告成!
2013/4/29 13:58