zoukankan      html  css  js  c++  java
  • JavaAgent简单学习

    1、Java Agent

      相当于main方法之前的一个拦截器

           本身是Java命令的一个参数,后面跟一个Jar包

           对Jar包的要求

        在META-INF目录下的MANIFEST.MF文件中必须指定premain-class配置项

        premain-class配置项指定的类必须提供premain方法

      针对Jar包的要求,我们可以使用maven插件来完成 maven-assembly-plugin

    1.1 通过Java Agent调整加载的类信息

      创建TestClass,修改返回值,生成新的class文件存放到其他目录,之后就是将原来的class信息,修改成其他目录下的class文件信息

    package com.fh;
    
    public class TestClass {
    
        public int getNumber(){
            return 1;
        }
    }
    View Code

    进行方法调用  启动类需要添加指定的参数

    package com.fh;
    
    /**
     * -javaagent:E:idea_workspaceworkspace_skywalkingTestAgent	argetTestAgent-1.0-SNAPSHOT.jar
     */
    public class Main {
    
        public static void main(String[] args) throws InterruptedException {
            System.out.println(new TestClass().getNumber());
        }
    }
    View Code

    创建一个新的项目作为agent的jar来使用

    package com.fh;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.InputStream;
    import java.lang.instrument.ClassFileTransformer;
    import java.lang.instrument.IllegalClassFormatException;
    import java.lang.instrument.Instrumentation;
    import java.lang.instrument.UnmodifiableClassException;
    import java.security.ProtectionDomain;
    
    /**
     * 存在方法重载,如果两个都存在,一般会执行第一个
     * sun.instrument.InstrumentationImpl.java
     */
    public class TestAgent1 {
    
    
        /**
         *
         * @param agentArgs -javaagent命令携带的参数
         * @param inst 提供了操作类定义的相关方法
         */
        public static void premain(String agentArgs, Instrumentation inst) throws UnmodifiableClassException {
    //      注册/注销一个ClassFileTransformer类的实例,该Transformer实例会在类加载的时候被调用
    //      可用于修改类定义
    //      inst.addTransformer();
    //      inst.removeTransformer();
    
    //      针对的是已经加载的类,他会对已经传入的类进行重新定义
    //      inst.redefineClasses();
    //      返回虚拟机已经加载的所有类
    //      inst.getAllLoadedClasses()
    //      返回当前虚拟机已经初始化的类
    //      inst.getInitiatedClasses()
    //      获取参数指定的对象的大小
    //      inst.getObjectSize()
    
    
    //        System.out.println("this is a Java agent with two args");
    //        System.out.println("参数:"+agentArgs);
    
            inst.addTransformer(new Transformer(),true);
            inst.retransformClasses(TestClass.class);
            System.out.println("premain done");
        }
    
        public static void premain(String agentArgs){
            System.out.println("this is a Java agent with only one args");
            System.out.println("参数:"+agentArgs);
        }
    
        static class Transformer implements ClassFileTransformer{
    
            @Override
            public byte[] transform(ClassLoader loader, String className, Class<?> c, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
                if(!c.getSimpleName().equals("TestClass")){
                    return null;
                }
                return getBytesFromFile("E:\idea_workspace\workspace_skywalking\agent-demo\TestClass.class");
            }
    
            public byte[] getBytesFromFile(String filename){
                try {
                    File file = new File(filename);
                    InputStream is = new FileInputStream(file);
                    long length = file.length();
                    byte[] bytes = new byte[(int) length];
    
                    //read the bytes
                    int offset = 0;
                    int numRead = 0;
                    while (offset < bytes.length &&
                            (numRead = is.read(bytes,offset,bytes.length-offset))>=0){
                        offset +=numRead;
                    }
                    if(offset < bytes.length){
                        throw new Exception("Could not completely read file");
                    }
                    is.close();
                    return bytes;
                }catch (Exception e){
                    e.printStackTrace();
                    return null;
                }
    
            }
        }
    }
    View Code

    pom文件

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.fh</groupId>
        <artifactId>TestAgent</artifactId>
        <version>1.0-SNAPSHOT</version>
    
    
        <dependencies>
            <dependency>
                <groupId>com.fh</groupId>
                <artifactId>agent-demo</artifactId>
                <version>1.0-SNAPSHOT</version>
                <scope>compile</scope>
            </dependency>
            <!--统计方法耗时-->
            <dependency>
                <groupId>net.bytebuddy</groupId>
                <artifactId>byte-buddy</artifactId>
                <version>1.10.19</version>
            </dependency>
            <dependency>
                <groupId>net.bytebuddy</groupId>
                <artifactId>byte-buddy-agent</artifactId>
                <version>1.10.19</version>
            </dependency>
        </dependencies>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-assembly-plugin</artifactId>
                    <version>2.4</version>
                    <configuration>
                        <appendAssemblyId>false</appendAssemblyId>
                        <!--将TestAgent的所有依赖包都打到jar包中-->
                        <descriptorRefs>
                            <descriptorRef>jar-with-dependencies</descriptorRef>
                        </descriptorRefs>
                        <archive>
                            <manifest>
                                <!-- 添加MANIFEST.MF中的各项配置-->
                                <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                                <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
                            </manifest>
                            <!-- 将 premain-class 配置项设置为com.xxx.TestAgent-->
                            <manifestEntries>
                                <Can-Retransform-Classes>true</Can-Retransform-Classes>
                                <Premain-Class>com.fh.TestAgent</Premain-Class>
     
                            </manifestEntries>
                        </archive>
                    </configuration>
                    <executions>
                        <execution>
                            <!-- 绑定到package生命周期阶段上 -->
                            <phase>package</phase>
                            <!-- 绑定到package生命周期阶段上 -->
                            <goals>
                                <goal>single</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.1</version>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                        <encoding>UTF-8</encoding>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </project>
    View Code

    1.2 通过byte-buddy计算方法的耗时   byte-buddy是一个开源的Java库,可以帮助用户屏蔽字节码操作

    package com.fh;
    
    import net.bytebuddy.agent.builder.AgentBuilder;
    import net.bytebuddy.description.method.MethodDescription;
    import net.bytebuddy.implementation.MethodDelegation;
    import net.bytebuddy.matcher.ElementMatchers;
    
    import java.lang.instrument.Instrumentation;
    
    public class TestAgent2 {
    
        public static void premain(String agentArgs,
                                   Instrumentation inst){
            // Byte Buddy会根据 Transformer指定的规则进行拦截并增强代码
            AgentBuilder.Transformer transformer = (builder, typeDescription, classLoader, javaModule) -> {
                // method()指定哪些方法需要被拦截,ElementMatchers.any()表
                return builder.method(ElementMatchers.<MethodDescription>any())
                        .intercept(MethodDelegation.to(TimeInterceptor.class));// intercept()指明拦截上述方法的拦截器
            };
            new AgentBuilder
                    .Default()
                    //根据包名前缀拦截类
                    .type(ElementMatchers.nameStartsWith("com.fh"))
                    .transform(transformer)//拦截到的类由transformer来处理
                    .installOn(inst);//安装到Instrumentation
        }
    }
    View Code
    package com.fh;
    
    import net.bytebuddy.implementation.bind.annotation.Origin;
    import net.bytebuddy.implementation.bind.annotation.RuntimeType;
    import net.bytebuddy.implementation.bind.annotation.SuperCall;
    
    import java.lang.reflect.Method;
    import java.util.concurrent.Callable;
    
    public class TimeInterceptor {
    
        /**
         *
         * @param method 被拦截方法的Method对象
         * @param callable 可以调用到被拦截的目标方法,即使目标方法带参数,也不需要显示传递
         * @return
         * @throws Exception
         */
        @RuntimeType
        public static Object intercept(@Origin Method method,
                                       @SuperCall Callable<?> callable) throws Exception {
            long l = System.currentTimeMillis();
            try {
                return callable.call();
            }finally {
                System.out.println(method.getName()+":"+
                        (System.currentTimeMillis()-l)+"ms");
            }
        }
    }
    View Code

    pom文件需要引入的信息,已经在上面的pom文件中添加,修改premain-class信息即可

    还需要添加Can-Retransform-Classes标签为true

    2、Attach API

      为了更好的灵活性,在Java6之后提供的,可以在main方法之后后执行agentmain方法添加一下特殊的功能

    添加要被监听的方法main   不需要添加javaagent参数

    package com.fh;
    
    /**
     * -javaagent:E:idea_workspaceworkspace_skywalkingTestAgent	argetTestAgent-1.0-SNAPSHOT.jar
     */
    public class Main {
    
        public static void main(String[] args) throws InterruptedException {
            System.out.println(new TestClass().getNumber());
            while (true){
                Thread.sleep(1000);
                System.out.println(new TestClass().getNumber());
            }
        }
    }
    View Code

    添加加载jar包附着在虚拟机上的程序

    package com.fh;
    
    import com.sun.tools.attach.*;
    
    import java.io.IOException;
    import java.util.List;
    
    public class AttachMain {
    
        public static void main(String[] args) throws IOException, AttachNotSupportedException, AgentLoadException, AgentInitializationException, InterruptedException {
            List<VirtualMachineDescriptor> listBefore = VirtualMachine.list();
            //agentmain()方法所在jar包
            String jar = "E:\idea_workspace\workspace_skywalking\TestAgent\target\TestAgent-1.0-SNAPSHOT.jar";
            VirtualMachine virtualMachine = null;
    
            List<VirtualMachineDescriptor> listAfter = null;
            while (true){
                listAfter = VirtualMachine.list();
                for (VirtualMachineDescriptor descriptor : listAfter) {
                    if(!listBefore.contains(descriptor)){//发现新的JVM
                        System.out.println("attach JVM");
                        virtualMachine = VirtualMachine.attach(descriptor);//attach到新JVM
                        virtualMachine.loadAgent(jar);//加载agentmain所在的jar包
                        virtualMachine.detach();
                        return;
                    }
                }
                Thread.sleep(1000);
            }
    
        }
    }
    View Code

    jar包内容

    package com.fh;
    
    import java.lang.instrument.Instrumentation;
    import java.lang.instrument.UnmodifiableClassException;
    
    /**
     * attach api
     */
    public class TestAgent {
    
        public static void agentmain(String agentArgs,
                                     Instrumentation inst) throws UnmodifiableClassException {
    //     是对一个Java虚拟机的抽象,在Attach工具程序监控目标虚拟机的时候会用到此类
    //     提供类JVM枚举,Attach,Detach等基本操作
    //     VirtualMachine
    //     描述虚拟机的容器类
    //     VirtualMachineDescriptor
            inst.addTransformer(new TestAgent1.Transformer(),true);
            inst.retransformClasses(TestClass.class);
            System.out.println("premain done");
        }
    
        public static void agentmain(String agentArgs){
    
        }
    
    }
    View Code

    pom文件中的Premain-class替换成Agent-class,还需要添加Can-Retransform-Classes标签为true

    之后进行进行启动,可以先启动attach程序,然后启动main方法,attachMain会检测运行中的虚拟机,然后将jar包附着着新的虚拟机上

      

  • 相关阅读:
    实验吧因缺思汀的绕过注入解析
    python模块中requests参数stream
    土司论坛nc反弹神器使用方法
    msf web脚本反弹shell
    python 多线程
    metasploit后门维持技术
    ew做socks5代理
    双内网渗透代理之reGeorg+Proxifier
    SVN源码泄露漏洞
    Java反射的实例
  • 原文地址:https://www.cnblogs.com/nihaofenghao/p/14801489.html
Copyright © 2011-2022 走看看