15

从两款开源工具学习 Java_Instrumentation 技术

 4 years ago
source link: https://paper.seebug.org/1071/?
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

作者:Litch1@Dubhe
本文为作者投稿,Seebug Paper 期待你的分享,凡经采用即有礼品相送!
投稿邮箱:[email protected]

最近看了一下JavaProbe(0Kee-Team)OpenRasp(Baidu)的源码,两者都使用了instrumentation agent技术,但是由于场景不同,所以使用的差异也比较大,这篇笔记对于java instrumentation两种加载方式以及进行学习。由于个人水平有限,写的地方肯定有很多错误,还请各位师傅指出。

Instrumentation

对于instrumentation agent来说有两种代理方式,一种是在类加载之前进行代理,可以进行字节码的修改即所谓的agent on load。另一种是在运行时动态进行加载,这种方法对于字节码的修改有较大的限制,但是利用运行时动态加载可以获得JVM的一些运行时信息,这种方式为agent on attach 。

OpenRasp

关于RASP网上有不少分析的文章,这里就不多赘述了。

其基本的检测思路:Hook住程序的一些敏感类或敏感方法,通过检查传入的参数和上下文信息来判断请求是否恶意。

想要Hook住程序的一些敏感类或敏感方法(通常都是一些JDK中的类或方法),添加我们的检查方法,就需要动态的修改类定义时的字节码。OpenRasp采用Java Instrumentation来实现。

OpenRasp的入口在agent的premain方法,premain方法会在main方法运行之前先运行。大概梳理了一下与instrumentation有关的调用的流程

1572839374000-1vtugy.png-w331s

关键函数分析:

com.baidu.openrasp.Agent#premain

public static void premain(String agentArg, Instrumentation inst) {
        init(START_MODE_NORMAL, START_ACTION_INSTALL, inst);
}

在agent的pom里面定义好了MANIFEST.MF文件的premain-class选项

<Premain-Class>com.baidu.openrasp.Agent</Premain-Class>

为目标程序添加我们的agent需要在目标程序启动的时候添加-javaagent参数

在JVM初始化完成之后会创建InstrumentationImpl对象,监听ClassFileLoadHook事件,接着会去调用javaagent里MANIFEST.MF里指定的Premain-Class类的premain方法

premain第二个参数中的Instrumentation是我们字节码转换的工具,因为监听了ClassFileLoadHook事件,一旦有类加载的事件发生,便会触发Instrumentation去调用其已经注册的Transformer的transform方法去进行字节码的更改。

在OpenRasp中,为Instrumentation注册了com.baidu.openrasp.transformer.CustomClassTransformer

public CustomClassTransformer(Instrumentation inst) {
        this.inst = inst;
        inst.addTransformer(this, true);
        addAnnotationHook();
    }

来看一下CustomClassTransform的transform方法

com.baidu.openrasp.transformer.CustomClassTransformer#transform

1572839376000-2gwhyu.png-w331s

我们随便挑一个注册的Hook来分析看看,这里具体的如何进行转化transform主要是由每一个继承了AbstractClassHook这个抽象类的hookMethod方法来决定的

com.baidu.openrasp.hook.system.ProcessBuilderHook

这个类主要是用来检测采用ProcessBuilder来执行系统命令的恶意请求,在最后调用ProcessBuilder.start()时,恶意系统命令会传递到ProcessImpl或者UNIXProcess的构造函数中

1572839376000-3igjvh.png-w331s

所以Match的class是java.lang.processImpljava.lang.UNIXProcess

com.baidu.openrasp.hook.system.ProcessBuilderHook#hookMethod

1572839377000-4crxoz.png-w331s

这里将ProcessBuilderHook的checkCommand方法插入到构造函数之前,这样就可以在构造时进行检查传入的command。

getInvokeStaticSrc 可以用于获取执行指定类的指定方法的源代码字符串,然后通过insertBefore来插入到目标class的\<init>方法中。

insertBefore方法的核心是javassist.CtBehavior#insertBefore(java.lang.String),所以最后就是利用javassist提供的一些封装方法来操作字节码进行目标方法的插入。

注:getInvokeStaticSrc参数中paramString之所以是1,2这种形式,是因为源代码在传入javassit的insertBefore方法时,会将1,2这种形式解析为目标方法的第一个参数,第二个参数,以此类推

OpenRasp使用agent在jvm初始化后进入premain方法,将自定义的ClassTransformer注册到instrumentation中,在有类加载时会触发其的transform方法,其根据匹配的class去调用具体hook的transform方法,在里面使用了javassit来操作字节码来改变被hook的class类定义时的字节码。

JavaProbe

JavaProbe使用agentmain来收集运行中的JVM的信息。

agentmain和premain比较相似,区别是agentmain允许在main函数启动后再运行我们的agentmain方法。并且其不需要在目标程序启动的时候添加-javaagent,目标程序独立运行,没有侵入性,更加灵活,但是同时其对于字节码的修改限制比较大。其和premain函数一样需要在MANIFEST.MF中指定参数

Agent-Class: newagent.HookMain

JavaProbe有多用户模式和单用户模式,多用户模式是利用runuser来切换用户,本质也是执行单用户模式,方便分析,我们直接分析JavaProbe的单用户模式。

newagent.NewAgentMain#hookIng的关键部分截取:

1572839377000-5osclk.png-w331s

利用com.sun.tools.attach.VirtualMachine#list来获取该用户正在运行的所有JVM List,对这个List进行遍历,通过虚拟机的id attach到指定的虚拟机上,接着使用loadAgent方法来加载我们的代理agent,这样就可以在指定的虚拟机上运行我们想要运行的附加程序。loadagent方法的第二个参数会作为参数传入agentmain方法,接着便会去执行agentmain方法。

agentmain的逻辑也比较简单,关键主要就是利用java.lang.instrument.Instrumentation#getAllLoadedClasses来获得JVM已经加载的类,以及使用System.getProperty来获得JVM实际运行的一些关键信息

注:使用agentmain也可以获得获取所有已经初始化过的类,或者类的大小等等。

JavaProbe为了无侵入地获得所有JVM的运行时信息,采用instrumentation的agentmain,独立于其他目标JVM,可以动态将代理attach到指定的JVM上去获取有关的信息。

Instrumentation总结

无论是premain或是agentmain,使用instrumentation技术地优点都在于无侵入以及深入性,可以在运行时动态深入到JVM层面去获取信息,或是在字节码层面改变运行时的Java程序,从而进行监控或者保护。而这种无侵入式的防护和监控是安全产品比较理想的形态。

OpenRasp官方文档

Java SE 6 新特性Instrumentation 新功能

JVM 源码分析之 javaagent 原理完全解读

java agent简介


Paper 本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/1071/


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK