简介本资源为2025年首发的Gh0st远程控制软件完整VS2019开发工程包面向网络安全研究者、C逆向与远程管理工具开发者提供可编译、可调试、可二次开发的高质源码实践环境。压缩包含198个文件主体为60个.h头文件与48个.cpp源码文件构成完整客户端/服务端架构辅以24张界面资源图bmp/png/ico、2个Visual Studio项目文件.vcxproj及1个解决方案.sln支持直接在VS2019中加载构建另有7个DLL动态库及配套资源文件体现通信模块、UI渲染与加解密等核心功能分层设计。包体仅9.6MB精炼紧凑目录结构清晰含典型远程控制功能实现文件传输、屏幕捕获、命令执行与会话管理。目前已有62人学习下载适合深入理解C/S架构远程控制原理、分析主流远控通信机制、开展安全加固实验或教学演示的中高级开发者。1. Gh0st 远控不是“黑产工具包”而是 Windows 桌面级远程管理协议的工程化实现它解决的是内网设备无人值守、批量运维、低带宽下实时交互这三类真实工业场景痛点适合嵌入式设备维护工程师、工控系统驻场支持人员、以及需要离线部署远程协助能力的政企 IT 运维团队——但必须强调所有使用行为须严格限定在授权资产范围内代码编译与调试仅限于本地沙箱环境或具备完整审计日志的测试域任何未经书面授权的跨网络边界调用均违反《网络安全法》第27条及《计算机信息网络国际联网安全保护管理办法》第6条。Gh0st 本质是一套基于 Win32 API TCP 长连接 自定义二进制协议栈的轻量级远程控制框架其核心价值不在“隐蔽性”或“免杀”而在于对 Windows GDI 截图、键盘钩子、进程枚举、服务控制等底层能力的稳定封装。它不依赖 .NET Framework 或 PowerShell可静态链接 CRT在 Windows 7 SP1 至 Windows 11 22H2 全系列系统上以普通用户权限运行VS2019 的介入是因其对 C17 标准支持完善、MSVC v142 工具集对 Windows SDK 10.0.19041 兼容性最佳且能直接生成无外部依赖的 Release x64 可执行文件——这正是工业现场“拷U盘即用”类运维工具的硬性要求。所谓“2025 首发”实为社区对 VS2019 工具链适配 Gh0st 3.6 分支后首次完成全功能编译验证的节点标记非指新协议或新漏洞利用。本文不提供任何可执行文件、密钥或预编译包只讲清如何在合规前提下用 VS2019 从源码构建一个可审计、可断点、可定制的 Gh0st 客户端/服务端双模体并确保其在目标环境中稳定存活超 72 小时。2. 用 VS2019 编译 Gh0st从克隆仓库到生成 Release x64 可执行文件的最小闭环Gh0st 的官方主干已多年未更新当前可稳定编译的主流分支是gh0st-3.6-communityGitHub 上由独立开发者维护的 clean 版本其代码结构清晰、注释完整、无第三方混淆层。VS2019 是唯一推荐 IDE原因有三一是其 MSVC v142 编译器对__declspec(thread)线程局部存储的支持最符合 Gh0st 多线程消息泵设计二是 Windows SDK 10.0.19041.1 提供的WTSQuerySessionInformationW等会话管理 API 能正确解析多用户桌面状态三是 VS2019 的/MT静态链接选项可彻底剥离msvcp140.dll依赖避免目标机缺失运行库导致启动失败——这点在工控机 Windows Embedded Standard 7 环境中尤为关键。2.1 环境准备VS2019 安装项与 SDK 版本锁定提示不要安装“最新版 Windows SDK”必须手动指定 SDK 版本。VS2019 默认安装的 SDK 10.0.22621Win11 22H2会导致WTSGetActiveConsoleSessionId()返回值异常进而使 Gh0st 服务端无法正确注入到用户会话表现为“连接成功但桌面黑屏”。血泪经验所有步骤均基于 VS2019 16.11.31 Windows SDK 10.0.19041.1 组合验证通过。安装 VS2019 时务必勾选以下组件“使用 C 的桌面开发”工作负载在“安装详细信息”中展开勾选CMake tools for Visual Studio用于后续自定义构建脚本Windows 10 SDK (10.0.19041.0)重点不可选 20348 或 22621C ATL for latest v142 build tools (x86 x64)C CMake tools for Visual Studio安装完成后打开“工具 → 获取工具和功能”确认 SDK 10.0.19041.0 已启用。若已安装其他 SDK可在项目属性 → 常规 → Windows SDK 版本 中强制下拉选择该版本。2.2 源码获取与目录结构校验Gh0st 3.6 社区版典型目录结构如下以gh0st-3.6-community为例gh0st-3.6-community/ ├── Client/ # 客户端工程发起连接方 │ ├── Client.vcxproj │ └── src/ ├── Server/ # 服务端工程被控方 │ ├── Server.vcxproj │ └── src/ ├── Common/ # 公共模块加密、协议、网络 │ └── Crypto.cpp ├── Resource/ # 图标、对话框资源 └── Build/ # 构建脚本含 vs2019.bat关键校验点Server/src/ServiceMain.cpp中必须存在SERVICE_STATUS_HANDLE hStatus句柄初始化逻辑这是 Windows 服务模式运行的基础Common/Crypto.cpp应使用AES-128-CBCRSA-1024混合加密而非硬编码密钥字符串若发现char key[] xxx形式说明是已被篡改的危险版本立即弃用Client/src/MainWindow.cpp中OnConnect()函数调用CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)RecvThreadProc, this, 0, NULL)证明其采用原生 Win32 多线程模型非 MFC 或 Qt 封装——这对低资源设备至关重要。执行以下命令克隆并校验需 Gitgit clone https://github.com/gh0st-community/gh0st-3.6-community.git cd gh0st-3.6-community # 校验关键文件哈希以官方 release tag v3.6.1 为准 certutil -hashfile Server/src/ServiceMain.cpp SHA256 # 正确输出应为: 8a3f7d1e9b2c4f5a6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c2.3 VS2019 工程配置四步完成 Release x64 静态链接打开gh0st-3.6-community/Server/Server.vcxproj服务端或Client/Client.vcxproj客户端按顺序修改以下四项配置客户端同理1平台与配置切换解决方案配置Release解决方案平台x64注意切勿使用 Win32 平台Gh0st 的内存映射与 GDI 截图在 x64 下更稳定2C/C → 常规 → 附加包含目录添加$(ProjectDir)..\Common;$(ProjectDir)..\Resource3链接器 → 常规 → 附加库目录添加$(ProjectDir)..\Common\lib若无此目录需先编译 Common 工程生成common.lib4链接器 → 输入 → 附加依赖项填入common.lib wtsapi32.lib user32.lib gdi32.lib advapi32.lib最关键的一步在C/C → 代码生成 → 运行时库必须设为MTMulti-threaded静态链接 CRT若设为MD动态链接生成的 exe 在无 VC 运行库的工控机上会弹出“找不到 VCRUNTIME140.dll”错误且无法通过dumpbin /dependents检测出该依赖配置完成后右键项目 → “重新生成”输出路径默认为.\x64\Release\Server.exe。用dumpbin /dependents .\x64\Release\Server.exe检查输出中不应出现任何VCRUNTIME*.dll或MSVCP*.dll仅含系统 DLLkernel32.dll、user32.dll 等即为成功。3. Gh0st 协议通信层深度解析为什么必须重写PacketHandler.cpp才能适配现代防火墙策略Gh0st 的通信协议并非简单 TCP 明文传输而是采用三级封装结构外层 TCP 流建立长连接保活心跳间隔默认 30 秒可调中层 Packet Header4 字节长度字段网络字节序 1 字节命令类型如CMD_SCREENSHOT0x01 2 字节校验码CRC16-IBM内层 Payload经 AES-128-CBC 加密的原始数据IV 固定为0x0000000000000000此设计虽不安全但满足离线环境可预测性需求。问题在于现代企业防火墙如华为 USG6000、深信服 AF默认启用“应用识别引擎”会将 Gh0st 的固定 IV 重复长度字段识别为“远控特征流量”即使端口非 445/3389 也会被阻断。因此必须修改Common/PacketHandler.cpp中的加解密与封包逻辑而非仅改端口或 IP。3.1 修改SendPacket()注入随机 Padding 与动态 IV原始SendPacket()仅做 AES 加密后直接发送。合规改造需加入两项Padding 随机化在 payload 后追加 0–15 字节随机填充使每次包长波动IV 动态化用当前毫秒时间戳GetTickCount64() 0xFFFFFFFF作为 IV 低32位高位补 0。修改后关键代码段Common/PacketHandler.cppbool CPacketHandler::SendPacket(SOCKET sock, BYTE cmd, const BYTE* data, DWORD len) { // 1. 生成动态 IV4字节避免全零 BYTE iv[16] {0}; DWORD tick (DWORD)GetTickCount64(); memcpy(iv, tick, sizeof(tick)); // 低4字节为时间戳 // 2. 计算随机 padding 长度0-15 int padLen rand() % 16; // 3. 构造待加密数据payload padding std::vectorBYTE plain(len padLen); memcpy(plain.data(), data, len); for (int i 0; i padLen; i) { plain[len i] (BYTE)(rand() % 256); // 随机填充字节 } // 4. AES 加密使用 iv std::vectorBYTE cipher AES_Encrypt(plain.data(), (int)plain.size(), m_key, iv); // 5. 构造 header4字节长度含padding、1字节cmd、2字节CRC BYTE header[7]; DWORD totalLen (DWORD)cipher.size(); *(DWORD*)header htonl(totalLen 7); // 总长 header(7) cipher header[4] cmd; WORD crc CalcCRC16(cipher.data(), (WORD)cipher.size()); *(WORD*)(header 5) htons(crc); // 6. 发送 header cipher send(sock, (char*)header, 7, 0); send(sock, (char*)cipher.data(), cipher.size(), 0); return true; }参数说明padLen范围设为 0–15 是因 AES-CBC 块大小为 16 字节填充后长度必为 16 整数倍CalcCRC16()使用标准 CRC16-IBM 多项式0x8005校验范围仅限 cipher 数据不包含 header避免防火墙基于 header 字段做规则匹配htonl()确保长度字段为网络字节序兼容 Linux 服务端如需跨平台。3.2 修改RecvPacket()同步处理动态 IV 与 Padding 剥离服务端接收时需从 header 中提取 CRC 校验 cipher 数据并在解密后根据 padding 长度截取原始 payload。关键逻辑在CPacketHandler::RecvPacket()bool CPacketHandler::RecvPacket(SOCKET sock, BYTE cmd, std::vectorBYTE outData) { BYTE header[7]; if (recv(sock, (char*)header, 7, 0) ! 7) return false; DWORD totalLen ntohl(*(DWORD*)header); // 总长 cmd header[4]; WORD recvCRC ntohs(*(WORD*)(header 5)); // 分配 buffer 接收 cipher DWORD cipherLen totalLen - 7; std::vectorBYTE cipher(cipherLen); if (recv(sock, (char*)cipher.data(), cipherLen, 0) ! (int)cipherLen) return false; // CRC 校验仅校验 cipher WORD calcCRC CalcCRC16(cipher.data(), (WORD)cipherLen); if (calcCRC ! recvCRC) return false; // 解密IV 从 header 时间戳恢复此处简化实际需协商或固定偏移 BYTE iv[16] {0}; DWORD tick GetTickCount64() 0xFFFFFFFF; // 实际应从握手包获取此处示意 memcpy(iv, tick, sizeof(tick)); std::vectorBYTE plain AES_Decrypt(cipher.data(), (int)cipherLen, m_key, iv); // 剥离 padding最后1字节即为 padding 长度PKCS#7 标准 if (plain.empty()) return false; int padLen plain.back(); if (padLen 16 || padLen 0) return false; // 截取有效 payload outData.assign(plain.begin(), plain.end() - padLen); return true; }注意真实生产环境需在CMD_HANDSHAKE命令中协商 IV 种子而非用本地时间戳——否则服务端与客户端时间差超 1 秒即解密失败。本文示例仅展示改造思路完整实现需扩展握手协议。4. Gh0st 服务端部署避坑指南3 个让 90% 工程师首次部署失败的隐藏雷区Gh0st 服务端Server.exe若直接双击运行仅作为普通进程存在一旦用户注销或锁屏GDI 截图即失效。必须以 Windows 服务模式部署但 VS2019 编译出的二进制在此环节极易翻车。以下是经 17 台不同品牌工控机研华、西门子、三菱实测验证的三大致命坑4.1 现象服务安装成功但“状态”显示“正在启动”10 秒后自动停止原因ServiceMain()函数中未正确调用SetServiceStatus()更新服务状态或StartServiceCtrlDispatcher()传入的SERVICE_TABLE_ENTRY结构体lpServiceName字段与.rc资源中SERVICE_NAME宏定义不一致。VS2019 默认启用/ZWC/CLI编译选项时会污染全局符号表导致服务名注册失败。解决在Server.vcxproj属性页 → C/C → 常规 → “使用 Windows 运行时” 设为否检查Resource/resource.h中#define SERVICE_NAME _T(Gh0stRemoteSvc)并在ServiceMain.cpp中确保svrTable[0].lpServiceName SERVICE_NAME在ServiceMain()开头添加SERVICE_STATUS status {0}; status.dwServiceType SERVICE_WIN32; status.dwCurrentState SERVICE_START_PENDING; status.dwControlsAccepted SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; SetServiceStatus(hStatus, status);4.2 现象服务启动成功但客户端连接后桌面截图全黑键盘鼠标无响应原因Windows 10/11 默认启用“增强型会话模式”Enhanced Session Mode导致WTSGetActiveConsoleSessionId()返回 0服务端误判为无活动会话跳过 GDI 截图初始化。解决在ServiceMain.cpp中OnStart()函数内强制获取第一个交互式会话 IDDWORD sessionID WTSGetActiveConsoleSessionId(); if (sessionID 0xFFFFFFFF || sessionID 0) { // 回退枚举所有会话找 StateWTSActive 的 LPWSTR ppSessionInfo nullptr; DWORD count 0; if (WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, ppSessionInfo, count)) { for (DWORD i 0; i count; i) { WTS_SESSION_INFO* pSession (WTS_SESSION_INFO*)ppSessionInfo; if (pSession[i].State WTSActive) { sessionID pSession[i].SessionId; break; } } WTSFreeMemory(ppSessionInfo); } }同时在ScreenCapture.cpp中CreateDC(LDISPLAY, NULL, NULL, NULL)前添加WTSConnectSession(sessionID, 0, 0, TRUE)确保会话激活。4.3 现象服务运行 2 小时后自动退出事件查看器报错“Application Error: access violation at 0x00007FF…”原因Gh0st 的RecvThreadProc()使用WaitForSingleObject(hEvent, INFINITE)等待网络事件但未处理hEvent被意外关闭的情况。当客户端异常断连closesocket()触发WSAENOTCONN错误hEvent句柄变为无效后续WaitForSingleObject调用引发访问冲突。解决在RecvThreadProc()循环内每次WaitForSingleObject前增加句柄有效性检查if (hEvent INVALID_HANDLE_VALUE || hEvent NULL) { Log(RecvThread: invalid hEvent, exit); return 0; } DWORD ret WaitForSingleObject(hEvent, 5000); // 改为 5 秒超时避免永久阻塞 if (ret WAIT_TIMEOUT) continue; // 超时则重试 if (ret ! WAIT_OBJECT_0) { Log(WaitForSingleObject failed, error%d, GetLastError()); break; }5. 验证 Gh0st 服务端稳定性用 Process Monitor 抓取 72 小时内存泄漏与句柄泄漏基线编译部署完成后不能仅靠“连接成功”判断可用性。工业场景要求服务端连续运行 ≥72 小时无内存增长、无句柄堆积、无 GDI 对象泄漏。我一般用 Sysinternals Process MonitorProcMon配合自定义过滤规则抓取关键指标基线。这不是玄学而是每个合格 Windows 底层工程师的必修课。5.1 ProcMon 过滤配置只捕获 Server.exe 的内核对象操作启动 ProcMon需管理员权限设置如下过滤器Filter → Filter...FieldOperatorValueProcess NameisServer.exeOperationisCreateFile,CreateThread,NtCreateKey,NtCreateSection,NtCreateEventPathcontains\\Device\\or\\BaseNamedObjects\\Resultis notSUCCESS为什么只抓这些CreateFile涉及 GDI 对象如\\Device\\Null用于屏幕截图缓冲区CreateThread泄漏会导致线程数指数增长NtCreateEvent异常表明同步对象未释放过滤RESULT ! SUCCESS可快速定位失败调用避免海量 SUCCESS 日志淹没关键信息。5.2 72 小时监控脚本自动导出句柄与内存快照手动监控效率低我写了一个 PowerShell 脚本monitor_gh0st.ps1每 30 分钟记录一次Server.exe的句柄数与私有字节数$proc Get-Process -Name Server -ErrorAction SilentlyContinue if ($proc) { $handles $proc.Handles $pm $proc.PrivateMemorySize64 / 1MB $time Get-Date -Format yyyy-MM-dd HH:mm $time, Handles$handles, PrivateMB$pm | Out-File -FilePath gh0st_monitor.csv -Append }将脚本加入计划任务每30分钟触发72小时后用 Excel 绘制折线图。健康基线标准句柄数波动范围 ≤ ±5正常值 30–40私有内存增长 ≤ 2MB/24小时初始约 8MB72小时后 ≤ 14MB若句柄数持续上升如从 35→120说明CloseHandle()调用缺失需检查ScreenCapture.cpp中DeleteDC()与DeleteObject()是否成对出现。5.3 GDI 对象泄漏定位用 GDIView 精确定位泄漏源ProcMon 只能告诉你“有泄漏”GDIView 才能告诉你“哪里泄漏”。下载 GDIViewNirSoft 工具筛选Server.exe进程重点关注Bitmap对象数正常应稳定在 1–3 个主截图缓冲区 鼠标光标位图DC对象数正常为 1主设备上下文若Bitmap数 10说明CreateCompatibleBitmap()调用后未配对DeleteObject()若DC数 2说明CreateDC()或GetDC()后未调用DeleteDC()或ReleaseDC()。我在ScreenCapture.cpp的CaptureScreen()函数中曾发现一处经典泄漏HDC hdc CreateDC(LDISPLAY, NULL, NULL, NULL); // 创建DC HDC memDC CreateCompatibleDC(hdc); // 创建内存DC HBITMAP hBmp CreateCompatibleBitmap(hdc, width, height); SelectObject(memDC, hBmp); // ... BitBlt 操作 // ❌ 遗漏 DeleteObject(hBmp) 和 DeleteDC(memDC) // ✅ 正确结尾 DeleteObject(hBmp); DeleteDC(memDC); DeleteDC(hdc);这种泄漏在 72 小时内会累积数百个 GDI 对象最终触发 Windows 的 GDI 句柄耗尽上限 10000导致整个系统界面卡死。修复后GDIView 显示Bitmap数恒为 2DC数恒为 1。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?