文件目录
  • 0 从零开始的Java RASP完成(一)
  • 1 javaagent
    • 1.1 Main方式 运行前
      • 定义详细介绍:
      • 怎么使用
      • 建立agent
      • 建立main
    • 1.2 JVM运行后
      • attach体制
      • 运行一个长期运作的jvm
      • 装包一个agentmain代理商jar
      • 应用attach
  • 参照

0 从零开始的Java RASP完成(一)

大学本科毕业设计做了Python的RASP以后,对此项技术性很有兴趣爱好,那时候OpenRASP逐渐发生,而且Java的完成十分贴近真真正正的运作时防御力的定义。一直没有时间和充足的驱动力学习培训Java,近期一口气学了许多Java有关的物品,提前准备从反序列化和RASP2个方位再次深层次学一下Java。这里手记关键也是纪录全部学习过程,总体目标是模仿OpenRASP的java完成,进行一个Java的RASP。

1 javaagent

1.1 Main方式 运行前

定义详细介绍:

javaagent是java指令给予的一个主要参数,这一主要参数能够特定一个jar包,在真真正正的程序流程沒有运作以前先运作特定的jar包。而且对jar包有两个规定:

  • jar包的MANIFEST.MF文档务必特定Premain-Class
  • Premain-Class特定的类务必完成premain()方式 。

这一premain方式 会在javacmd特定的main函数以前运作。

在java指令主要参数种,还能够见到其他主要参数,比如

-agentlib:<libname>[=<选择项>]
                  载入该设备代理商库 <libname>, 比如 -agentlib:hprof
                  另客户程序 -agentlib:jdwp=help 和 -agentlib:hprof=help
-agentpath:<pathname>[=<选择项>]
                  按详细路径名载入该设备代理商库
-javaagent:<jarpath>[=<选择项>]
                  载入 Java 计算机语言代理商, 客户程序 java.lang.instrument

javaagent能够特定许多个,jvm会先后实行不一样的jar。前边提及的premain方式 有二种界定方法

public static void premain(String agentArgs, Instrumentation inst)

public static void premain(String agentArgs)

依据sun.instrument.InstrumentationImpl 的源码,能够了解,会优先选择启用第一种书写。这类方式 能够在JDK1.5及以后的版本号应用

怎么使用

应用javaagent必须好多个流程:

  • 界定一个MANIFEST.MF文档,务必包括Premain-Class选择项,也必须添加Can-Redefine-Classes和Can-Retransform-Classes选择项,后边2个选择项看名称就了解含意
  • 建立Premain-Class特定的类,类中包括premain方式 ,该方式 能够进一步载入RASP完成基本原理
  • 将MANIFEST.MF和写好的各种各样类装包成jar
  • 运行java时,加上-javaagent:xx.jar,就可以让java先全自动实行写好的premain方式

在premain方式 实行时,获得的Instrumentation目标还会继续载入绝大多数类,包含后边main方式 实行时必须载入的各种各样类,可是抓不上系统软件类。换句话说,在这个部位在main方式 实行前,就可以阻拦或是调用类,融合ASM、javassist、cglib方法就可以完成对类的改变或是插桩。

建立agent

如今来完成一下,文件目录构造以下

-java-agent
----src
----|----main
----|----------java
----|--------------com
----|-------------------bitterz
----|----------------------PreMain
----|pom.xml

pom.xml应用idea建立maven新项目内置的pom.xml就可以,随后添加以下配备

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <configuration>
                <archive>
                    <manifestEntries>
                        <Premain-Class>com.bitterz.PreMain</Premain-Class>
                        <Can-Redefine-Classes>true</Can-Redefine-Classes>
                        <Can-Retransform-Classes>true</Can-Retransform-Classes>
                    </manifestEntries>
                </archive>
            </configuration>
        </plugin>
    </plugins>
</build>

改动里边的premain就可以,那样配备以后,立即应用idea的maven->package就可以装包成一个能够应用的agent.jar。

com.bitterz.PreMain以下:

package com.bitterz;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;

public class PreMain {
        public static void premain(String agentArgs, Instrumentation inst){
            System.out.println("agentArgs:"   agentArgs);
            inst.addTransformer(new DefineTransformer(), true);
        }

        static class DefineTransformer implements ClassFileTransformer{
            @Override
            public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
                System.out.println("premain load Class: "   className);  // 留意这儿的輸出
                return classfileBuffer;
            }
        }
}

建立main

随后再建立一个要实行的main

package com.bitterz;

public class Main {
    public static void main(String[] args) {
        System.out.println("Main.main() in test project");
    }
}

一样改动pom.xml配备,只必须再<manifestEntries>标识下加上一个<Main-Class>就可以用idea的maven装包成一个jar,而且特定了main类。

2个新项目用maven装包后,在cmd实行一下

能够见到premain先輸出了载入的各种各样类,包含com.bitterz.Main,随后才算是真真正正的main实行,最终完毕时,premain还载入了一些完毕时必须的类。到此,在运行main方式 前,完成对事后类的载入或进一步改动实际操作,早已拥有原型

1.2 JVM运行后

前边的方式 必须在main函数运行前,实行agent,但有一些情况下,jvm早已运行了,并且服务项目不可以随便中止,但这个时候或是想对jvm中的类做一些改动应当怎么办呢?

attach体制

这就需要引进attch体制了,jdk1.6以后在Instrumentation中加上了一种agentmain的代理商方式 ,能够在main函数实行以后再运行。和premain函数一样,开发人员能够撰写一个包括agentmain函数的Java类,它也是有二种书写:

public static void agentmain (String agentArgs, Instrumentation inst)

public static void agentmain (String agentArgs)

一样的,含有Instrumentation的方式 会被优先选择启用,开发人员务必再MANIFEST.MF文档中设定Agent-Class来特定包括agentmain函数的类。

这类attach体制的实际完成在com.sun.tools.attach中,有以下2个类:

  • VirtualMachine 字面上实际意义表明一个Java vm虚拟机,也就是程序流程必须监管的总体目标vm虚拟机,给予了获得系统信息(例如获得运行内存dump、进程dump,类信息内容统计分析(例如已载入的类及其案例数量等), loadAgent,Attach 和 Detach (Attach 姿势的反过来个人行为,从 JVM 上边消除一个代理商)等方式 ,能够完成的作用可以说十分之强劲 。此类容许大家根据给attach方式 传到一个jvm的pid(过程id),远程桌面连接到jvm上

    代理商类引入实际操作仅仅它诸多作用中的一个,根据loadAgent方式 向jvm申请注册一个代理商程序流程agent,在该agent的代理商程序流程中会获得一个Instrumentation案例,该案例能够 在class载入前更改class的字节码,还可以在class载入后重新加载。在启用Instrumentation案例的方式 时,这种方式 会应用ClassFileTransformer插口中给予的方式 开展解决。

  • VirtualMachineDescriptor 则是一个叙述vm虚拟机的容器类,相互配合 VirtualMachine 类进行各种各样作用

实际完成全过程:根据VirtualMachine类的attach(pid)方式 ,便能够attach到一个运作中的java过程上,以后便能够根据loadAgent(agentJarPath)来将agent的jar包引入到相匹配的过程,随后相匹配的过程会启用agentmain方式 。

从jdk网站根目录的lib/tools.jar源代码一路追踪了一下VirtualMachine.attach方式 ,发觉传到一个pid以后,在Windows下能根据WindowsVirtualMachine这一类的构造方法,启用native方式 ,完成对jvm过程的attach

运行一个长期运作的jvm

最底层方式 还得靠c/c 来完成(搞笑),掌握这一体制以后,返回前边的agentmain的完成步骤。最先运行一个一直运作的jvm

package com.bitterz;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("Main.main() in test project start!!");
        Thread.sleep(300000000);
        System.out.println("Main.main() in test project end!!");
    }
}

装包一个agentmain代理商jar

运行以后,把再写一个agentmain,而且还需要写好MANIFEST.MF文档配备,编码和pom.xml以下:

package com.bitterz;

import java.lang.instrument.Instrumentation;

public class AgentMain {
    public static void agentmain(String agentArgs, Instrumentation instrumentation) {
        System.out.println("agentmain start!");
        System.out.println(instrumentation.toString());
    }
}
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <configuration>
                <archive>
                    <manifestEntries>
                        <Agent-Class>com.bitterz.AgentMain</Agent-Class>
                        <Can-Redefine-Classes>true</Can-Redefine-Classes>
                        <Can-Retransform-Classes>true</Can-Retransform-Classes>
                    </manifestEntries>
                </archive>
            </configuration>
        </plugin>
    </plugins>
</build>

应用maven package装包成一个jar文件就可以

应用attach

再开运行另一个java程序流程,应用过程号attach到前边一直运作的jvm,并应用loadAgent给这一jvm加上代理商jar:

package com.bitterz.attach;

import com.sun.tools.attach.AgentInitializationException;
import com.sun.tools.attach.AgentLoadException;
import com.sun.tools.attach.AttachNotSupportedException;
import com.sun.tools.attach.VirtualMachine;

import java.io.IOException;

public class AttachTest {
    public static void main(String[] args) throws IOException, AttachNotSupportedException, AgentLoadException, AgentInitializationException {
        VirtualMachine attach = VirtualMachine.attach("12244");  // cmd寻找这一jvm的过程号
        attach.loadAgent("C:\\Users\\helloworld\\Desktop\\java learn\\java-attach\\target\\java-attach-1.0-SNAPSHOT.jar");
        attach.detach();
    }
}

运作这一java文件,会见到前边一直sleep运作的jvm会輸出agentmain里边给出的輸出!

这儿也就表明,根据attach体制,我们可以对特定运作中的jvm加上agent,而在premain方式 中获得到Instrumentation目标,根据对Instrumentation目标加上transformer类,能够完成类变换(Class Transform),也就是在transform涵数中融合改动字节码的方式 (ASM、Javassist、cglib等)能够进一步完成RASP!

事后的文章内容可能写一写怎样完成这种对特定类方法的Hook,及其怎样运作时对最底层涵数的主要参数开展过虑。

参照

https://www.cnblogs.com/rickiyang/p/11368932.html

https://www.cnblogs.com/kendoziyu/p/maven-auto-build-javaagent-jar.html

Java最底层安全防护 - OpenRASP关键源代码浅谈


创作者:bitterz
详细地址:https://www.cnblogs.com/bitterz/
文中著作权归创作者和博客园全部,热烈欢迎转截,转截请标出来源。
假如您感觉这篇博闻对您有一定的获得,请点一下右下方的 [强烈推荐],感谢!

评论(0条)

刀客源码 游客评论