在jdk 1.5之后引入的java.lang.instrument包提供了检测java程序的api,用于监控、收集性能信息、诊断问题等。通过 java.lang.instrument 实现的工具我们称之为 Java Agent ,Java Agent 能够在不影响正常编译的情况下来修改字节码,即动态修改已加载或者未加载的类,包括类的属性、方法等。
Java agent 一般来说又两种使用方法:
- premain方法:
这种方法会在jvm启动前加载,需要-javaagent参数,这两种情况我们基本都无法控制,因为jvm一般来说已经启动- agentmain方法:
相对于上面的只能在启动前开启,agentmain可以在jvm已经启动时候插入,可以想象我们如果能控制这一步骤就能改动运行的java程序,如果我们直接它的运行代码中插入恶意代码一般的监控软件很难检测到也很难排查
接下来我们分析agentmain方法的一种实现:https://github.com/rebeyond/memShell
整个agentmain方法的利用链如下:
(1) 想办法获得jvm的pid(就是java进程)
(2) 通过VirtualMachine virtualMachine = VirtualMachine.attach(pid) 获得一个attach到jvm上的实例
(3) 之后通过virtualMachine.loadAgent(jarName) 让jvm执行一个我们指定的jar包(当我们将代码注入成功之后最后在结尾使用virtualMachine.detach 将痕迹清理)
(4) 之后就是我们的agent的功能了,这地方一般就可以自由发挥了。一般来说需要使用Java的instrumentation来注册修改方法,然后调用javassist去修改字节码,修改字节码的技术有很多,一般来说使用javassist这个比较简单一些
(5) 在agentment中调用Instrumentation.getAllLoadedClasses()获得全部的已加载的类,然后遍历所有类找到我们想要修改的类,使用Instrumentation. addTransformer(new TransformerDemo(), true);添加我们编写的transformer
(6) 之后使用Instrumentation.retransformClasses(我们想要修改的class)来触发我们的transformer
(7) 最后在transfromer中使用javassist等方法去修改字节码,至于要添加什么代码就看自己的想法了,注入完成之后可以直接删除所有的文件
检测步骤与注入步骤基本相同:
1.Attach检测Agent到JVM进程
2.获取JVM中已经加载的Class列表
3.根据指纹特征将可疑的Class反编译为Java源码
4.根据源码检测出Webshell
原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/270730.html