Agent 内存马的攻防之道
字数 2109 2025-08-20 18:18:40

Agent 内存马的攻防之道 - 深入解析与实战指南

一、Java 内存马概述

Java 内存马主要分为两种形式:

  1. 创建 Java Web 组件(如 Controller、Servlet、Filter、Valve)并通过反射注册或替换
  2. 通过 Java Agent 技术修改关键类(如 Servlet)的代码

Agent 型内存马特点

  • 修改的类位置不固定
  • 被修改的类不是纯粹的"内存"类
  • 检测难度高于传统内存马

二、Java Agent 技术基础

1. 加载方式

  • Agent_OnLoad:通过 -javaagent 参数加载
  • Agent_OnAttach:通过 VM.attach 方法注入

2. 关键类与方法

  • Instrumentation 接口
    • redefineClasses:重定义类
    • addTransformer + retransformClasses:添加转换器并重新转换类

3. JVM 类加载流程

  1. 正常类加载

    • 从本地 jar 包获取类字节码
    • 经过 JvmtiClassFileLoadHookPoster 转换
    • 编译为 InstanceKlass
  2. redefineClasses

    • 类来源更换为指定字节码
    • 类加载流程与正常加载类似
  3. retransformClasses

    • 根据 InstanceKlass 重新生成类字节码
    • 存入缓存 InstanceKlass._cached_class_file

三、攻防对抗分析

1. 攻击方式

(1) 通过 redefineClasses

  • 优点:直接有效
  • 缺点:容易被防护模式检测到

(2) 通过 retransformClasses

  • 优点:若攻击者 agent 在防御者之后注入,防御者无法获取修改后的字节码
  • 缺点:需要先添加 reTransformer

2. 防御方式

(1) 防护模式

  • 应用运行时加载检测 agent
  • 添加 reTransformer 监控关键类
  • 可检测到类被重新加载

(2) 临时检测模式

  • 通过 VirtualMachine.attach 加载检测 agent
  • 添加临时 reTransformer 获取类字节码

3. 攻防博弈场景

攻击方式 防御模式 检测结果
redefineClasses 防护模式 可检测
retransformClasses 防护模式 无法获取修改后字节码
redefineClasses 临时检测 可检测
retransformClasses 临时检测 可检测

四、高级攻击技术

1. 借尸还魂技术

原理:利用已有 agent 的 InstrumentationImpl 实例

实现步骤

  1. 从内存解析 JvmtiEnv
  2. 获取 _env_local_storage (_JPLISEnvironment)
  3. 从中获取 InstrumentationImpl 实例
  4. 使用 jobject 转 Java 对象技术

关键代码

// 获取对象地址
long address = unsafe.getLong(new Object[]{obj}, arrayBaseOffset);

// 从地址恢复对象
unsafe.putLong(array, arrayBaseOffset, jobjectAddr);
Object obj = array[0];

2. 无文件 Agent 注入

技术难点

  1. 构造 JPLISAgent 对象
  2. 获取 JavaVM 实例(从 libjvm.somain_vm 符号)
  3. 获取 jmethodID(通过解析 jobject

实现方案

  1. 使用 setHasRetransformableTransformers 创建 JvmtiEnv
  2. 解析 jobject 获取 klass 地址
  3. 通过方法参数数量定位 transformer 方法

3. 隐蔽攻击技术

核心思想:确保攻击者的 jvmtiEnv 在链末尾

实现方法

  1. 检查自身是否在链末尾
  2. 若不在,移动到末尾并设置清除标志
  3. 下次执行时结束链

代码片段

if(!clearFlag){
    long nextJvmti = getTheNextOfJvmtiEnv(ownJvmtiEnvAddr);
    if (nextJvmti != 0){
        // 从链中剔除自己的 jvmtiEnv
        putLong(jvmtiPointer, nextJvmti);
        
        // 将自己添加到链末尾
        long lastJvmti = findTheLastJvmtiEnv();
        setTheNextJvmti(lastJvmti, ownJvmtiEnvAddr);
        
        clearFlag = true;
        return null;
    }
}

五、内存马实战

1. 传统 Agent 内存马

  • 修改 javax.servlet.http.HttpServletservice 方法
  • 拦截所有请求

2. 高级内存马特点

  • 无文件落地
  • 防御工具无法检测
  • 修改后不会因防御扫描而失效

3. 防御建议

  1. 监控 addTransformerretransformClassesredefineClasses 方法
  2. 定期检查关键类字节码
  3. 使用专业内存马检测工具

六、总结与展望

Java Agent 内存马技术不断发展:

  1. 从落地 Jar 到无文件注入
  2. 从简单修改到隐蔽攻击
  3. 攻防对抗日益复杂

未来方向

  1. 更隐蔽的注入技术
  2. 对抗高级检测手段
  3. 跨平台兼容性解决方案

七、参考资源

  1. OpenJDK 源码
  2. Java Object Layout
  3. 基于 javaAgent 内存马检测查杀指南
  4. 如何优雅的注入 Java Agent 内存马
  5. Java 内存攻击技术漫谈

:本文涉及技术仅供学习研究,请勿用于非法用途。实际应用中请遵守相关法律法规。

Agent 内存马的攻防之道 - 深入解析与实战指南 一、Java 内存马概述 Java 内存马主要分为两种形式: 创建 Java Web 组件(如 Controller、Servlet、Filter、Valve)并通过反射注册或替换 通过 Java Agent 技术修改关键类(如 Servlet)的代码 Agent 型内存马特点 : 修改的类位置不固定 被修改的类不是纯粹的"内存"类 检测难度高于传统内存马 二、Java Agent 技术基础 1. 加载方式 Agent_ OnLoad :通过 -javaagent 参数加载 Agent_ OnAttach :通过 VM.attach 方法注入 2. 关键类与方法 Instrumentation 接口 redefineClasses :重定义类 addTransformer + retransformClasses :添加转换器并重新转换类 3. JVM 类加载流程 正常类加载 : 从本地 jar 包获取类字节码 经过 JvmtiClassFileLoadHookPoster 转换 编译为 InstanceKlass redefineClasses : 类来源更换为指定字节码 类加载流程与正常加载类似 retransformClasses : 根据 InstanceKlass 重新生成类字节码 存入缓存 InstanceKlass._cached_class_file 三、攻防对抗分析 1. 攻击方式 (1) 通过 redefineClasses 优点 :直接有效 缺点 :容易被防护模式检测到 (2) 通过 retransformClasses 优点 :若攻击者 agent 在防御者之后注入,防御者无法获取修改后的字节码 缺点 :需要先添加 reTransformer 2. 防御方式 (1) 防护模式 应用运行时加载检测 agent 添加 reTransformer 监控关键类 可检测到类被重新加载 (2) 临时检测模式 通过 VirtualMachine.attach 加载检测 agent 添加临时 reTransformer 获取类字节码 3. 攻防博弈场景 | 攻击方式 | 防御模式 | 检测结果 | |---------|---------|---------| | redefineClasses | 防护模式 | 可检测 | | retransformClasses | 防护模式 | 无法获取修改后字节码 | | redefineClasses | 临时检测 | 可检测 | | retransformClasses | 临时检测 | 可检测 | 四、高级攻击技术 1. 借尸还魂技术 原理 :利用已有 agent 的 InstrumentationImpl 实例 实现步骤 : 从内存解析 JvmtiEnv 链 获取 _env_local_storage ( _JPLISEnvironment ) 从中获取 InstrumentationImpl 实例 使用 jobject 转 Java 对象技术 关键代码 : 2. 无文件 Agent 注入 技术难点 : 构造 JPLISAgent 对象 获取 JavaVM 实例(从 libjvm.so 的 main_vm 符号) 获取 jmethodID (通过解析 jobject ) 实现方案 : 使用 setHasRetransformableTransformers 创建 JvmtiEnv 解析 jobject 获取 klass 地址 通过方法参数数量定位 transformer 方法 3. 隐蔽攻击技术 核心思想 :确保攻击者的 jvmtiEnv 在链末尾 实现方法 : 检查自身是否在链末尾 若不在,移动到末尾并设置清除标志 下次执行时结束链 代码片段 : 五、内存马实战 1. 传统 Agent 内存马 修改 javax.servlet.http.HttpServlet 的 service 方法 拦截所有请求 2. 高级内存马特点 无文件落地 防御工具无法检测 修改后不会因防御扫描而失效 3. 防御建议 监控 addTransformer 、 retransformClasses 、 redefineClasses 方法 定期检查关键类字节码 使用专业内存马检测工具 六、总结与展望 Java Agent 内存马技术不断发展: 从落地 Jar 到无文件注入 从简单修改到隐蔽攻击 攻防对抗日益复杂 未来方向 : 更隐蔽的注入技术 对抗高级检测手段 跨平台兼容性解决方案 七、参考资源 OpenJDK 源码 Java Object Layout 基于 javaAgent 内存马检测查杀指南 如何优雅的注入 Java Agent 内存马 Java 内存攻击技术漫谈 注 :本文涉及技术仅供学习研究,请勿用于非法用途。实际应用中请遵守相关法律法规。