
Insomnia Windows Secure Wrapper基于 PROCESS_MITIGATION_POLICY 缓解本地搜索路径漏洞与本地构建指南【免费下载链接】insomniaThe open-source, cross-platform API client for GraphQL, REST, WebSockets, SSE and gRPC. With Cloud, Local and Git storage.项目地址: https://gitcode.com/GitHub_Trending/in/insomnia本文围绕 Insomnia 仓库中packages/insomnia/src/cpp/目录下的 C Secure Wrapper安全外壳程序展开先讲清它要解决的 Windows 本地搜索路径DLL 搜索顺序漏洞与PROCESS_MITIGATION_POLICY缓解机制再逐段剖析 insomnia.cpp 的进程编排实现最后完整继承并扩充原文档 cpp/README.md 中基于 MSYS2 的本地构建步骤。读完后可独立理解该安全外壳的完整运行链路并在 Windows 上自行重新构建。一、Secure Wrapper 是什么问题背景与设计目标README 开篇即说明该安全外壳的核心目的缓解本地搜索路径漏洞local search path vulnerability。这类漏洞的典型场景是Windows 程序的加载器在解析依赖 DLL 时会按“应用程序目录 → 系统目录 → …”的既定顺序搜索如果安装目录可被低权限用户写入例如某些打包器将 Electron 应用装到用户可写的目录攻击者即可在应用目录中放置一个同名的“毒 DLL”应用启动时加载器优先命中该恶意 DLL导致以当前用户身份执行任意代码。Secure Wrapper 的解法是不让 Electron 主程序直接作为启动入口而是由一个独立的 C 外壳最终被打包为Insomnia.exe先行启动通过 Windows 的PROCESS_MITIGATION_POLICY接口优先使用系统路径使 Electron 应用不会加载被放置在安装目录中的劫持 DLL。源码层面的证据在 insomnia.cpp 中见下文“启用缓解策略”一节同时代码注释明确标注了运行环境前提// NOTE: The calls in this wrapper are only supported on Windows 8. #define _WIN32_WINNT 0x602即这些缓解策略调用仅适用于 Windows 8 及以上这与 manifest.txt 中声明的supportedOSWindows 8 / Windows 8.1 / Windows 10一致。包装结构谁是外壳、谁是真身从 构建脚本 可以确认 Squirrel 布局下的文件关系cp $DEST_DIR/Insomnia.exe $DEST_DIR/insomnia.dll # 真身副本 1 cp $DEST_DIR/Insomnia.exe $DEST_DIR/Insomnia-origin-$VERSION.exe # 真身副本 2原本由 Electron 构建出的Insomnia.exe先被复制为insomnia.dll和Insomnia-origin-版本号.exe随后 C 外壳编译产物覆盖dist/win-unpacked/Insomnia.exe成为用户实际双击的入口把真身 Electron 可执行文件改名为insomnia.dll使安装目录中的入口文件只有外壳也降低了真身被直接双击或误执行的可能。外壳在启动时会区分两种安装形态从 insomnia.cpp 的源码结构看安装形态判定方式外壳的执行策略Squirrel便携/目录安装安装目录中不存在installer-info.json将insomnia.dll复制为insomnia-版本号.exe临时文件再启动进程结束后删除NSIS 安装包安装目录中存在installer-info.json仅探测文件是否存在即判定直接启动Insomnia-origin-版本号.exe不做临时复制二、insomnia.cpp 实现剖析以下按 insomnia.cpp 的WinMain执行顺序拆解。1. 调试模式与日志命令行包含--debug时进入调试模式L94调试日志通过DebugLog追加写入%TEMP%\insomnia.log带本地时间戳新建文件时写入 UTF-16 BOM 以保证记事本正确识别编码L47-L77。2. Squirrel 生命周期指令的处理外壳会拦截 Squirrel 更新框架传给入口 exe 的四个特殊参数L121-L150参数外壳行为--squirrel-install通过Update.exe --createShortcutexe 文件名创建快捷方式后直接返回--squirrel-updated/--squirrel-obsolete直接退出--squirrel-uninstall通过Update.exe --removeShortcutexe 文件名删除快捷方式后退出--squirrel-first-run记录日志后继续正常启动流程快捷方式目标名取的是入口 exe 的文件名且路径含空格时会自动加引号QuotePathIfNeededL86-L90。Update.exe的路径按“当前目录的上一级目录”推导Squirrel 的标准目录结构std::wstring updatePath(workDir); // get one directory above updatePath updatePath.substr(0, updatePath.find_last_of(L\\)) L\\Update.exe;注意Electron 侧也存在一套等价的 Squirrel 参数处理逻辑见 squirrel-startup.ts它服务于不使用外壳的构建形态如开发模式。3. 核心启用进程缓解策略这是整个 Secure Wrapper 的“题眼”L152-L181::PROCESS_MITIGATION_POLICY psp ::ProcessSignaturePolicy; ::PROCESS_MITIGATION_POLICY pilp ::ProcessImageLoadPolicy; ... // 二进制签名策略MitigationOptIn 1启用 if (!::GetProcessMitigationPolicy(::GetCurrentProcess(), psp, pmbsp, sizeof(pmbsp))) { return ::ExitWithWarning(nCmdShow, LCould not get ProcessImageLoadPolicy.); } if (pmbsp.MitigationOptIn 0) { pmbsp.MitigationOptIn 1; if (!::SetProcessMitigationPolicy(psp, pmbsp, sizeof(pmbsp))) { return ::ExitWithWarning(nCmdShow, LCould not set ProcessImageLoadPolicy.); } } // 镜像加载策略PreferSystem32Images 1优先系统路径 if (!::GetProcessMitigationPolicy(::GetCurrentProcess(), pilp, pmilp, sizeof(pmilp))) { return ::ExitWithWarning(nCmdShow, LCould not get ProcessImageLoadPolicy.); } if (pmilp.PreferSystem32Images 0) { pmilp.PreferSystem32Images 1; if (!::SetProcessMitigationPolicy(pilp, pmilp, sizeof(pmilp))) { return ::ExitWithWarning(nCmdShow, LCould not set ProcessImageLoadPolicy.); } }两段逻辑分别对应两类策略ProcessSignaturePolicy→MitigationOptIn 1启用二进制签名校验策略ProcessImageLoadPolicy→PreferSystem32Images 1镜像加载时优先从系统目录System32取 DLL从而压低“应用目录中的同名恶意 DLL 抢先被加载”的风险。两步都遵循“先读当前策略、仅在未启用时再写入”的幂等模式任一步Get/Set失败都会调用ExitWithWarning弹出错误对话框并返回非 0L25-L34对话框中附带项目 Issue 报告地址并询问用户是否用默认浏览器打开。注意这些策略设置在CreateProcessW之前即它们作用于外壳自身这个进程树入口——子进程真正的 Electron 应用由外壳创建并继承相应的加载环境约束这正是 README 所说“prefer the system paths”的实现载体。4. 管道重定向子进程输出外壳在启动真身之前建立匿名管道把子进程的标准输出/错误重定向到管道并循环读回后转发到外壳自身的控制台从而在保持控制台体验的前提下隔离子进程L190-L272if (!::CreatePipe(outrd, outwr, sa, 0)) { return ::ExitWithWarning(nCmdShow, LCould not create pipe.); } ... si.dwFlags | STARTF_USESTDHANDLES; si.hStdOutput outwr; si.hStdError outwr;同时通过::AttachConsole(-1)接入已有控制台启动时先打印Insomnia is starting...与命令行参数便于命令行用户确认进程已被外壳接管。5. 临时可执行文件的生命周期Squirrel 分支对非 NSIS 安装外壳启动的是带版本号的临时副本L208-L258tmpExe workDir\insomnia-版本号.exesourceInsomniaExe workDir\insomnia.dll若tmpExe已存在则跳过复制——源码注释解释为“另一个 Insomnia 实例很可能已经在运行”若该路径是一个目录则判定安装损坏并提示重新安装复制失败“Cannot read or write to executable folder”说明安装目录不可写直接终止以workDir为工作目录调用CreateProcessW启动该临时 exe主进程退出WaitForSingleObject等待后对临时文件做最多 5 次、每次间隔 1 秒的删除重试——因为文件句柄可能尚未完全释放L285-L302。NSIS 分支则跳过复制/删除直接启动Insomnia-origin-版本号.exeL251-L256。版本号常量INSOMNIA_VERSION是构建期由脚本注入的__VERSION__占位符见下文。三、嵌入的资源manifest 与 VERSIONINFO外壳 exe 内嵌了两类资源由 resources.rc 与 resource.h 定义应用清单1 MANIFEST manifest.txt把 manifest.txt 编译进 exe。清单关键项包括SquirrelAwareVersion: 1—— 声明自身是 Squirrel 感知的可执行文件dpiAware: true/pm—— 支持每显示器 DPI 感知位图模式requestedExecutionLevel levelasInvoker——以调用者权限运行、不请求 UAC 提权这对“缓解可写安装目录漏洞”的安全模型很重要提权反而掩盖问题依赖 Common Controls 6.0 并声明 Windows 8/8.1/10 兼容。版本资源VERSIONINFO块中的__MAJOR__、__MINOR__、__PATCH__、__TAG__、__YEAR__等占位符在构建期被替换且StringFileInfo中固定写入SquirrelAwareVersion, 1与清单声明呼应。图标资源1 ICON insomnia.ico使用的insomnia.ico由构建脚本从应用图标复制而来。四、本地构建指南完整继承并扩充原文档步骤以下流程完整继承自 cpp/README.md并补充了 build-secure-wrapper.sh 的内部行为适用于在 Windows 上手动重建外壳。步骤 1安装 MSYS2使用 MSYS2 官方 releases 页面上的基础自解压安装包base self-extracting installer将下载的.sfx.exe文件移动到你希望安装 MSYS2 的位置并运行它会就地解压出安装目录例如把C:\msys2-base-x86_64-NNNNNNNN.sfx.exe放到 C 盘得到C:\msys64打开 MSYS2 终端完成安装C:\msys64\msys2.exe关闭该终端改开ucrt64终端C:\msys64\ucrt64.exe——后续所有命令都在这类 UCRT64 环境的终端中执行。步骤 2安装构建依赖在ucrt64终端中安装 MinGW-w64 GCC 工具链pacman -S mingw-w64-ucrt-x86_64-gcc如尚未安装 git 与 nodepacman -S git pacman -S nodejs完成后确认windres与g在 PATH 中$ which windres /ucrt64/bin/windres $ which g /ucrt64/bin/g步骤 3构建进入仓库顶层目录并执行与原文档一致npm install ./build-secure-wrapper.sh构建成功后Squirrel 安装器即可从dist/win-unpacked启动即 构建脚本 中的packages/insomnia/dist/win-unpacked。脚本内部做了什么对照 build-secure-wrapper.sh./build-secure-wrapper.sh的完整行为是读取版本用jq从 packages/insomnia/package.json 提取version拆出MAJOR/MINOR/PATCH与可选的预发布TAG重建未打包应用若不带参数运行先执行npm run package:windows:unpacked -w insomnia重新产出 Electron 应用制作真身副本把dist/win-unpacked/Insomnia.exe复制为insomnia.dll与Insomnia-origin-VERSION.exe并把 icons/icon.ico 复制为外壳的图标源文件注入版本字符串用sed把insomnia.cpp中的__VERSION__、resources.rc中的__MAJOR__/__MINOR__/__PATCH__/__TAG__/__YEAR__替换为实际值生成final.cpp与final.rc编译资源windres final.rc res.o编译并静态链接g -lkernel32 -mwindows编译 C再以-O2 -static -static-libgcc -static-libstdc -mwindows -lwinpthread链接——静态链接保证外壳 exe不依赖 UCRT 等运行时 DLL避免外壳自身引入新的 DLL 搜索面打包发行物执行npm run package:windows:dist -w insomnia产出最终安装包复位把dist/win-unpacked中的insomnia.dll改名回Insomnia.exe脚本注释说明目的是“Reset to prevent accidental loops”——防止再次从该目录启动时外壳复制到的“真身”其实是外壳自己。此外脚本支持一个特殊上下文参数./build-secure-wrapper.sh SOLOSOLO模式下跳过“重建 unpacked 应用”与“打包发行物”两个阶段只重新编译外壳并输出到packages/insomnia/src/cpp/Insomnia.exe——正如脚本内注释所说适合只想重建外壳再手动拷进现有安装目录的场景。五、外壳与 Electron 更新流程的交互影响Secure Wrapper 一旦成为启动入口会对应用内部的更新逻辑产生可观测的影响仓库中有两处直接证据quitAndInstall的绕过updates.ts 中Windows 平台不走autoUpdater.quitAndInstall()而是手动拉起Update.exe// Workaround for the windows secure wrapper breaking quitAndInstall logic. // This is related to PR 8451 / CVE-2025-1353 / which broke the auto restart after an in-place update const updateExe path.resolve(path.dirname(process.execPath), .., Update.exe); spawn(updateExe, [--processStartAndWait, Insomnia.exe], { detached: true, windowsHide: true, }); app.quit();源码注释明确点出这是Windows 安全外壳破坏了quitAndInstall重启逻辑的变通方案且与 CVE-2025-1353 相关的修复有关。这也从侧面印证了 Secure Wrapper 就是针对该类本地搜索路径漏洞的工程修复。NSIS 与 Squirrel 双轨制同一文件中的init()通过isNsisInstaller()区分两套更新实现——NSIS 安装走electron-updaterSquirrel 安装走electron.autoUpdater这与外壳里依据installer-info.json的存在与否区分安装形态是同一设计在不同进程中的映射。NSIS 安装器的打包配置见 electron-builder.config.jstarget: nsis、自定义nsisInstall.nsh脚本等。六、小结Secure Wrapper 是一个约 300 行的 Windows 专用 C 外壳核心价值在SetProcessMitigationPolicy的两项策略二进制签名校验MitigationOptIn与系统镜像优先加载PreferSystem32Images从加载器层面封堵“可写安装目录中的毒 DLL”攻击路径它同时承担了 Squirrel 生命周期指令中转、子进程输出管道转发、版本化临时文件管理含最多 5 次删除重试与 NSIS/Squirrel 双形态适配等职责本地重建只需 MSYS2 UCRT64 环境下的windresg一条./build-secure-wrapper.sh或SOLO模式单独重建外壳即可完成版本注入、资源编译与静态链接阅读源码时建议按 insomnia.cpp → build-secure-wrapper.sh → manifest.txt / resources.rc → updates.ts 的顺序串联理解从外壳行为、到构建产物布局、再到对上层更新流程的影响构成该安全机制的完整证据链。【免费下载链接】insomniaThe open-source, cross-platform API client for GraphQL, REST, WebSockets, SSE and gRPC. With Cloud, Local and Git storage.项目地址: https://gitcode.com/GitHub_Trending/in/insomnia创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考