__realloc_hook 劫持篡改 gadgets
参考资料:https://zhuanlan.zhihu.com/p/269126935
劫持 __realloc_hook 的背景:
我们在写堆溢出的时候经常会用到篡改 hook 为 gadgets 的手法去获取shellcode,不过相应的也存在一些问题
One_gadgets 虽然可以一键获取 shell,但是他对执行时的寄存器和栈环境有及其严苛的要求:

比如它可能要求 [rsp+0x40] == NULL 或者 rcx == NULL。 当我们通过劫持 __malloc_hook,在调用 malloc 时直接跳向 one_gadget 时,当栈环境不满足这些条件时,如果硬跳,程序就会因为条件不符而直接段错误 Segmentation Fault 崩溃,无法获取 shell。 为了改变栈环境,我们需要寻找某个函数可以修改当前的 rsp,而在 Glibc 中,realloc 函数的开头通常是一长串用来保存寄存器状态的汇编指令,具体的寄存器因版本而异,但大概率如下:
1 | 0x00: push r15 ; rsp 减小 8 |
这时就可以考虑下用 malloc_hook 和 realloc_hook 结合。先通过 realloc 调整栈帧,然后再运行 onegadget 。
了解 realloc_hook:
realloc 在库函数中的作用是重新调整 malloc 或 calloc 所分配的堆大小。它和 malloc 函数一样有 hook 函数,当 hook 函数不为空时,就会跳转运行 hook 函数(和 malloc_hook 一样的)。
1 | __int64 __fastcall realloc(signed __int64 a1, unsigned __int64 a2, __int64 a3) |
看看 realloc 的汇编代码:(可以把 libc 拖到 ida 中看,也可以泄露地址后 gdb 调试查看)
1 | .text:00000000000846C0 realloc proc near ; DATA XREF: LOAD:0000000000006BA0↑o |
函数一开始有很多的 push ,realloc 函数先执行 push 压栈,然后在跳转执行 realloc_hook 存储的函数。我们就是利用这些 push 调整栈帧。push 的数量发生变化会影响 rsp 的地址,这样就可以控制 rsp 的取值,从而满足 onegadget 的执行条件。除了可以控制 push 数量,还能通过偏移得到其他的 push xxx 。
malloc_hook 与 realloc_hook 配合
将 malloc_hook 劫持为 realloc ,realloc_hook 劫持为 onegadget ,实际运行顺序:
1 | malloc -> malloc_hook -> realloc -> realloc_hook -> onegadget |
这样就能经过 realloc 调整栈帧后再运行 onegadget 。实际情况中,并不是直接劫持 malloc_hook 为 realloc ,而是要加上一定的偏移,也就是调整 push 的数量,让栈帧结构满足 onegadget 运行。
demo1
我们以 https://www.yuque.com/idcm/wnemg9/rm9lztbtgps8cz57 为例看一看调整栈帧的过程:
触发 malloc (即最后的 add(6, 0x10)) 之前,用 GDB attach 上去并下断点:
1 | ... |

假设我们现在并不清楚选择哪个 gadgets 和 realloc_hook 的偏移,我们先搜集信息:
- 查看当前 rsp 栈帧以及 realloc 的汇编代码:
disass __libc_realloc

1 | pwndbg> disass __libc_realloc |
当我们从 realloc + 0x0 开始执行这个函数,每一次 push 都会导致 rsp - 0x8,如果我们绕过这些 push 直接到 realloc + 16 的地方寻找 sub rsp,0x38 指令,就会使 rsp 的栈帧直接 -0x38,那么我们 gadgets 进行判断的时候就会使 rsp - 0x70 的检查变为: rsp + 0x70 - 0x38 = rsp + 0x38 = NULL。
我们此时再去看 rsp 的栈帧,rsp + 0x38 的数据为 0,因此可以通过 gadgets 的判断从而获取shell。
demo2
再看一道国赛题 https://www.yuque.com/idcm/hnfk6u/xygapu3i4gero3zi
1 | ... |

看一下此时的 rsp 栈帧和 realloc 函数汇编:
1 | pwndbg> x/20gx $rsp |
两个 push 和一个 sub 0x18 让 rsp 下降了 0x28,我们需要 rsp + 0x40 - 0x28 = rsp + 0x18 = NULL
此时是正好符合我们的条件的,因此可以获取 shell
存疑
- 这里提一点 io.sendline(p64(realloc + 14)) 也是可以成功的,它符合 onegadgets 的另一个条件
- 尽管现在还不是很理解为什么可以是 14
更新: 2026-04-27 20:58:02
原文: https://www.yuque.com/idcm/wnemg9/dfg3cdnir7uc2mp1