You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

二进制/进程内加密跳转执行:如何无文件落地运行加密嵌入的应用?

实现核心思路

你之前的方案触发段错误有两个核心原因:

  • 堆内存默认开启NX/DEP保护,无执行权限,直接跳转执行必然触发访问异常
  • 你嵌入的是完整应用二进制而非位置无关的shellcode,缺少重定位、导入表解析、段权限配置等PE/ELF/Mach-O加载的必需步骤,直接跳转无法正常运行

如果你用Tauri的话,bootstrapper是桌面端程序,分Windows、Linux、macOS三个平台处理,不需要落地文件的核心是实现内存加载器,把解密后的二进制直接在用户态完成加载流程后执行。

C/C++ 实现方案

Windows平台(加载PE文件)

核心步骤:

  1. 对解密后的PE字节先校验IMAGE_DOS_SIGNATURE、IMAGE_NT_SIGNATURE魔数合法性
  2. 调用VirtualAlloc申请内存,参数指定MEM_COMMIT | MEM_RESERVE,权限先设为PAGE_READWRITE
  3. 把PE头、各个节按VirtualAddress偏移拷贝到申请的内存空间
  4. 处理重定位表:如果实际加载基址和PE可选头的ImageBase不一致,遍历重定位表修正所有地址偏移
  5. 解析导入表:遍历导入的dll,调用LoadLibrary加载,再调用GetProcAddress获取函数地址填充到IAT表
  6. 调用VirtualProtect修改代码段内存权限为PAGE_EXECUTE_READ
  7. 跳转到PE的入口点执行,示例代码如下:
typedef int (*PEEntryPoint)();
PEEntryPoint entry = (PEEntryPoint)((char*)alloc_base + nt_header->OptionalHeader.AddressOfEntryPoint);
int ret = entry();

Linux/macOS平台(加载ELF/Mach-O)

逻辑和PE加载类似,Linux下需要解析ELF的程序头,处理动态段、重定位、GOT表,调用mmap分配内存,设置对应段的PROT_READ/PROT_WRITE/PROT_EXEC权限,最后跳转到ELF的e_entry地址执行。

Rust 实现方案

Rust下可以直接调用系统API完成上述流程,也可以用成熟的第三方库减少重复开发:

  • Windows下可以用PE解析库处理PE结构,调用winapi的VirtualAlloc、VirtualProtect等API完成加载
  • Linux下可以用二进制解析库处理ELF结构,调用libc的mmap、mprotect等API

Windows PE加载最小示例

use std::ptr;
use winapi::um::memoryapi::{VirtualAlloc, VirtualProtect};
use winapi::um::winnt::{MEM_COMMIT, MEM_RESERVE, PAGE_EXECUTE_READ, PAGE_READWRITE};
use pelite::PeFile;

unsafe fn run_pe_in_memory(pe_data: &[u8]) -> i32 {
    let pe = PeFile::from_bytes(pe_data).unwrap();
    let image_base = pe.optional_header().ImageBase;
    // 申请内存空间
    let alloc_base = VirtualAlloc(
        ptr::null_mut(),
        pe.optional_header().SizeOfImage as usize,
        MEM_COMMIT | MEM_RESERVE,
        PAGE_READWRITE,
    );
    // 拷贝PE头和各节数据
    ptr::copy_nonoverlapping(pe_data.as_ptr(), alloc_base as *mut u8, pe.optional_header().SizeOfHeaders as usize);
    for section in pe.section_headers() {
        let va = section.VirtualAddress as usize;
        let size = section.SizeOfRawData as usize;
        ptr::copy_nonoverlapping(
            pe_data.as_ptr().add(section.PointerToRawData as usize),
            (alloc_base as *mut u8).add(va),
            size,
        );
    }
    // 此处省略重定位、导入表处理逻辑
    // 修改内存为可执行权限
    let mut old_protect = 0;
    VirtualProtect(alloc_base, pe.optional_header().SizeOfImage as usize, PAGE_EXECUTE_READ, &mut old_protect);
    // 跳转至入口点执行
    let entry: extern "system" fn() -> i32 = std::mem::transmute((alloc_base as u64 + pe.optional_header().AddressOfEntryPoint as u64) as *mut ());
    entry()
}

Tauri适配注意事项

  • 因为Tauri的bootstrapper本身运行在用户态,你加载的目标应用如果也是GUI程序,不需要额外创建进程,直接在当前进程执行即可
  • 如果你需要隔离bootstrapper和目标应用的运行环境,也可以用进程空心化技术:创建挂起的进程,把解密后的二进制注入到挂起进程的地址空间,修改上下文后恢复进程执行,完全不需要落地文件

逆向强化补充建议

适配远程考试应用的防破解需求,你可以做额外加固:

  • 解密逻辑可以做代码虚拟化、多分支混淆,避免被直接dump内存拿到解密后的二进制
  • 可以分段解密,执行到对应代码段的时候才解密对应部分,减少完整二进制出现在内存中的时间
  • 加入内存校验,检测是否被调试器dump内存,发现异常直接退出

内容的提问来源于stack exchange,提问作者t348575

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 12:06:03