Shellcoding教程:介紹ASM

      網上看到一篇不錯的介紹shellcode的入門文章,我就大致翻譯一下,算是自己真正跨入二進制安全相關領域的學習吧。原文地址:http://www.primalsecurity.net/0x0-shellcoding-tutorial-introduction-to-asm/

      以下爲翻譯內容:(非逐句翻譯)

      彙編代碼介紹:

      彙編語言是一種爲了方便與微處理器交互而設計的低級編程語言。該語言是與處理器系列相關聯的,如Intel、ARM等。在理解彙編的時候,體系結構發揮了重要的作用,因爲在32位和64位之間存在很大的不同。在這裏我們主要集中到Linux下的Intel(IA-32)。

      今天我們看到的CPU寄存器爲EAX、EBX、ECX和EDX。在最初設計時,這些寄存器擁有一般的功能。但是基於我們的目的,我們可以在每個時序存儲任何我們喜歡的數據。這些寄存器的標準用法如下:

EAX

“累加器”通常用於算術運算

EBX

基址寄存器,作爲數據指針

ECX

“計算器”,用於循環的索引

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/”或者可能在其他位置。我們可以打開這個文件查看可用的調用:

48

      立即看到兩個我們利用的系統調用,exit函數(#define __NR_exit 1)和write函數(#define __NR_write 4)。注意着兩個系統調用號因爲我們會在後面使用到。我們可以使用“man 2”來查看關於這些系統調用的細節。(例如:man 2 write):

49

      查看man文件,看到我們需要使用多個字段,‘int fd’(字段描述符),‘const void *buf’(緩衝區),‘size_t count’(字符串大小)。在這個例子中,我們的字段描述符指示我們將要寫入的位置(0代表標準輸入,1代表標準輸出,2代表標準錯誤)。在這裏,我們的緩衝區,就是‘Hello World!’字符串,計數器就是緩衝區的長度。總括來說,我們有幾下幾點:

  • syscall:4;系統調用號代表我們的write命令
  • fd:1;字段描述符指示我們的字符串將被寫到標準輸出
  • *buf:msg;我們在.data段中創建的hello world字符串
  • count:13;我們緩衝區的長度12加上一個換行符

      現在,我們已經標識的必要的信息,我們可以開始操作寄存器了。要做到這一點,我們將使用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/

發佈了81 篇原創文章 · 獲贊 25 · 訪問量 29萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章