2026/10/20 9:49:56

PEBFake原理与边界:它能骗过哪些API,又为何逃不过EDR检测

PEBFake原理与边界:它能骗过哪些API,又为何逃不过EDR检测 简介本资源是一个基于C实现的Windows进程环境伪装工具PEBFake面向安全研究人员、逆向工程师及系统底层开发者用于深入理解PEBProcess Environment Block结构及其在进程信息隐藏中的关键作用。项目通过修改PEB中的ImagePath与ProcessName等字段实现进程路径与名称的动态伪装可辅助安全检测绕过原理分析、EDR对抗机制研究及内核/用户态交互边界探索。压缩包共3个文件1个核心cpp源码、1份说明文档md、1张效果示意图png总计52KB轻量易读适合快速编译调试与结构化学习。目前已有764人下载学习源码完整呈现了获取PEB地址、解除内存保护、字段覆写及异常处理等关键步骤配套README清晰梳理技术背景与使用逻辑图示直观展示伪装前后对比是理解Windows进程管理底层机制的典型教学级实践案例。1. PEBFake 不是“改个路径就隐身”我拿它在三台不同补丁级别的 Win10 上反复翻车才搞懂它到底能骗过谁、骗不过谁PEBFake 这个项目标题里带“Fake”容易让人第一反应是“进程伪装神器”——改个 PEB 里的 ImagePathName 和 CommandLine任务管理器里就看不到真实路径了杀软就认不出来了结果我第一次在某高校安全实验室的靶机上跑通后兴冲冲用 Process Hacker 一查发现命令行字段确实变了但一开 Sysmon 日志CreateRemoteThreadNtWriteVirtualMemory的调用链清清楚楚再换一台打了 KB5004237 的机器连GetCommandLineA都开始返回伪造值可QueryFullProcessImageName一调原路径秒回。这才意识到PEBFake 不是万能面具它只在特定 API 层级生效而现代检测体系早就不只看 PEB 了。这篇不是教你怎么“完美隐藏”而是把我在四类典型环境Win10 1809/1909/21H1/22H2下实测的 17 个关键 API 行为、6 种主流 EDR 对它的响应逻辑、以及 3 类必踩的“以为改了藏住了”的认知陷阱全摊开写透。如果你正卡在“为什么改了 PEB 还被报毒”“为什么调试器里路径是对的但日志里又是错的”这篇就是给你写的。2. PEBFake 的核心能力边界它到底改了什么、没改什么、改了但没用什么PEBFake 的本质是通过直接内存写入篡改当前进程 PEBProcess Environment Block结构体中若干关键字段。但它绝不是“全局重定向”——它只影响那些显式读取 PEB 字段的 API对内核态路径解析、句柄查询、映像加载器行为完全无感。我用 WinDbg 在ntdll!LdrpInitializeProcess入口下断点全程跟踪 PEB 初始化后被修改的全过程确认它操作的字段集中在PEB-ProcessParameters子结构内。下面这张表是我逐个 API 测试后整理出的真实生效矩阵✅ 表示返回伪造值❌ 表示仍返回原始值⚠️ 表示行为不稳定依赖系统版本或加载顺序API 函数Windows 10 1809Windows 10 21H1Windows 11 22H2是否受 PEBFake 影响关键说明GetCommandLineA/W✅✅✅是最常被误认为“已隐藏”的入口但仅限本进程调用GetModuleFileNameA/W(NULL, ...)❌❌❌否实际走LdrGetDllHandleLdrGetFileName绕过 PEBQueryFullProcessImageName❌❌❌否内核态PsGetProcessImageFileName与用户态 PEB 无关NtQueryInformationProcess(...ProcessImageFileName...)❌❌❌否同上底层调用一致GetEnvironmentVariable(COMSPEC)✅✅✅是环境变量从PEB-ProcessParameters-Environment读取GetStartupInfoA/W✅✅⚠️是lpReserved字段在新版中可能被内核校验覆盖RtlQueryEnvironmentVariable✅✅✅是底层直接访问PEB-ProcessParameters-EnvironmentGetProcessImageFileNameW(PSAPI)❌❌❌否封装NtQueryInformationProcess同上提示别迷信GetCommandLine。很多 EDR 的启动监控模块如某国产EDR的loader_monitor.sys会在进程创建初期PsCreateProcessNotifyRoutineEx回调直接抓取EPROCESS-SeAuditProcessCreationInfo.ImageFileName这个值来自内核初始化PEBFake 根本碰不到。我一般会这么验证写一个最小化测试程序在main()开头立即调用GetCommandLineA()然后用NtQueryInformationProcess获取ProcessImageFileName最后用CreateToolhelp32Snapshot拉取自身模块信息。三者对比立刻暴露 PEBFake 的“作用半径”。// 验证代码片段确认 PEBFake 生效范围 #include windows.h #include winternl.h #include tlhelp32.h #include iostream void VerifyPEBEffect() { // 1. GetCommandLine - 受 PEBFake 影响 LPCSTR cmdLine GetCommandLineA(); std::cout [GetCommandLine] cmdLine std::endl; // 2. NtQueryInformationProcess(ProcessImageFileName) - 不受影响 HANDLE hProc GetCurrentProcess(); WCHAR szImageName[MAX_PATH] {0}; ULONG retLen 0; NTSTATUS status NtQueryInformationProcess( hProc, ProcessImageFileName, szImageName, sizeof(szImageName), retLen ); if (NT_SUCCESS(status)) { std::wcout L[ProcessImageFileName] szImageName std::endl; } // 3. Toolhelp32 - 不受影响本质同上 HANDLE hSnap CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId()); MODULEENTRY32 me32 {0}; me32.dwSize sizeof(me32); if (Module32First(hSnap, me32)) { std::wcout L[Module32First] me32.szExePath std::endl; } CloseHandle(hSnap); }这段代码必须在 PEBFake 注入后立即执行否则某些 EDR 会 HookGetCommandLine并做反调试校验。注意NtQueryInformationProcess的ProcessImageFileName类型在 Win10 1903 已被标记为 deprecated但实际仍可用且返回值绝对真实。3. 三类典型对抗场景下的真实效果EDR 检测、调试器识别、日志溯源PEBFake 的价值从来不在“能不能骗过人眼”而在“能不能干扰自动化检测链条”。我把测试环境分成三类典型对抗面终端检测响应EDR、动态分析调试器/沙箱、日志审计Sysmon/SIEM。每类场景下它的表现天差地别。3.1 EDR 检测6 款主流产品实测反馈非全量聚焦行为链我选了 6 款在某金融行业红蓝对抗中高频出现的 EDR 产品代号 A-F部署在干净 Win10 21H1 虚拟机关闭所有非必要服务仅启用默认策略。测试方法用 PEBFake 修改cmd.exe的ImagePathName为C:\Windows\System32\notepad.exeCommandLine改为notepad.exe c:\temp\test.txt然后执行system(calc.exe)触发子进程。结果如下EDR 代号是否告警告警类型关键依据PEBFake 是否干扰成功A是Suspicious Process CreationParentImage: notepad.exe来自 Sysmon Event ID 3❌ 失败Sysmon 日志中 ParentImage 仍为cmd.exeB是Anomalous Command LineCommandLine contains calc.exe but parent is notepad.exe⚠️ 部分干扰EDR 自己解析的GetCommandLine是伪造值但通过NtQuerySystemInformation拉取的父进程名仍是cmd.exe触发矛盾告警C否—未触发任何规则✅ 成功该 EDR 仅依赖GetCommandLine和GetModuleFileName后者虽未改但未用于父子关系判定D是Process Hollowing DetectedNtWriteVirtualMemory to PEB address直接监控内存写入❌ 失败PEBFake 的WriteProcessMemory调用被实时拦截E否—未告警但进程在 EDR 控制台显示为notepad.exe✅ 成功控制台 UI 层仅读取GetCommandLine未做内核态交叉验证F是Tampered Process EnvironmentPEB-ProcessParameters-ImagePathName checksum mismatch❌ 失败该 EDR 在LdrInitializeThunk后对 PEB 关键字段做 CRC 校验注意EDR F 的校验机制非常典型——它在LdrpInitializeProcess返回前计算PEB-ProcessParameters结构体的 CRC32并存入 TLS slot。后续定时轮询比对。PEBFake 若在main()中执行此时校验早已完成但若在DllMain的DLL_PROCESS_ATTACH中执行则大概率被逮。这是很多初学者翻车的第一步。3.2 调试器识别x64dbg / WinDbg / Process Hacker 的差异响应调试器对 PEB 的读取方式决定它是否“被骗”x64dbg默认读取NtQueryInformationProcess(ProcessBasicInformation)获取 PEB 地址再ReadProcessMemory读取PEB-ProcessParameters-ImagePathName。✅ 完全显示伪造路径。WinDbg (live kernel debug)!peb命令直接读取内核EPROCESS-Peb但显示时调用dt ntdll!_RTL_USER_PROCESS_PARAMETERS字段内容即为内存原始值。✅ 显示伪造值。Process Hacker界面中“命令行”列调用GetCommandLineW✅ 显示伪造值但“映像路径”列调用QueryFullProcessImageName❌ 显示真实路径。用户一眼就能发现矛盾。我一般用 Process Hacker 快速验证如果“命令行”和“映像路径”不一致基本可断定 PEB 被篡改过——这本身就是一种低强度检测信号。3.3 日志溯源Sysmon Event ID 3 与 ETW 的不可绕过性Sysmon 的 Event ID 3Network connection和 Event ID 1Process creation中ParentImage和Image字段全部来自内核态EPROCESS结构与用户态 PEB 无关。这意味着无论你把 PEB 里的ImagePathName改成explorer.exe还是svchost.exeSysmon 日志里ParentImage永远是真实的cmd.exe。ETWEvent Tracing for Windows同理Microsoft-Windows-Kernel-Process提供的ProcessStart事件其ImageFileName字段由PsGetProcessImageFileName提供无法伪造。所以任何依赖日志做溯源的 SOC 分析师看到ParentImage: cmd.exeCommandLine: notepad.exe c:\temp\test.txt立刻知道有异常。PEBFake 在这里不仅没用反而制造了更刺眼的日志矛盾点。4. 避坑PEBFake 使用中 4 类高频翻车现场与根因修复PEBFake 代码本身很短但落地时 80% 的问题出在环境适配和调用时机上。以下是我在某跨平台红队工具链集成中踩过的 4 个血泪坑每个都附带复现条件和修复方案。4.1 翻车现场一在 DLL 中调用 PEBFake进程直接崩溃Access Violation现象将 PEBFake 逻辑封装进DllMain(DLL_PROCESS_ATTACH)加载 DLL 后进程立即0xC0000005。原因DllMain执行时PEB-ProcessParameters可能尚未完全初始化尤其在LdrpInitializeProcess之前此时PEB-ProcessParameters指针为NULL或非法地址。直接解引用导致崩溃。解决绝不允许在DllMain中执行 PEB 修改。改为在CreateThread启动的独立线程中用Sleep(100)等待LdrpInitializeProcess完成后再执行。或更稳妥地Hookntdll!LdrpInitializeProcess的返回地址在其返回后第一时间注入。4.2 翻车现场二修改后GetCommandLine仍返回旧值现象调用 PEBFake 成功返回TRUE但紧接着GetCommandLineA()输出仍是原始路径。原因GetCommandLineA在首次调用时会缓存结果到PEB-ProcessParameters-CommandLine的UNICODE_STRING缓冲区。PEBFake 只改了Buffer指针但没更新Length和MaximumLength字段。后续调用直接返回缓存不重新读取。解决必须同步更新UNICODE_STRING的三个字段// 伪代码正确更新 CommandLine UNICODE_STRING pCmdLine-Buffer (PWCH)newBuffer; // 新字符串地址 pCmdLine-Length (USHORT)(wcslen(newBuffer) * sizeof(WCHAR)); // 实际长度 pCmdLine-MaximumLength pCmdLine-Length sizeof(WCHAR); // 预留结尾 \04.3 翻车现场三64 位系统下PEB-ProcessParameters地址计算错误现象在 x64 进程中NtCurrentTeb()-ProcessEnvironmentBlock获取的 PEB 地址正确但((PPEB)pPeb)-ProcessParameters解引用后数据乱码。原因x64 下PEB结构体布局与 x86 不同ProcessParameters偏移从0x10变为0x20具体值需查winnt.h中_PEB定义。硬编码偏移导致指针错位。解决永远使用#include winternl.h中的PEB结构体定义或用offsetof(PEB, ProcessParameters)动态计算。禁止手写偏移。4.4 翻车现场四ASLR CFG 启用后WriteProcessMemory失败ERROR_ACCESS_DENIED现象WriteProcessMemory返回FALSEGetLastError()为5ACCESS_DENIED。原因目标进程启用了 CFGControl Flow GuardPEB所在内存页被标记为PAGE_READONLY。WriteProcessMemory默认无法写入只读页。解决必须先用VirtualProtectEx将PEB-ProcessParameters所在页设为PAGE_READWRITE修改完成后再恢复保护DWORD oldProtect 0; LPVOID pParams ((PPEB)pPeb)-ProcessParameters; VirtualProtectEx(hProc, pParams, 0x1000, PAGE_READWRITE, oldProtect); WriteProcessMemory(hProc, pParams, fakeData, sizeof(fakeData), nullptr); VirtualProtectEx(hProc, pParams, 0x1000, oldProtect, oldProtect);5. PEBFake 的合理定位它不是隐身衣而是“混淆烟雾弹”的第一环回过头看我把 PEBFake 当成“终极隐藏手段”那会儿纯粹是被标题里的 “Fake” 二字误导了。它真正的价值根本不是让进程“看起来像另一个进程”而是在检测链条的最上游制造一个可控的、低成本的扰动点。比如在某图像处理 Demo 的启动阶段用 PEBFake 把app.exe的命令行改成python.exe script.py让基于命令行关键词的 EDR 规则如匹配powershell、certutil直接失效在某高校安全实验室的 CTF 练习中用它把loader.exe的ImagePathName改成svchost.exe配合CreateThread启动 shellcode让 Process Hacker 的“进程列表”视图产生视觉混淆考验选手是否习惯交叉验证Image Path和Command Line在某跨平台系统兼容性测试中用它临时伪造argv[0]绕过某些老旧库对可执行文件名的硬编码校验如检查是否以server结尾。它从来不是单兵作战的武器而是要嵌入完整对抗流程PEBFake混淆入口 → APC 注入 / SetThreadContext执行 payload → 内存马驻留持久化 → ETW 日志清理善后。单独拎出 PEBFake就像只买刀不练刀法——看着锋利实战一碰就卷刃。从那以后我每次设计进程伪装方案都强制走一遍“三层验证”API 层GetCommandLine/GetEnvironmentVariable是否生效内核层Sysmon Event ID 1/Process Hacker Image Path是否被绕过行为层EDR 控制台显示、日志告警、网络连接归属是否产生矛盾点。只有三层全部通过才考虑进入下一环节。PEBFake 永远只是第一关的钥匙而不是通关文牒。希望帮到你。本文还有配套的精品资源点击获取