網上看到一篇不錯的介紹shellcode的入門文章,我就大體翻譯一下,算是本身真正跨入二進制安全相關領域的學習吧。原文地址:http://www.primalsecurity.net/0x0-shellcoding-tutorial-introduction-to-asm/linux
如下爲翻譯內容:(非逐句翻譯)shell
彙編代碼介紹:編程
彙編語言是一種爲了方便與微處理器交互而設計的低級編程語言。該語言是與處理器系列相關聯的,如Intel、ARM等。在理解彙編的時候,體系結構發揮了重要的做用,由於在32位和64位之間存在很大的不一樣。在這裏咱們主要集中到Linux下的Intel(IA-32)。安全
今天咱們看到的CPU寄存器爲EAX、EBX、ECX和EDX。在最初設計時,這些寄存器擁有通常的功能。可是基於咱們的目的,咱們能夠在每一個時序存儲任何咱們喜歡的數據。這些寄存器的標準用法以下:編程語言
EAX編輯器 |
「累加器」一般用於算術運算函數 |
EBX學習 |
基址寄存器,做爲數據指針ui |
ECXspa |
「計算器」,用於循環的索引 |
EDX |
數據寄存器,充當一個I/O指針 |
在後續文章中,咱們會介紹其餘一些寄存器。
操做咱們的寄存器:
首先,咱們會利用以前提到的寄存器建立一個基本的「hello world」的彙編語言腳本。要作到這一點,咱們先建立一個名爲「helloworld.asm」的新文件(能夠取任何你想取的名字),而後在文本編輯器中建立‘.text’和‘.data’兩個段,以下所示:
section .text global _start ;default entry point for linking _start: ; entry point for commands section .data
.data段咱們將用於存儲字符串(這能夠用於變量等),.text段將建立ELF連接的入口,咱們的指令用於操做寄存器設置咱們的系統調用(多個),以及咱們的指令給內核執行咱們的系統調用。
首先,咱們須要使用define byte或者db把咱們的字符串添加到.data段中:
msg: db 「Hello World!:,0x0a ; the string, followed by a new line character
接下來,咱們須要決定什麼系統調用將用於咱們的彙編指令。爲了查看可用的系統調用,咱們須要查看「uninstd_32.h」文件,通常存在於「/usr/include/i386-linux-gnu/asm/」或者可能在其餘位置。咱們能夠打開這個文件查看可用的調用:
當即看到兩個咱們利用的系統調用,exit函數(#define __NR_exit 1)和write函數(#define __NR_write 4)。注意着兩個系統調用號由於咱們會在後面使用到。咱們可使用「man 2」來查看關於這些系統調用的細節。(例如:man 2 write):
查看man文件,看到咱們須要使用多個字段,‘int fd’(字段描述符),‘const void *buf’(緩衝區),‘size_t count’(字符串大小)。在這個例子中,咱們的字段描述符指示咱們將要寫入的位置(0表明標準輸入,1表明標準輸出,2表明標準錯誤)。在這裏,咱們的緩衝區,就是‘Hello World!’字符串,計數器就是緩衝區的長度。總括來講,咱們有幾下幾點:
如今,咱們已經標識的必要的信息,咱們能夠開始操做寄存器了。要作到這一點,咱們將使用Intel系統結構的寄存器操做的mov命令:
mov [destination],
咱們將重複mov與四個字段的每個,依次爲EAX,EBX,ECX和EDX寄存器,後面再加上」int 0x80」命令來執行系統調用。
section .text global _start ;default entry point for linking _start: ; entry point for commands ; use the write syscall to print 'Hello world!' to stdout mov eax, 4 ; move syscall 4(write) to the eax register mov ebx, 1 ; move field descriptor for stdout to ebx mov ecx, msg ; move the memory address of our string to ecx mov edx, 13 ; move the length of the string to edx int 0x80 ; execute the syscall section .data msg: db 「Hello world!」, 0x0a ; the string, followed by a new line character
如今,咱們已經當心的編寫了write系統調用。咱們須要遵循相同的步驟,乾淨執行程序。要作到這一點,咱們將使用前面提到的「exit」的系統調用.這一次,咱們僅須要利用」int status「,下面的步驟用於exit系統調用後,你的代碼將和下面相似:
section .text global _start ;default entry point for linking _start: ; entry point for commands ; use the write syscall to print 'Hello world!' to stdout mov eax, 4 ; move syscall 4(write) to the eax register mov ebx, 1 ; move field descriptor for stdout to ebx mov ecx, msg ; move the memory address of our string to ecx mov edx, 13 ; move the length of the string to edx int 0x80 ; execute the syscall ; use the exit syscall to exit the program with a status code of 0 mov eax, 1 ; mov syscall 1(exit) to the eax register) mov ebx, 0 ; move status code to ebx int 0x80 ; execute the syscall section .data msg: db 「Hello world!」, 0x0a ; the string, followed by a new line character
建立咱們的可執行程序:
如今,咱們的彙編代碼已經建立了,接下來將要把它編譯稱爲目標文件,而後使用連接器建立咱們的ELF可執行文件,咱們使用以下的NASM命令來建立咱們的目標文件:
nasm -f elf32 -o <output object file> <input assembly file>
如今咱們有了一個成功的目標文件,咱們可使用ld來連接它,而後建立最後的執行文件。咱們使用以下命令:
ld -o <output file> <input object file>
假設這種狀況成功了,咱們應該有了一個全功能的ELF可執行程序。如今,咱們能夠執行咱們的文件,而且保證正確執行。
附上NASM的下載地址:http://www.nasm.us/pub/nasm/releasebuilds/2.11.08/