前言
Ghosting Hollowing其实就是Process Hollowing(进程镂空) + Process Ghosting(进程幽灵化)的组合使用,相当于取长补短吧。
Process Ghosting 的问题:
✅ 文件删除后安全软件无法扫描
❌ 需要通过 NtCreateProcessEx 创建全新进程
❌ 新进程初始化复杂(PEB、进程参数等)
❌ 稳定性和兼容性不够好
Process Hollowing 的问题:
✅ 利用已有进程,稳定简便
❌ 内存中恶意代码来源可追溯
❌ WriteProcessMemory 被 EDR 重点监控
❌ 内存页面类型为 MEM_PRIVATE,容易被发现
Ghosting Hollowing 的思路:
从 Ghosting 借用: delete-pending 文件删除技巧
从 Hollowing 借用: 注入已有挂起进程
→ 文件被删除(安全软件无法扫描)
→ 注入已有进程(稳定可靠)
→ 使用 NtMapViewOfSection(内存特征更合法)
Process Hollowing
Process Hollowing流程非常简单,无法就是创建一个新的进程挂起,然后掏空里面的内存,把恶意的PE文件写入到挂起的进程里面,然后回复线程执行。
有一点要注意的是,需要修复重定位表,这一块稍微有点小麻烦,建议不熟悉PE文件格式的人直接网上找或者叫AI写一个就行。
CreateProcess (SUSPENDED)
│
▼
GetThreadContext ──→ 获取 PEB 地址
│
▼
ReadProcessMemory ──→ 读取原始 ImageBase
│
▼
NtUnmapViewOfSection ──→ 卸载原始映像
│
▼
VirtualAllocEx ──→ 分配新内存空间
│
▼
WriteProcessMemory ──→ 写入 PE Headers + Sections
│
▼
处理重定位(如果需要)
│
▼
WriteProcessMemory ──→ 更新 PEB.ImageBase
│
▼
SetThreadContext ──→ 设置新入口点 (EAX/RCX)
│
▼
ResumeThread ──→ 恶意代码开始执行
整体流程十分简单,就不给出代码了,需要注意的是卸载原始映像之后,可能会导致回复了线程也无法运行,所以建议不需要卸载原始映像,VirtualAllocEx会自动分配空间。
Process Ghosting
翻译过来就叫进程幽灵化,这个主要是利用 Windows 在创建进程时对文件状态检查的时序漏洞(TOCTOU)。 Windows 创建一个文件时,可以标记为 pending delete(待删除) 状态时,其他任何进程无法打开该文件(包括 AV 扫描)。但是,但已经基于该文件创建的 Section(映像节)仍然有效。 所以我们可以创建一个文件标为为待删除状态,接着写入恶意的PE文件,然后基于该文件创建一个Section, 最后基于该Section再创建一个进程,最后关闭文件句柄,待删除文件就会从磁盘消失,这就是进程幽灵化。
整体流程图如下,值得一提的是,创建进程时要用NtCreateProcessEx,只有NtCreateProcessEx能基于Section 去创建进程。CreateProcess无法基于Section 去创建进程,但是可以正常创建一个进程并挂起,然后把Section 映射到这个挂起的进程里面,然后回复线程执行的化,其实也是执行这个恶意Section的,但是这属于Ghosting变种了。
┌─────────────────────────────────────────────────────┐
│ Step 1: NtCreateFile │
│ 创建一个新文件 (temp.exe) │
│ │ │
│ ▼ │
│ Step 1b: NtSetInformationFile │
│ 标记文件为 "Pending Delete" │
│ ┌─────────────────────────────────┐ │
│ │ 文件处于待删除状态 │ │
│ │ AV/EDR 无法打开扫描 │ │
│ └─────────────────────────────────┘ │
│ │ │
│ ▼ │
│ Step 2: NtWriteFile │
│ 将恶意 PE Payload 写入文件 │
│ │ │
│ ▼ │
│ Step 3: NtCreateSection (SEC_IMAGE) │
│ 基于文件创建映像 Section │
│ 内核缓存 PE 映像到内存 │
│ │ │
│ ▼ │
│ Step 4: NtClose(hFile) │
│ 关闭文件句柄 → 文件自动从磁盘删除 │
│ ┌─────────────────────────────────┐ │
│ │ 磁盘上文件已消失 ❌ │ │
│ │ 内存中 Section 仍有效 ✅ │ │
│ └─────────────────────────────────┘ │
│ │ │
│ ▼ │
│ Step 5: NtCreateProcessEx(hSection) │
│ 基于 Section 创建进程对象 │
│ │ │
│ ▼ │
│ Step 6: 设置 PEB / ProcessParameters │
│ NtQueryInformationProcess │
│ RtlCreateProcessParametersEx │
│ NtAllocateVirtualMemory + NtWriteVirtualMemory │
│ │ │
│ ▼ │
│ Step 7: NtCreateThreadEx │
│ 创建主线程 → 恶意代码开始执行 │
│ │ │
│ ▼ │
│ 进程在任务管理器中显示,但对应磁盘文件不存在 │
│ AV 扫描时找不到文件或文件内容 │
└─────────────────────────────────────────────────────┘
整体流程并不复杂,所以也不给代码了,唯一要注意的NtCreateProcessEx要自己修复PEB,如果有重定位表也要修复。
Ghosting Hollowing
终于来到今天的主角Ghosting Hollowing了,其实就是上面两个技术一起来用。
该注入可以分为两阶段,第一阶段和Process Ghosting一样,第二阶段就是和Process Hollowing一样。简单概括就是,创建一个待删除(delete-pending)的文件 → 写入恶意内容 → 创建映像 Section → 文件被删除 → 将恶意 Section 映射到一个挂起的合法进程中 → 恶意代码在合法进程外壳中执行,而磁盘上的恶意文件已不复存在。
流程如下,相当于注入阶段是用Ghosting,执行阶段就是Hollowing,所以就叫Ghosting Hollowing。
阶段一:幽灵化准备(来自 Ghosting)
══════════════════════════════════
步骤1: CreateFile("C:\\Temp\\ghost.exe", ...)
→ 创建一个新文件,获取文件句柄 hFile
步骤2: NtSetInformationFile(hFile, FileDispositionInformation, DELETE=TRUE)
→ 将文件标记为 "delete-pending"(待删除)
→ 此时:
✅ 持有句柄的当前进程仍可读写
❌ 其他进程(包括安全软件)无法打开此文件
步骤3: WriteFile(hFile, malicious_PE_content)
→ 将恶意 PE 写入这个待删除状态的文件
→ 安全软件此时已无法访问该文件
步骤4: NtCreateSection(hFile, SEC_IMAGE)
→ 基于这个 delete-pending 文件创建可执行映像 Section
→ ★ 恶意代码的内存映像已创建完成 ★
步骤5: CloseHandle(hFile)
→ 关闭文件句柄
→ ★ 文件被操作系统真正删除!磁盘上不再存在 ★
→ 但内存中的 Section 仍然有效!
阶段二:进程镂空注入(来自 Hollowing)
═══════════════════════════════════
步骤6: CreateProcess("svchost.exe", CREATE_SUSPENDED)
→ 创建一个合法的挂起进程作为宿主
步骤7: NtUnmapViewOfSection(target_process, image_base)
→ 掏空目标进程的原始映像(建议不掏空)
步骤8: NtMapViewOfSection(hGhostSection, target_process)
→ ★ 核心步骤 ★
→ 将阶段一中创建的幽灵 Section 映射到目标进程
→ 替代传统 Hollowing 的 WriteProcessMemory
步骤9: 修复重定位 / 更新 PEB / 修改入口点
→ SetThreadContext 设置新的入口点
步骤10: ResumeThread
→ 恢复执行
→ 恶意代码在 svchost.exe 外壳中运行
→ 磁盘上无恶意文件
→ 安全软件无法追溯文件来源
实现代码就不放出来,有需要的师傅可以加我好友。
总结
Ghosting Hollowing整体流程不算复杂,比较复杂的就是修复重定位。当然,如果你的恶意exe没有重定位表,那就不需要修复,有的需就需要,否则PE将无法执行。