### JNDI 如何做 Hook

1. 使用 Java Agent 动态修改字节码

这是最强大和最通用的 Hook 方法。Java Agent 可以在不修改源代码的情况下，在 JVM 运行时动态地修改类的字节码

- 原理：创建一个 Java Agent，并在 JVM 启动时通过 `-javaagent` 参数加载它。在 Agent 的 `premain` 或 `agentmain` 方法中，你可以使用 ASM、Javassist 或 Byte Buddy 等字节码操作库，找到 `InitialContext.lookup(name)` 所在的类和方法
- Hook 实现：找到目标方法后，可以修改它的字节码，在其原始逻辑执行前或执行后插入你自己的代码
  - 插入安全检查：在 `lookup` 方法的开头，插入一段代码来检查传入的 URL。你可以判断 URL 是否符合预设的白名单，或者直接拒绝所有远程 JNDI 请求
  - 记录日志：将 `lookup` 方法的参数和调用堆栈记录下来，以便进行审计
  - 修改返回对象：如果 URL 被判定为恶意，你可以修改 `lookup` 方法的返回值为一个安全的对象，而不是让其继续进行远程查找
- 优点：非常灵活，可以 Hook 任何类的任何方法，无需访问源代码
- 缺点：需要深入理解 Java 字节码，且实现起来比较复杂。

2. 使用动态代理

动态代理是一种更高级的 Hook 方法，它通过 Java 的反射机制来创建接口的代理对象

- 原理：如果你知道应用程序使用的是某个 JNDI 接口（例如 `Context`），你可以创建一个代理对象，这个代理对象会实现相同的接口，并在所有方法调用时，将调用转发给你自己的处理逻辑
- Hook 实现：
  1. 找到应用程序创建 `InitialContext` 的地方
  2. 用你自己的代理类替换 `InitialContext` 的实例
  3. 在代理类中，拦截 `lookup(name)` 方法的调用
  4. 在 `lookup` 方法的实现中，你可以先执行安全检查，然后再决定是否调用原始的 `InitialContext.lookup(name)`
- 优点：不需要字节码操作，相对简单
- 缺点：只能 Hook 接口，对于没有实现接口的类不起作用。此外，需要修改应用程序的某些部分来插入代理，不像 Java Agent 那样完全透明

3. 修改 JVM 参数

这是最简单的 Hook 方法，但功能也最有限

- 原理：一些 JVM 实现了特殊的参数来控制 JNDI 的行为。例如，在一些版本的 Java 中，可以通过设置 `com.sun.jndi.rmi.object.trustURLCodebase=false` 来阻止 RMI 客户端加载远程对象
- Hook 实现：只需在 JVM 启动命令中添加这些参数即可
- 优点：非常简单，无需编写代码
- 缺点：依赖于特定的 JVM 版本和参数，无法进行细粒度的控制，也不能用于日志记录等目的