网上看到一篇不错的介绍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/