# 从任意地址写到控制执行流的方法总结

## 0x00 前言

任意地址写（Arbitrary Address Write, AAW），是指在漏洞利用过程中，攻击者拥有对任意指定地址上的内容进行修改的能力。

产生任意地址写漏洞的原因可能很多，如栈指针溢出、格式化字符串漏洞、UNLINK等等，但是从任意地址写到控制执行流，往往还有很长的路要走。以下是一些常用套路的总结。

## 0x01 GOT表覆写

这是最常见，也是最简单的一种。

通过覆写动态链接程序中，某个函数的GOT表，就能控制对应函数的指向，使这个函数在被调用的时候，运行我们覆写的地址处的代码。

关于GOT、PLT和延迟绑定技术，参考：《[通过 GDB 调试理解 GOT/PLT](http://rickgray.me/2015/08/07/use-gdb-to-study-got-and-plt.html)》

## 0x02 .fini\_array段覆写

在程序中，也许在漏洞产生后就不再有库函数的调用，因此GOT覆写就没有意义了。此时可以通过覆写.fini\_array来控制执行流。

.fini\_array是ELF程序中一个特殊的段，它存放着在程序即将结束时需要执行的一系列代码的地址。因此修改了这个数组，就能在程序结束的时候得到一次代码执行的机会。

## 0x03 覆盖函数指针

这也是比较简单的一种方法。一般是覆盖全局结构体中的函数指针，或者覆盖类的虚表中的函数指针，调用的时候就能执行我们写入的代码。

## 0x04 覆写栈上的返回地址

由于栈中存放着返回地址，因此可以通过覆写返回地址来控制执行流。

但是由于任意地址写一般和栈溢出不同，栈溢出只要考虑返回地址和溢出点的相对位置，而任意地址写漏洞往往需要知道地址的确定值，因此在通过任意地址写漏洞来覆写返回地址的时候，一般需要先泄露一个栈上的地址，得到栈在内存空间中的位置，通过计算得到返回地址所在的内存地址。

可以通过调试，来得到返回地址和泄露的地址之间的偏移。当每次启动程序，执行的指令相同，虽然栈被分布在不同的内存页上，但栈中的相对位置往往是不变的。所以可以通过偏移来计算返回地址的位置，覆写即可。

## 0x05 覆写\_\_free\_hook

当开启RELRO或PIE保护时，ELF程序部分中很难利用，甚至连地址都难以获得，只能通过libc做文章。

只要先泄露libc的基址，然后覆写libc中的\_\_free\_hook就能对free函数进行劫持。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ctfbook.ph0en1x.com/pwn/cong-ren-yi-di-zhi-xie-dao-kong-zhi-zhi-xing-liu-de-fang-fa-zong-jie.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
