利用小众语言进行免杀一直是一个屡试不爽的方法,从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大概快200m,在没有安装jre环境的普通用户来说,显然带着整个jre和后门一起打包是不可能的了,但我们可以从jre中提取加载后门时需要用到的class文件,并集合到一起,这样就能大大压缩jre的体积。
jre最主要的两个目录是bin跟lib,bin下主要是各类dll跟可执行文件,lib下是java的依赖库。精简jre就可以从这两方面入手。
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文件操作的支持。
只找到了jdk/bin目录的介绍,jre有些没有,将就着看一下吧
https://www.cnblogs.com/chongcheng/p/14138996.html
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大小了。
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把jre跟jar打包成一个单独的exe试试
这里install.exe是偷懒用msfvenom -p windows/exec生成的
可以执行,但是会有UAC提示框,不太行
VT上查杀过半了,看来不能偷懒
后来又用C++写了一个exe去调用,还是杀的比较多
不过话说我为什么要打包到一起呢,沙箱里面一跑就出来了,这就失去了jar的优势:jar除了可以分离真正的Payload以外,本身就可以加各种混淆,各种商业软件也都是带混淆的,杀软也不能直接杀。
转换思路,我可以仅打包一个人畜无害的jre到exe,然后再jre.exe -jar xxx去调用。
打包方法同上,打包出来后8.2m,测试一下能不能用
执行成功
xxx不杀
VT测一下还有6个引擎检出。。。这tm就是个java.exe啊,还Static ML,真就瞎告呗。这样说我也能搞一个杀毒引擎,看到PE头就杀,名字就叫Deep Static ML。
本文仅用于安全研究,请勿用于非法用途。如果有什么问题欢迎交流。