无WriteProcessMemory CreateRemoteThread实现shellcode注入 GhostWriting x64实现
字数 1446 2025-08-30 06:50:11

Ghost Writing技术:无OpenProcess/WriteProcessMemory的Shellcode注入(x64实现)

技术概述

Ghost Writing是一种高级进程注入技术,允许在不使用OpenProcessWriteProcessMemoryCreateRemoteThreadDebugActiveProcess等传统API的情况下,向目标进程注入并执行shellcode。该技术最初由2007年的一篇博客提出,本文档将详细介绍其在x64环境下的实现方法。

核心原理

Ghost Writing技术的核心思想是:

  1. 利用MOV [REG1],REG2指令配合SetThreadContext API实现内存写入
  2. 使用EB FE指令(无限循环)作为执行滞留点,防止进程崩溃
  3. 通过修改线程上下文和返回地址控制执行流程

技术实现步骤

1. 寻找合适的指令片段(Gadget)

在x64环境下,我们需要寻找以下类型的指令:

  • MOV [REG1],REG2:用于实现内存写入
  • EB FE:无限循环指令,用于执行滞留

由于x64架构与x86有所不同,实际可用的指令片段较少,且多为易失寄存器。可以通过以下方法寻找:

; 示例gadget
pop rcx
add rsp, 0x28
mov [rax], rcx
ret

2. 构造执行环境

  1. 修改返回地址:将返回地址设置为包含EB FE指令的地址,形成死循环
  2. 平衡堆栈:在gadget中可能需要手动平衡堆栈(如插入popadd rsp指令)

3. 内存写入机制

利用找到的gadget实现内存写入:

// 伪代码示例
CONTEXT context;
GetThreadContext(hThread, &context);
context.Rip = gadget_address;  // 设置RIP为我们的gadget
context.Rax = target_address;  // 目标地址
context.Rcx = data_to_write;   // 要写入的数据
SetThreadContext(hThread, &context);

4. 调用任意函数

通过构造栈帧和修改RIP,可以调用任意函数(如ntdll!NtProtectVirtualMemory):

  1. 构造栈帧

    • 需要为shadow stack预留空间((4+3+1)*sizeof(ULONG64))
    • 包含返回地址、参数和指针内容
  2. 示例调用NtProtectVirtualMemory

    // 构造参数
    ULONG64 params[] = {
        (ULONG64)hProcess,
        (ULONG64)&baseAddress,
        (ULONG64)&size,
        newProtect,
        &oldProtect
    };
    
    // 设置上下文
    context.Rip = NtProtectVirtualMemory_address;
    context.Rsp -= sizeof(params);  // 调整栈指针
    WriteProcessMemory(hProcess, (LPVOID)context.Rsp, params, sizeof(params), NULL);
    

5. 执行Shellcode

  1. 分配内存:可以使用VirtualAllocEx申请内存(虽然使用了API,但可以替换为其他方法)
  2. 写入shellcode:通过上述内存写入机制
  3. 修改执行流程:将RIP指向shellcode地址

6. 触发执行

对于GUI程序,可以通过PostMessage发送消息来触发执行,因为GUI线程是消息驱动的。

高级应用:任意方法调用

可以封装一个通用函数来调用任意API:

template<typename... Args>
ULONG64 CallFunction(HANDLE hThread, ULONG64 functionAddress, Args... args) {
    CONTEXT context;
    GetThreadContext(hThread, &context);
    
    // 构造参数
    ULONG64 params[] = { args... };
    
    // 调整栈指针并写入参数
    context.Rsp -= sizeof(params);
    WriteProcessMemory(hProcess, (LPVOID)context.Rsp, params, sizeof(params), NULL);
    
    // 设置RIP
    context.Rip = functionAddress;
    SetThreadContext(hThread, &context);
    
    // 恢复执行
    ResumeThread(hThread);
    WaitForSingleObject(hThread, INFINITE);
    SuspendThread(hThread);
    
    // 读取返回值
    GetThreadContext(hThread, &context);
    return context.Rax;
}

读取指针返回值

对于通过参数写回数据的函数(如NtAllocateVirtualMemory),需要从栈上读取指针值:

ULONG64 ReadPointerFromStack(HANDLE hProcess, ULONG64 stackAddress, int pointerIndex) {
    ULONG64 buffer[10];
    ReadProcessMemory(hProcess, (LPCVOID)stackAddress, buffer, sizeof(buffer), NULL);
    return buffer[pointerIndex];
}

注意事项

  1. 线程句柄获取:虽然可以避免使用OpenProcess,但仍需要OpenThread获取线程句柄
  2. 替代方案:可以通过遍历线程快照(th32OwnerProcessID)来完全避免打开进程句柄
  3. 稳定性:注入后原进程的GUI可能会卡死,需要根据实际情况处理
  4. 权限问题:需要足够的权限来操作目标线程

技术优势

  1. 隐蔽性高:避免了传统注入技术使用的敏感API
  2. 适用范围广:可用于绕过某些安全产品的检测
  3. 灵活性好:可以扩展为通用的函数调用机制

总结

Ghost Writing技术通过巧妙的指令片段利用和线程上下文操作,实现了不依赖传统API的进程注入。在x64环境下实现时需要注意指令选择、堆栈平衡和参数传递的差异。该技术可以进一步扩展为通用的远程函数调用机制,具有很高的实用价值和研究意义。

Ghost Writing技术:无OpenProcess/WriteProcessMemory的Shellcode注入(x64实现) 技术概述 Ghost Writing是一种高级进程注入技术,允许在不使用 OpenProcess 、 WriteProcessMemory 、 CreateRemoteThread 或 DebugActiveProcess 等传统API的情况下,向目标进程注入并执行shellcode。该技术最初由2007年的一篇博客提出,本文档将详细介绍其在x64环境下的实现方法。 核心原理 Ghost Writing技术的核心思想是: 利用 MOV [REG1],REG2 指令配合 SetThreadContext API实现内存写入 使用 EB FE 指令(无限循环)作为执行滞留点,防止进程崩溃 通过修改线程上下文和返回地址控制执行流程 技术实现步骤 1. 寻找合适的指令片段(Gadget) 在x64环境下,我们需要寻找以下类型的指令: MOV [REG1],REG2 :用于实现内存写入 EB FE :无限循环指令,用于执行滞留 由于x64架构与x86有所不同,实际可用的指令片段较少,且多为易失寄存器。可以通过以下方法寻找: 2. 构造执行环境 修改返回地址 :将返回地址设置为包含 EB FE 指令的地址,形成死循环 平衡堆栈 :在gadget中可能需要手动平衡堆栈(如插入 pop 或 add rsp 指令) 3. 内存写入机制 利用找到的gadget实现内存写入: 4. 调用任意函数 通过构造栈帧和修改RIP,可以调用任意函数(如 ntdll!NtProtectVirtualMemory ): 构造栈帧 : 需要为shadow stack预留空间((4+3+1)* sizeof(ULONG64)) 包含返回地址、参数和指针内容 示例调用NtProtectVirtualMemory : 5. 执行Shellcode 分配内存 :可以使用 VirtualAllocEx 申请内存(虽然使用了API,但可以替换为其他方法) 写入shellcode :通过上述内存写入机制 修改执行流程 :将RIP指向shellcode地址 6. 触发执行 对于GUI程序,可以通过 PostMessage 发送消息来触发执行,因为GUI线程是消息驱动的。 高级应用:任意方法调用 可以封装一个通用函数来调用任意API: 读取指针返回值 对于通过参数写回数据的函数(如 NtAllocateVirtualMemory ),需要从栈上读取指针值: 注意事项 线程句柄获取 :虽然可以避免使用 OpenProcess ,但仍需要 OpenThread 获取线程句柄 替代方案 :可以通过遍历线程快照( th32OwnerProcessID )来完全避免打开进程句柄 稳定性 :注入后原进程的GUI可能会卡死,需要根据实际情况处理 权限问题 :需要足够的权限来操作目标线程 技术优势 隐蔽性高 :避免了传统注入技术使用的敏感API 适用范围广 :可用于绕过某些安全产品的检测 灵活性好 :可以扩展为通用的函数调用机制 总结 Ghost Writing技术通过巧妙的指令片段利用和线程上下文操作,实现了不依赖传统API的进程注入。在x64环境下实现时需要注意指令选择、堆栈平衡和参数传递的差异。该技术可以进一步扩展为通用的远程函数调用机制,具有很高的实用价值和研究意义。