长亭百川云 - 文章详情

精简JRE,打造无依赖的Java-ShellCode-Loader

网络安全回收站

38

2024-07-13

前言

       利用小众语言进行免杀一直是一个屡试不爽的方法,从python到go再到现在的nim免杀,用的人越多杀软的检测也就越来越严格。现在自己写的go程序基本只要涉及到网络通信360就干掉了。那么还有没有什么新的姿势呢?

之前介绍过在As-Exploits中用到的基于JNA实现的ShellCodeLoader(https://t.zsxq.com/022FQrFAu),这个Loader在精简后不到1m,配合JarLoader模块在插件里面可以直接内存加载,文件不落地。后来发现落地了问题也不大,到现在VT还是0/57。所以后来抽出来作为一个单独的项目:https://github.com/yzddmr6/Java-Shellcode-Loader

实战里面有Java的WebShell用起来非常方便,一键免杀xxx。但是缺点是如果用来钓鱼,或者碰上jdk环境过高过低都用不了,还是有局限性。所以就研究了一下怎么跟jre一起打包成一个单独的可执行文件exe。

    目前成果如下:用自解压精简后带jre环境的exe只有6.5m,用Enigma Virtual Box压缩模式8.5m,差不多跟python打包后差不多大小,VT 6/67,基本可以实现我们的需求。

jre目录结构

原版一个jre大概快200m,在没有安装jre环境的普通用户来说,显然带着整个jre和后门一起打包是不可能的了,但我们可以从jre中提取加载后门时需要用到的class文件,并集合到一起,这样就能大大压缩jre的体积。

jre最主要的两个目录是bin跟lib,bin下主要是各类dll跟可执行文件,lib下是java的依赖库。精简jre就可以从这两方面入手。

lib目录

access-bridge-64.jar

    Java Accessibility API是Java Accessibility Utilities的一部分,它是一组实用程序类,可帮助辅助技术提供对实现Java Accessibility API的GUI工具包的访问。

charsets.jar

    Java 字符集,包含 Java 所有支持字符的字符集

cldrdata.jar

    Unicode CLDR为软件提供了支持世界语言的关键构建块,提供了最大和最广泛的语言环境数据库。这些数据被广泛的公司用于其软件国际化和本地化,使软件适应不同语言的惯例以用于此类常见软件任务.

deploy.jar

    Java安装目录的常见部分 - 该文件运行某些产品的安装。正确设置Java路径后,用户可以执行此文件(只需双击它或按文件上的Enter键),要部署的应用程序将运行其安装程序。例如。诺基亚OVI套件通常使用这种部署形式。作为彼此的JAVA包,如果您将其重命名为ZIP并打开内容,则可以检查包中的类。

dnsns.jar

    即DNS naming service ,提供DNS地址服务的包,里面只有2个方法 getHostByAddr和 lookupAllHostAddr

jaccess.jar

    定义Assistive Technologies.AWT(Abstract Window Toolkit)使用的JDK实用程序类

javaws.jar

    JNLP(Java Network Launching Protocol )是java提供的一种可以通过浏览器直接执行java应用程序的途径。

jce.jar

    java类库是java发布之初就确定了的基础库, 而javax类库则是在上面增加的一层东西,就是为了保持版本兼容要保存原来的,但有些东西有了更好的解决方案, 所以,就加上些,典型的就是awt(Abstract Windowing ToolKit) 和swing。) 这个包都是加密相关的。

jfr.jar

    和 jdk\bin\jmc.exe有关系。Java Mission Control 包括 JMX 控制台和 Java 飞行记录器。Java 飞行记录器 (JFR) 是一个用于收集有关正在运行的 Java 应用程序的诊断数据和概要分析数据的工具。它集成到 Java 虚拟机 (JVM) 中, 几乎不会带来性能开销,因此甚至可以在高负载生产环境中使用。使用默认设置时,内部测试和客户反馈表明性能影响低于 1%。对于一些应用程序,这一数字会大幅降低。但是,对于短时间运行的应用程序 (不是在生产环境中运行的应用程序类型), 相对的启动和预热时间可能会较长,这对性能的影响可能会超过 1%。JFR 收集有关 JVM 及其上运行的 Java 应用程序的数据。

jfxrt.jar

    JDK有个 rt.jar ,是存储JAVA语言核心类的的。这个jfxrt.jar就相当于JavaFX的rt.jar. JavaFX是一组图形和媒体包,使开发人员能够设计,创建,测试,调试和部署在不同平台上一致运行的富客户端应用程序。在jdk最新的发版当中,javafx的包已经被移除了。

jfxswt.jar

    也是和JavaFx相关,为JavaFx和Swing提供一些兼容性操作。

jsse.jar

    SSL连接,验证的包,

localedata.jar

    日期显示国际化的包,里面包含各地区的日期文字。

management-agent.jar

    里面只有一个文本文件。

nashorn.jar

包括

1.动态链接.包含用于链接调用的动态调用站点的接口和类。dynalink与java.lang.invoke包密切相关,并且依赖于该包。虽然java.lang.invoke为invoke dynamic调用站点的动态链接提供了一个低级别的API,但它不提供一种方法来表示对象的更高级别操作,也不提供实现这些操作的方法。如果一种语言是静态类型的,并且它的类型系统与JVM的类型系统匹配,那么它可以使用通常的调用、字段访问等指令(例如invokevirtual、getfield)来实现这一点。但是,如果语言是动态的(因此,某些表达式的类型直到在运行时进行计算时才知道),或者其对象模型或类型系统与JVM的对象模型或类型系统不匹配, 那么它应该使用invokedynamic调用站点,并让dynalink管理它们。

2.Javascript引擎 从 JDK 8 开始,Nashorn取代 Rhino 成为 Java 的嵌入式 JavaScript 引擎。Nashorn 完全支持ECMAScript 5.1 规范以及一些扩展。该特性允许开发人员将 JavaScript 代码嵌入到 Java 中,甚至从嵌入的 JavaScript 中调用 Java。此外, 它还提供了使用jrunscript从命令行运行 JavaScript 的能力。

plugin.jar

    功能很庞大的一个包。

resources.jar

提示信息显示国际化的包,里面各地区的文字,图片等。

rt.jar

java核心源代码包

sunec.jar ,sunjce_provider.jar,sunmscapi.jar,sunpkcs11.jar

都是加密相关的包。

zipfs.jar

java 对zip文件操作的支持。

bin目录

只找到了jdk/bin目录的介绍,jre有些没有,将就着看一下吧

https://www.cnblogs.com/chongcheng/p/14138996.html

精简rt.jar

rt.jar是java核心源代码包,原版有61m,我们主要的精简也就是从这里入手。原理是jar包运行是加上-XX:+TraceClassLoading参数可以打印出所有被加载过的class文件,然后在对这部分class进行二次打包,生成我们的精简rt.jar。这里借MG师傅的图一用:

代码是参考MG1937师傅的这篇文章:

https://www.cnblogs.com/aldys4/p/14879607.html,修改后代码如下:

`import java.io.BufferedReader;``import java.io.IOException;``import java.io.InputStreamReader;``import java.util.ArrayList;``import java.util.List;``   ``public class Main {`    `public static void main(String[] arg) throws IOException {`        `Runtime runtime = Runtime.getRuntime();`        `String[] command = {"java", "-jar", "-XX:+TraceClassLoading", "D:\\ShellcodeLoader_jar\\ShellcodeLoader.jar", "aaaa"}; //这里要加上参数`        `Process process = runtime.exec(command);`        `BufferedReader bReader = new BufferedReader(new InputStreamReader(process.getInputStream()));`        `StringBuffer sBuffer = new StringBuffer();`        `List<String> list = new ArrayList<String>();`        `int i = 0;`        `String lineString;`        `while ((lineString = bReader.readLine()) != null) {`            `String core = getCore(lineString);`            `if (core != "") {`                `sBuffer.append("\n" + core);`                `list.add(getCore(lineString.replace(".", "/")));`            `}``   `            `i++;`        `}`        `bReader.close();`        `System.out.println(sBuffer.toString());`        `list.add(0, "D:\\rt.jar");`        `list.add(0, "xvf");`        `list.add(0, "jar");`        `String[] jar = list.toArray(new String[list.size()]);`        `process = runtime.exec(jar);`        `getOutput(process);`        `System.out.println("Load class:" + i);`        `System.out.println("jar xvf done!");`        `String[] cmdJarPackage = cmd("jar cvf rt.jar com java javax META-INF org sun sunw");`        `runtime.exec(cmdJarPackage);`        `System.out.println("All done!");`    `}``   `    `public static String getCore(String line) {`        `String result = null;`        `if (line.startsWith("[Loaded")) {`            `if (line.indexOf(".jna.") > 0 || line.indexOf("asexploits") > 0) {`                `return "";//过滤jna包跟我们自己的包名``   `            `} else {`                `result = line.split(" ")[1];`            `}`            `return result;`        `} else {`            `return "";`        `}`    `}``   `    `public static String[] cmd(String cmd) {`        `return cmd.split(" ");``   `    `}``   `    `public static void getOutput(Process process) throws IOException {`        `BufferedReader bReader = new BufferedReader(new InputStreamReader(process.getInputStream()));`        `while (bReader.readLine() != null) {`            `System.out.println("\n" + bReader.readLine());`        `}`    `}``}`

这里有一个坑点,就是第一次获取加载的class信息的时候没有加上ShellCode参数,也就会导致有些运行期间才会用到的类没有加载。

解决办法就是加上要执行的ShellCode,把执行过程中所有加载的类都暴露出来,然后再打包。这里的aaaa随便写,只要能走到注入的过程就可以。可以看到现在的rt.jar已经不报错了。

精简之前lib目录是104m,现在已经压缩到44m了。

我们压缩后的rt.jar也只有1.8m大小

这样肯定还是不够的,剩下目录里也有很多冗余的文件,这部分基本直接删除就可以了,不需要二次打包。另外charsets.jar还是有优化空间的,可以用类似rt.jar的方法进行精简,这里就懒得处理了。

    最后lib目录优化到只有5m大小了。

精简dll

bin目录同样很大,也是我们要优化的对象。

这里采取的办法是用process explorer查看程序运行时加载了哪些dll或者exe,仅保留这部分,其他的都可以删掉。

注意这里最好加一个System.in.read()保持控制台不退出,不然就会一闪而过,process explorer就看不到了。

还有一个简单的办法,在程序跑起来的同时,删除bin目录下所有文件,如果提示被占用了那么就是被打开了,把这部分跳过即可。

精简过后的bin目录大概10m,主要是jvm.dll比较大。他是jvm的核心链接库,不能轻易改动。

自解压捆绑执行

环境整好了,接下来就是让他跑起来。自解压是钓鱼老套路了,搞个vbs来运行我们的jar。这里的ShellcodeLoader.jar我硬编码了一个弹计算器的ShellCode先测试一下。

`Set ws = CreateObject("Wscript.Shell")``ws.run "cmd /c .\jre\bin\java.exe -jar .\ShellcodeLoader.jar"`

执行成功

压缩出来6.5m

VT 6/62还好,但是360杀了,估计自解压这种已经进特征库了。

EnigmaVirtualBox打包全部文件

自解压估计已经被重点监控了,用EnigmaVirtualBox把jre跟jar打包成一个单独的exe试试

这里install.exe是偷懒用msfvenom -p windows/exec生成的

可以执行,但是会有UAC提示框,不太行

VT上查杀过半了,看来不能偷懒

后来又用C++写了一个exe去调用,还是杀的比较多

EnigmaVirtualBox打包jre

不过话说我为什么要打包到一起呢,沙箱里面一跑就出来了,这就失去了jar的优势:jar除了可以分离真正的Payload以外,本身就可以加各种混淆,各种商业软件也都是带混淆的,杀软也不能直接杀。

转换思路,我可以仅打包一个人畜无害的jre到exe,然后再jre.exe -jar xxx去调用。

打包方法同上,打包出来后8.2m,测试一下能不能用

执行成功

xxx不杀

VT测一下还有6个引擎检出。。。这tm就是个java.exe啊,还Static ML,真就瞎告呗。这样说我也能搞一个杀毒引擎,看到PE头就杀,名字就叫Deep Static ML。

最后

    本文仅用于安全研究,请勿用于非法用途。如果有什么问题欢迎交流。

相关推荐
关注或联系我们
添加百川云公众号,移动管理云安全产品
咨询热线:
4000-327-707
百川公众号
百川公众号
百川云客服
百川云客服

Copyright ©2024 北京长亭科技有限公司
icon
京ICP备 2024055124号-2