Java agent技术的注入利用与避坑点

这篇具有很好参考价值的文章主要介绍了Java agent技术的注入利用与避坑点。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

什么是Java agent技术?

Java代理(Java agent)是一种Java技术,它允许开发人员在运行时以某种方式修改或增强Java应用程序的行为。Java代理通过在Java虚拟机(JVM)启动时以"代理"(agent)的形式加载到JVM中,以监视、修改或甚至完全改变目标应用程序的行为。

Java agent 可以做什么?

  1. 安全监控和审计:

    通过Java代理,可以在应用程序中注入代码以监视其行为并记录关键事件。这可以用于安全审计目的,以确保应用程序不受到恶意行为或违规操作的影响。

  2. 安全验证和授权:

    Java代理可以拦截对受保护资源的访问,并执行安全验证和授权操作。通过代理,可以实现访问控制策略,确保只有经过授权的用户或系统可以访问特定资源。

  3. 安全加固:

    通过Java代理,可以对应用程序进行安全加固,例如实时检测和防御攻击,包括代码注入、SQL注入、跨站点脚本攻击等。代理可以拦截请求,并根据安全策略进行处理,从而提高应用程序的安全性。

  4. 加密和解密:

    Java代理可以用于实现端到端的数据加密和解密,保护敏感数据在传输过程中的安全性。代理可以拦截数据流,对数据进行加密或解密操作,以确保数据在传输过程中不会被窃取或篡改。

  5. 安全日志记录:

    Java代理可以用于记录应用程序的安全日志,包括用户操作、异常事件、安全警报等。通过代理,可以将安全日志发送到中央日志服务器进行集中管理和分析,以便及时发现和应对安全威胁。

静态Agent使用

创建Maven项目,写一个类PreMainTraceAgent,使用Maven编译并打成jar包。

package com.example;
​
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;
​
public class PreMainTraceAgent {
​
public static void premain(String agentArgs, Instrumentation inst) {
System.out.println("agentArgs : " + agentArgs);
inst.addTransformer(new DefineTransformer(), true);
}
​
static class DefineTransformer implements ClassFileTransformer {
static int counts=0;
@Override
public byte[] transform(
ClassLoader loader,
String className,
Class<?> classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer
) throws IllegalClassFormatException {
System.out.println("premain load Class:" + className);
System.out.println("filter "+(counts++)+" class");
return classfileBuffer;
}
}
}

打成jar包之后我们要注意META-INF目录下的MSNIFEST.MF文件,MANIFEST.MF文件是 Java 归档文件(如 JAR文件)的一部分,用于描述归档文件的元数据信息和配置。它通常位于归档文件的根目录下。

一些常见的属性我们需要了解

  1. Manifest-Version: 描述了 MANIFEST.MF 文件的版本。

  2. Created-By: 描述了创建该归档文件的工具名称和版本。

  3. Main-Class: 描述了可执行 JAR 文件的入口类(Main类),当您执行 JAR

    文件时,Java虚拟机会自动寻找并执行该类中的main方法。

  4. Class-Path: 描述了归档文件中包含的依赖项 JAR 文件的路径,以便 Java

    虚拟机在运行时能够找到并加载这些依赖项。

在构建和部署 Java 应用程序时,MANIFEST.MF文件可以帮助指定各种元数据信息,使得应用程序可以更好地被管理和执行。例如,当您创建一个可执行的JAR 文件时,通过指定 Main-Class 属性,可以告诉 Java 虚拟机该 JAR文件的入口点是哪个类。

另外创建一个项目,写一个主函数,内容随意,配置虚拟机选项。这里-javaagent:后面跟上上面项目jar包的绝对路径

运行结果如图:

可以看到premain方法中的代码成功的执行在了Main函数之前。这种使用premain方法在Main函数前执行的也被成为静态agent

【----帮助网安学习,以下所有学习资料免费领!加vx:dctintin,备注 “博客园” 获取!】

 ① 网安学习成长路径思维导图
 ② 60+网安经典常用工具包
 ③ 100+SRC漏洞分析报告
 ④ 150+网安攻防实战技术电子书
 ⑤ 最权威CISSP 认证考试指南+题库
 ⑥ 超1800页CTF实战技巧手册
 ⑦ 最新网安大厂面试题合集(含答案)
 ⑧ APP客户端安全检测指南(安卓+IOS)

动态Agent使用

首先是被代理部分(单独的项目)

package com.example;
​
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;
​
public class AgentMain {
public static void agentmain(String agentArgs, Instrumentation
instrumentation) {
instrumentation.addTransformer(new MyTransformer(),true);
​
}
public static class MyTransformer implements ClassFileTransformer {
static int count = 0;
​
@Override
public byte[] transform(
ClassLoader loader,
String className,
Class<?> classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
System.out.println("hello world");//这里就是我们能看到的输出。
return classfileBuffer;
}
}
}

接下来就是使用Maven打成jar包

默认情况下META-INFMANIFEST.MF文件中有这些内容

Manifest-Version: 1.0

Created-By: Maven JAR Plugin 3.3.0

Build-Jdk-Spec: 11

但是这些是不够的,我们需要指出被代理的类。

Manifest-Version: 1.0

Agent-Class: com.example.AgentMain

Can-Redefine-Classes: true

Can-Retransform-Classes: true

  1. Agent-Class:指定了代理的入口类。这个属性告诉 Java

    虚拟机代理应该从哪个类的 premain 或 agentmain方法开始执行。premain 方法用于静态代理(在 JVM启动时加载),而 agentmain 方法用于动态代理(在 JVM运行时加载)。代理的入口类必须包含其中一个方法。

  2. Can-Redefine-Classes:指定了代理是否可以重新定义类。如果设置为

    true,代理将允许重新定义已经加载的类,这意味着你可以修改已经加载的类的字节码。这对于某些代理操作,如热代码替换,非常有用。

  3. Can-Retransform-Classes:指定了代理是否可以重新转换类。如果设置为

    true,代理将允许重新转换已经加载的类,这意味着你可以多次修改已经加载的类的字节码。这对于一些特定的代理操作也是非常有用的,如AOP(面向切面编程)。

因为是动态加载所以我们不需要在虚拟机启动选项中指定jar包的路径。

接下来写主程序的测试类

package org.example;
​
import com.sun.tools.attach.VirtualMachine;
​
import java.io.File;
import java.lang.management.ManagementFactory;
​
public class TestMain {
public static void main(String[] args) {
String agentJarPath =
"C:Users86186DesktopstudyJavauntitledtargetuntitled-1.0-SNAPSHOT.jar";
File agentJarFile = new File(agentJarPath);
if (!agentJarFile.exists()) {
System.err.println("Agent JAR file not found.");
return;
}
String name = ManagementFactory.getRuntimeMXBean().getName();
String pid = name.split("@")[0];
​
if (pid == null) {
System.err.println("Unable to find process ID.");
return;
}
String targetClassName = "AgentMain";
try {
VirtualMachine vm = VirtualMachine.attach(pid);
vm.loadAgent(agentJarPath,targetClassName);
vm.detach();
} catch (Exception e) {
e.printStackTrace();
}
}
​
}

这里在获取进程号的时候会因为版本的不同而出现错误,java9以下默认是正常的,java9以上会出现报错,我们需要在虚拟机启动参数中加上-Djdk.attach.allowAttachSelf=true。

运行结果:

为什么结果中有多个helloworld

这里有讲一下为什么我们在代码中之用了一次sout,但是在结果中却出现了多个helloworld。

MyTransformer类中的transform方法中的输出语句只会在类被加载时执行一次,但是它会对每个类文件调用一次。由于一个类可能会由多个ClassLoader加载,或者同一个ClassLoader可能会加载多次,因此会导致多次输出。

这种情况通常在Java应用程序中使用了多个ClassLoader时发生,例如Web应用程序中的热部署或者OSGi环境中。每次类被加载,transform方法都会被调用一次,因此会看到多次输出。

我们可以修改一下代码做测试,这里我在每个helloworld后添加了被加载类的名字

修改后的输出结果:

实战示例:修改目标虚拟机中执行的程序

第一步

首先我们写出我们正在执行的程序:循环打印helloworld。

package org.example;
​
import static java.lang.Thread.sleep;
​
public class Main {
public static void main(String[] args) throws InterruptedException {
while(true) {
hello();
sleep(1500);
}
}
public static void hello(){
System.out.println("Hello World!");
}
}

第二步

准备我们的agentmain和ClassFileTransformer实现类。

package com.example;
​
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
import java.security.ProtectionDomain;
​
public class AgentMain {
public static void agentmain(String agentArgs, Instrumentation
instrumentation) throws UnmodifiableClassException {
Class [] classes = instrumentation.getAllLoadedClasses();
​
//获取目标JVM加载的全部类
for(Class cls : classes){
​
if (cls.getName().equals("org.example.Main")){
​
instrumentation.addTransformer(new HackTransform(),true);
instrumentation.retransformClasses(cls);
}
// System.out.println(cls.getName());
}
​
}
​
}
​
package com.example;
​
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
​
import java.io.IOException;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
​
public class HackTransform implements ClassFileTransformer {
​
@Override
public byte[] transform(ClassLoader loader, String className,
Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
if (className.equals("org/example/Main")) {
try {
System.out.println(className);
​
ClassPool classPool = ClassPool.getDefault();
​
​
if (classBeingRedefined != null) {
ClassClassPath ccp = new ClassClassPath(classBeingRedefined);
classPool.insertClassPath(ccp);
}
​
CtClass ctClass = classPool.get("org.example.Main");
System.out.println(ctClass);
​
​
CtMethod ctMethod = ctClass.getDeclaredMethod("hello");
​
//设置方法体
String body = "{System.out.println("[+]Hacker!!");}";
ctMethod.setBody(body);
ctClass.defrost();
​
return ctClass.toBytecode();
​
} catch (Exception e) {
e.printStackTrace();
}
}
​
return null;
}
}

第三步

把第二步中的两个类打成jar包。并修改其中MANIFEST.MF中的内容。

MANIFEST.MF中的内容

Manifest-Version: 1.0Agent-Class:com.example.AgentMainCan-Redefine-Classes: trueCan-Retransform-Classes:true

第四步

写我们的注入代码

package org.example;
​
import com.sun.tools.attach.*;
​
import java.io.IOException;
import java.util.List;
​
public class inject {
​
public static void main(String[] args) throws IOException,
AttachNotSupportedException, AgentLoadException,
AgentInitializationException {
//调用VirtualMachine.list()获取正在运行的JVM列表
List<VirtualMachineDescriptor> list = VirtualMachine.list();
for (VirtualMachineDescriptor vmd : list) {
System.out.println(vmd.displayName());
​
if (vmd.displayName().equals("org.example.Main")) {
​
//连接指定JVM
VirtualMachine virtualMachine = VirtualMachine.attach(vmd.id());
String agentJarPath =
"C:Users86186DesktopstudyJavauntitledtargetuntitled-1.0-SNAPSHOT.jar";
//加载Agent
virtualMachine.loadAgent(agentJarPath,"com.example.AgentMain");
//断开JVM连接
virtualMachine.detach();
}
​
}
​
}
}

第五步

执行即可(先运行主java程序,后运行注入程序)

更多网安技能的在线实操练习,请点击这里>>

  文章来源地址https://www.toymoban.com/news/detail-837683.html

到了这里,关于Java agent技术的注入利用与避坑点的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • golang学习之七:for 语句的常见“坑”与避坑方法

    下面这个示例是对一个整型切片进行遍历,并且在每次循环体的迭代中都会创建一个新的,Goroutine(Go 中的轻量级协程),输出这次迭代的元素的下标值与元素值。 控制台 但是以上打印结果与我们的预期不符,这是为啥。 基于golang隐式代码块的规则(大家可以自行百度,这

    2024年02月16日
    浏览(41)
  • AI绘图cuda与stable diffusion安装部署始末与避坑

    stable diffusion的安装说起来很讽刺,最难的不是stable diffusion,而是下载安装cuda。下来我就来分享一下我的安装过程,失败了好几次,几近放弃。 我们都知道cuda是显卡CPU工作的驱动(或者安装官网的解释为一个GPU加速器app),这里么有什么介绍的,既然是驱动就要安装对版本

    2024年04月10日
    浏览(39)
  • 使用logstash将项目的日志存储到Elasticsearch中(详细!新手避坑点!)

    1.环境准备 我这里默认你们这个logstash和Elasticsearch已经安装好了。 我使用的是logstash版本7.4.0 Elasticsearch版本7.4.0。 使用其他版本 注意版本一定要一致,版本不一致大概率会出现logstash启动报Failed to install template.异常 ,已经踩坑了。 logstash的配置文件: 接下来 以配置文件启

    2024年02月04日
    浏览(86)
  • 【ES6】js 中class的extends、super关键字用法和避坑点

    在JavaScript中,使用class可以实现面向对象编程。其中,extends和super是两个非常重要的,它们分别用于实现类的继承和调用父类的方法。 一、extends extends用于实现类的继承,它可以让一个子类继承父类的属性和方法。使用extends时,需要指定要

    2024年02月09日
    浏览(32)
  • Java Agent技术

    在定位公司问题的时候,需要了解一下skywalking的相关知识,而agent就提上了日程。 官网文档 Agent技术是Jdk在1.5版本之后,所提供的一个在jvm启动前后对部分java类代理加强的机制。由于是直接修改字节码,并不会对业务代码有注入,所以可以很好的应用于监控或者热部署等场

    2024年02月09日
    浏览(41)
  • JAVA安全之Log4j-Jndi注入原理以及利用方式

    什么是JNDI? JDNI(Java Naming and Directory Interface)是Java命名和目录接口,它提供了统一的访问命名和目录服务的API。 JDNI主要通过JNDI SPI(Service Provider Interface)规范来实现,该规范定义了对JNDI提供者应实现的接口。在JNDI体系中,JNDI提供者是指实际提供命名和目录服务的软件组

    2024年01月19日
    浏览(82)
  • 如何利用 Agent 构建AI服务

    近年来,人工智能(AI)技术的飞速发展引起了广泛的关注和讨论。而如今,我们正站在一个全新的时代门槛前,面对着AI Agent带来的的崭新未来。以LLM(大型语言模型)作为其核心控制器构建代理是一个很酷的概念。它模拟人类的工作流程,能够自主进行信息搜索、分析、利

    2024年02月11日
    浏览(36)
  • Java接入sqlserver的一些坑点记录

    1.Java对应sqlserver的jdbc版本 jdbc对应的maven版本:网上搜索出来的资料有两种,一种是比较老版本的 这个版本我去maven的主仓库查了下,更新时间是2016年3月份,所以最好就别用这个老版本的包了。 推荐使用 :另外一种是船新版本的driver 2.Java对应sqlserver驱动名称 驱动名称: 发

    2024年02月08日
    浏览(34)
  • Ubuntu: windows10利用ssh连接Ubuntu,配置ssh,避坑

    什么是ssh:ssh是Secure Shell(安全外壳协议)的缩写,建立在应用层和传输层基础上的安全协议。为了便于访问github,要生成ssh公钥,这样就不用每一次访问github都要输入用户名和密码。 我们是使用 SSH 连接远程服务器,因此 Windows 需要支持 SSH, 使用 Win + R ,输入 cmd 打开控制

    2024年02月10日
    浏览(53)
  • 【AI导师】利用Coding Agent完成AIGC编程

      AI产品的发展确实在过去两年年中取得了显著进展,尤其是在编程领域。一开始,ChatGPT和类似的语言模型主要用于自然语言处理和生成对话。在这个背景下,一些国内的开发者和企业开始将这些技术应用于编程领域,形成了一些 Coding Agent 类型的AI产品。   这些产品的

    2024年02月03日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包