- 实验目的及要求
目的:
通过对本实验执行过程的理解,认真分析总结,能够独立的在 Linux 下进行 shellcode 的编写。
要求:
(1)%70:完成对 shellcode 的分析及提取
(2)%100:完成对 shellcode 的验证
- 实验环境和准备
操作系统: Ubuntu 22.04(64bit)
工具:
- `vim`:用于编写代码。
- `nasm`:汇编器,编译汇编代码。
- `ld`:链接器,生成可执行文件。
- `gef`:GDB 插件,便于调试。
- `gcc`:编译 C 语言代码。
- `execstack`:修改堆栈的执行属性。
- 实验结果分析
1. C 代码实现调用 Shell 的功能——c_shellcode.c
演示如何通过简单的 C 代码实现调用 Shell 的功能。
提供一个使用 `execve` 系统调用启动 `/bin/sh` 的示例代码。
源代码如下:
通过 GDB 调试此文件,分析系统调用的参数传递方式和内部实现逻辑
编译C源码生成可执行文件
gcc -m32 -g c_shellcode.c -o c_shellcode
运行结果如下,成功实现调用shell的功能:
查看execve()的参数
- filename必须指向包含要执行的二进制文件的路径的字符串,就是字符串[/ bin / sh]。
- argv []是程序的参数列表。大多数程序将使用强制性/选项参数运行。而我们只想执行“/ bin / sh”,而没有任何更多的参数,所以参数列表只是一个NULL指针。但是,按照惯例,第一个参数是我们要执行的文件名。所以,argv []就是['/ bin / sh',00000000]
- envp []是要以key:value格式传递给程序的任何其他环境选项的列表。为了我们的目的,这将是NULL指针\0x00000000
- execve的系统调用号为11(0xb)
在gdb中调试,进入execve()函数
查看此时相关寄存器的值
执行系统调用
2. Linux 平台下的系统调用——`hello.asm`
一个简单的汇编示例,用于输出 "Hello, world!" 并退出程序。
演示 Linux 平台下的系统调用(`sys_write` 和 `sys_exit`)使用方法。
通过调试和分析 `hello.asm`,可以学习如何使用 Linux 系统调用,这与 Shellcode 的实现方式相同(通过 `int 0x80` 或类似指令进入内核)。为后续编写 `shellcode.asm` 提供了基础,特别是如何使用寄存器和调用内核功能。
汇编代码如下:
nasm -f elf32 hello.asm # 将 hello.asm 汇编为 32 位的目标文件 hello.o
ld -m elf_i386 -s -o hello hello.o # 链接生成 32 位可执行文件
执行结果如下:
查看反汇编代码
objdump -d hello
对于调用 int 0x80 的 软 中 断 而 言 , 除 了 eax 对 应 的 函 数 号 之 外 ,ebx,ecx,edx,esi,edi 依次作为参数。
3. 汇编语言实现 Shellcode ——`shellcode.asm`
这是实验的核心文件,直接使用汇编语言实现了 Shellcode 的功能:
启动 `/bin/sh` 的命令行 Shell。
模拟 `execve` 的行为,通过手动设置寄存器参数和发出系统调用。
它的功能与 `c_shellcode.c` 一致,都是启动一个 Shell,但使用汇编直接实现,以避免 C 语言运行时的依赖。通过反汇编生成的可执行文件,可以提取出纯净的 Shellcode 字节流。提取的 Shellcode 将被嵌入 `runshellcode.c` 中,用于验证运行效果。
nasm -f elf32 shellcode.asm #汇编为 32 位的目标文件 shellcode.o
ld -m elf_i386 -s -o shellcode shellcode.o # 链接生成 32 位可执行文件
汇编代码如下:
在x86堆栈中是从高地址到低地址的,所以要输入反向的字符串。同样,使用为4的倍数的最短指令会更容易些。而/bin/sh是7个字节,把它变成8个字节,加个/就ok了。因为在Linux中,多几个/不会有影响,如下
可以用python来生成hs/nib//的十六进制
使用objdump查看
使用以下指令可以用于提取shellcode 的指令来源
objdump -d ./shellcode|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'
- 验证提取的shellcode——`runshellcode.c
一个验证程序,使用 C 语言将提取的 Shellcode 字节流嵌入程序中,运行时直接调用 Shellcode。目的是确保从汇编中提取的 Shellcode 能在没有外部依赖的情况下正常运行。
源代码如下:
编译修改栈属性并运行
gcc -m32 -fno-stack-protector -z execstack -no-pie runshellcode.c -o runshellcode
-m32:指定32位程序
-fno-stack-protector:禁用栈保护机制(Stack Protector)
-z execstack:允许堆栈执行代码
-no-pie:禁用地址空间布局随机化(ASLR)中的位置无关执行(PIE)。