### NX 是怎么绕过的

**绕过 NX 的基本思路**

NX 阻止了攻击者在数据段上执行**自己的代码**。那么，绕过 NX 的基本思路就是：**不注入代码，而是利用程序本身已有的、具有执行权限的代码**

这个思路催生了多种绕过技术，其中最主要、最著名、最通用的就是 **ROP**

**ROP**

ROP 是目前最主流的 NX 绕过技术。它的原理是利用程序中已有的、以 `ret` 指令结尾的短小代码片段，这些片段被称为 **“gadgets”**

**ROP 的工作原理**

1. **寻找 Gadgets：** 攻击者首先在目标程序或其依赖的共享库（如 `libc`）中寻找一系列以 `ret` 指令结尾的“gadgets”。一个 gadget 可能是一条或几条汇编指令，例如：`pop edi; ret;` 或 `mov eax, [ebx]; ret;`
2. **构建 ROP 链：** 攻击者利用漏洞（如缓冲区溢出），用一系列精心挑选的 gadget 地址来覆盖栈上的返回地址这些地址按顺序排列，形成一个 **“ROP 链”**
3. **劫持控制流：** 当函数返回时，它不再返回到正常调用的地方，而是返回到 ROP 链中的第一个 gadget
4. **链式执行：**
   - 第一个 gadget 执行完后，其末尾的 `ret` 指令会从栈上弹出下一个地址，也就是 ROP 链中的第二个 gadget
   - 这样，一个 gadget 接一个 gadget 地执行，每个 `ret` 指令都将控制流转移到下一个 gadget
   - 通过这种方式，攻击者可以利用程序中已有的代码，间接地执行任意恶意逻辑

**ROP 攻击的最终目标**

一个典型的 ROP 攻击，其最终目标通常是调用某个函数，比如 `system()`，并将一个指向 Shell 命令字符串（例如 `"/bin/sh"`）的指针作为参数传递给它

一个完整的 ROP 链通常包含：

- **`pop` gadget：** 用于将栈上的参数值弹出到寄存器中，为函数调用做准备
- **`system()` 的地址：** ROP 链的末尾，用于最终调用 `system()`
- **字符串 `/bin/sh` 的地址：** 作为 `system()` 的参数

**绕过 NX 的其他方法**

除了 ROP，还有其他一些不那么常见，但同样能绕过 NX 的技术：

**1. JIT Spraying（JIT 喷射）**

这种方法主要用于绕过浏览器中的 NX 保护

- **原理：** JIT（Just-In-Time）编译器会动态地生成可执行代码。攻击者可以利用 JavaScript 等语言的 JIT 特性，构造大量的 `nop` 指令（无操作指令），然后在其末尾附上 Shellcode
- **工作方式：** JIT 引擎会将这些指令编译成原生机器码并存放在一个**可执行的**内存区域。攻击者只需找到这个可执行区域的地址，并跳转过去即可

**2. Return-to-libc（返回到 libc）**

Return-to-libc 是 ROP 的前身和简化版。它不需要复杂的 gadget 链，而是直接劫持程序流，跳转到已加载的 `libc` 库中的一个函数

- **原理：** 攻击者利用漏洞，用 `libc` 中 `system()` 函数的地址覆盖栈上的返回地址
- **工作方式：** 当函数返回时，程序流会直接跳转到 `system()` 函数。攻击者在栈上预先放置好 `system()` 函数所需的参数（如 `"/bin/sh"` 的地址），即可实现代码执行
- **局限性：** 这种方法非常简单，但它只能调用 `libc` 中已有的函数，而不能像 ROP 那样组合出更复杂的逻辑