远程控制开发基础

2、客户端进程信息获取

1、课程目标

  1. 掌握Windows进程枚举技术
  2. 实现进程列表获取功能
  3. 获取进程详细信息(路径、PID等)
  4. 理解进程权限和访问控制

2、名词解释

术语 全称 解释
Process 进程 程序的执行实例
PID Process ID 进程标识符
TID Thread ID 线程标识符
Snapshot 快照 系统对象的瞬时视图
ToolHelp32 - Windows提供的进程/线程枚举API

3、技术原理

1. 进程枚举方法

方法1: CreateToolhelp32Snapshot
  - 创建系统快照
  - 枚举进程/线程/模块
  - 最常用的方法

方法2: EnumProcesses (PSAPI)
  - 获取PID列表
  - 需要进一步查询详细信息

方法3: WTSEnumerateProcesses
  - 终端服务API
  - 可获取会话信息

方法4: NtQuerySystemInformation
  - Native API
  - 更底层,功能强大

2. 进程信息结构

// PROCESSENTRY32 结构
typedef struct tagPROCESSENTRY32 {
    DWORD dwSize;              // 结构大小
    DWORD cntUsage;            // 引用计数
    DWORD th32ProcessID;       // 进程ID
    ULONG_PTR th32DefaultHeapID; // 默认堆ID
    DWORD th32ModuleID;        // 模块ID
    DWORD cntThreads;          // 线程数
    DWORD th32ParentProcessID; // 父进程ID
    LONG pcPriClassBase;       // 优先级基值
    DWORD dwFlags;             // 标志
    CHAR szExeFile[MAX_PATH];  // 可执行文件名
} PROCESSENTRY32;

3、代码实现

1. 基础进程枚举

// process_enum.cpp
// 进程信息获取

#include <windows.h>
#include <tlhelp32.h>
#include <psapi.h>
#include <stdio.h>
#include <vector>
#include <string>

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

// 进程信息结构
typedef struct _PROCESS_INFO {
    DWORD pid;
    DWORD parentPid;
    DWORD threadCount;
    std::string exeName;
    std::string fullPath;
    DWORD priority;
} PROCESS_INFO, *PPROCESS_INFO;

// 方法1: ToolHelp32枚举
std::vector<PROCESS_INFO> EnumProcesses_ToolHelp() {
    std::vector<PROCESS_INFO> processes;
    
    // 创建进程快照
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnapshot == INVALID_HANDLE_VALUE) {
        return processes;
    }
    
    PROCESSENTRY32 pe = { sizeof(PROCESSENTRY32) };
    
    // 获取第一个进程
    if (Process32First(hSnapshot, &pe)) {
        do {
            PROCESS_INFO info;
            info.pid = pe.th32ProcessID;
            info.parentPid = pe.th32ParentProcessID;
            info.threadCount = pe.cntThreads;
            info.priority = pe.pcPriClassBase;
            info.exeName = pe.szExeFile;
            
            // 尝试获取完整路径
            HANDLE hProcess = OpenProcess(
                PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 
                FALSE, pe.th32ProcessID);
            
            if (hProcess) {
                char path[MAX_PATH];
                DWORD size = MAX_PATH;
                if (QueryFullProcessImageNameA(hProcess, 0, path, &size)) {
                    info.fullPath = path;
                }
                CloseHandle(hProcess);
            }
            
            processes.push_back(info);
        } while (Process32Next(hSnapshot, &pe));
    }
    
    CloseHandle(hSnapshot);
    return processes;
}

// 方法2: PSAPI枚举
std::vector<PROCESS_INFO> EnumProcesses_PSAPI() {
    std::vector<PROCESS_INFO> processes;
    
    DWORD pids[1024];
    DWORD bytesReturned;
    
    // 获取PID列表
    if (!EnumProcesses(pids, sizeof(pids), &bytesReturned)) {
        return processes;
    }
    
    DWORD count = bytesReturned / sizeof(DWORD);
    
    for (DWORD i = 0; i < count; i++) {
        if (pids[i] == 0) continue;
        
        PROCESS_INFO info;
        info.pid = pids[i];
        
        // 打开进程获取更多信息
        HANDLE hProcess = OpenProcess(
            PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
            FALSE, pids[i]);
        
        if (hProcess) {
            // 获取可执行文件名
            char name[MAX_PATH];
            if (GetModuleBaseNameA(hProcess, NULL, name, MAX_PATH)) {
                info.exeName = name;
            }
            
            // 获取完整路径
            char path[MAX_PATH];
            DWORD size = MAX_PATH;
            if (QueryFullProcessImageNameA(hProcess, 0, path, &size)) {
                info.fullPath = path;
            }
            
            // 获取父进程和线程信息(需要Native API)
            info.parentPid = 0;
            info.threadCount = 0;
            info.priority = 0;
            
            CloseHandle(hProcess);
        } else {
            // 权限不足,但仍记录PID
            info.exeName = "Access Denied";
        }
        
        processes.push_back(info);
    }
    
    return processes;
}

// 方法3: 获取进程详细信息
PROCESS_INFO GetProcessDetails(DWORD pid) {
    PROCESS_INFO info = {0};
    info.pid = pid;
    
    HANDLE hProcess = OpenProcess(
        PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
        FALSE, pid);
    
    if (!hProcess) {
        info.exeName = "Access Denied";
        return info;
    }
    
    // 可执行文件名
    char name[MAX_PATH];
    if (GetModuleBaseNameA(hProcess, NULL, name, MAX_PATH)) {
        info.exeName = name;
    }
    
    // 完整路径
    char path[MAX_PATH];
    DWORD size = MAX_PATH;
    if (QueryFullProcessImageNameA(hProcess, 0, path, &size)) {
        info.fullPath = path;
    }
    
    // 进程内存信息
    PROCESS_MEMORY_COUNTERS pmc;
    if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) {
        // 可以添加内存使用信息
    }
    
    CloseHandle(hProcess);
    return info;
}

// 方法4: 获取父进程信息
DWORD GetParentProcessId(DWORD pid) {
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnapshot == INVALID_HANDLE_VALUE) return 0;
    
    PROCESSENTRY32 pe = { sizeof(PROCESSENTRY32) };
    
    if (Process32First(hSnapshot, &pe)) {
        do {
            if (pe.th32ProcessID == pid) {
                CloseHandle(hSnapshot);
                return pe.th32ParentProcessID;
            }
        } while (Process32Next(hSnapshot, &pe));
    }
    
    CloseHandle(hSnapshot);
    return 0;
}

// 格式化输出进程列表
void PrintProcessList(const std::vector<PROCESS_INFO>& processes) {
    printf("\n%-8s %-8s %-6s %-20s %s\n", 
           "PID", "PPID", "Threads", "Name", "Path");
    printf("----------------------------------------------------------------\n");
    
    for (const auto& proc : processes) {
        printf("%-8lu %-8lu %-6lu %-20s %s\n",
            proc.pid,
            proc.parentPid,
            proc.threadCount,
            proc.exeName.c_str(),
            proc.fullPath.c_str());
    }
    printf("\nTotal: %zu processes\n", processes.size());
}

// 搜索特定进程
std::vector<PROCESS_INFO> FindProcessesByName(
    const std::vector<PROCESS_INFO>& processes, 
    const std::string& name) {
    
    std::vector<PROCESS_INFO> result;
    for (const auto& proc : processes) {
        if (_stricmp(proc.exeName.c_str(), name.c_str()) == 0) {
            result.push_back(proc);
        }
    }
    return result;
}

// 获取系统进程数
DWORD GetProcessCount() {
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnapshot == INVALID_HANDLE_VALUE) return 0;
    
    DWORD count = 0;
    PROCESSENTRY32 pe = { sizeof(PROCESSENTRY32) };
    
    if (Process32First(hSnapshot, &pe)) {
        do {
            count++;
        } while (Process32Next(hSnapshot, &pe));
    }
    
    CloseHandle(hSnapshot);
    return count;
}

// 测试函数
void TestProcessEnumeration() {
    printf("=== Process Enumeration Test ===\n\n");
    
    // 方法1测试
    printf("[*] Using ToolHelp32:\n");
    auto processes1 = EnumProcesses_ToolHelp();
    printf("Found %zu processes\n", processes1.size());
    
    // 显示前10个进程
    size_t showCount = min(10, processes1.size());
    for (size_t i = 0; i < showCount; i++) {
        printf("  [%lu] %s\n", 
            processes1[i].pid, processes1[i].exeName.c_str());
    }
    
    if (processes1.size() > showCount) {
        printf("  ... and %zu more\n", processes1.size() - showCount);
    }
    
    // 搜索特定进程
    auto explorers = FindProcessesByName(processes1, "explorer.exe");
    printf("\n[*] Found %zu explorer processes:\n", explorers.size());
    for (const auto& exp : explorers) {
        printf("  PID: %lu, Path: %s\n", exp.pid, exp.fullPath.c_str());
    }
    
    // 系统信息
    printf("\n[*] System Info:\n");
    printf("  Total processes: %lu\n", GetProcessCount());
}

// 远程控制集成
std::string GetProcessListAsString() {
    auto processes = EnumProcesses_ToolHelp();
    
    std::string result;
    char buffer[1024];
    
    sprintf_s(buffer, "%-8s %-20s %s\n", "PID", "Name", "Path");
    result += buffer;
    sprintf_s(buffer, "----------------------------------------\n");
    result += buffer;
    
    for (const auto& proc : processes) {
        sprintf_s(buffer, "%-8lu %-20s %s\n",
            proc.pid,
            proc.exeName.c_str(),
            proc.fullPath.c_str());
        result += buffer;
    }
    
    return result;
}

int main() {
    printf("========================================\n");
    printf("     Process Information Enumerator     \n");
    printf("========================================\n");
    
    TestProcessEnumeration();
    
    // 演示字符串输出(用于网络传输)
    printf("\n=== Formatted Output ===\n");
    std::string formatted = GetProcessListAsString();
    printf("%s", formatted.c_str());
    
    return 0;
}

2. 高级进程信息获取

// advanced_process.cpp
// 高级进程信息获取

#include <windows.h>
#include <tlhelp32.h>
#include <psapi.h>
#include <winternl.h>
#include <stdio.h>

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

// 进程内存信息
typedef struct _PROCESS_MEMORY_INFO {
    SIZE_T workingSetSize;
    SIZE_T peakWorkingSetSize;
    SIZE_T pageFaultCount;
    SIZE_T quotaPeakPagedPoolUsage;
    SIZE_T quotaPagedPoolUsage;
    SIZE_T quotaPeakNonPagedPoolUsage;
    SIZE_T quotaNonPagedPoolUsage;
    SIZE_T pagefileUsage;
    SIZE_T peakPagefileUsage;
} PROCESS_MEMORY_INFO, *PPROCESS_MEMORY_INFO;

// 获取进程内存信息
bool GetProcessMemoryInfoEx(DWORD pid, PPROCESS_MEMORY_INFO memInfo) {
    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
    if (!hProcess) return false;
    
    PROCESS_MEMORY_COUNTERS_EX pmc = { sizeof(PROCESS_MEMORY_COUNTERS_EX) };
    bool result = GetProcessMemoryInfo(hProcess, (PPROCESS_MEMORY_COUNTERS)&pmc, sizeof(pmc));
    
    if (result) {
        memInfo->workingSetSize = pmc.WorkingSetSize;
        memInfo->peakWorkingSetSize = pmc.PeakWorkingSetSize;
        memInfo->pageFaultCount = pmc.PageFaultCount;
        memInfo->quotaPeakPagedPoolUsage = pmc.QuotaPeakPagedPoolUsage;
        memInfo->quotaPagedPoolUsage = pmc.QuotaPagedPoolUsage;
        memInfo->quotaPeakNonPagedPoolUsage = pmc.QuotaPeakNonPagedPoolUsage;
        memInfo->quotaNonPagedPoolUsage = pmc.QuotaNonPagedPoolUsage;
        memInfo->pagefileUsage = pmc.PagefileUsage;
        memInfo->peakPagefileUsage = pmc.PeakPagefileUsage;
    }
    
    CloseHandle(hProcess);
    return result;
}

// 获取进程时间信息
bool GetProcessTimesEx(DWORD pid, FILETIME* createTime, FILETIME* exitTime,
                       FILETIME* kernelTime, FILETIME* userTime) {
    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
    if (!hProcess) return false;
    
    bool result = GetProcessTimes(hProcess, createTime, exitTime, kernelTime, userTime);
    CloseHandle(hProcess);
    return result;
}

// 获取进程优先级
DWORD GetProcessPriority(DWORD pid) {
    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
    if (!hProcess) return 0;
    
    DWORD priority = GetPriorityClass(hProcess);
    CloseHandle(hProcess);
    return priority;
}

// 检查进程是否64位
bool IsProcess64Bit(DWORD pid) {
    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
    if (!hProcess) return false;
    
    BOOL isWow64 = FALSE;
    IsWow64Process(hProcess, &isWow64);
    CloseHandle(hProcess);
    
    // 如果是Wow64,则是32位进程在64位系统上运行
    return !isWow64 && sizeof(void*) == 8;
}

// 获取进程命令行
std::string GetProcessCommandLine(DWORD pid) {
    HANDLE hProcess = OpenProcess(
        PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
    if (!hProcess) return "";
    
    // 这需要读取PEB和RTL_USER_PROCESS_PARAMETERS
    // 实现较为复杂,这里简化处理
    
    CloseHandle(hProcess);
    return "Not implemented";
}

// 进程完整性级别
typedef enum _INTEGRITY_LEVEL {
    UnknownIntegrity,
    LowIntegrity,
    MediumIntegrity,
    HighIntegrity,
    SystemIntegrity
} INTEGRITY_LEVEL;

INTEGRITY_LEVEL GetProcessIntegrityLevel(DWORD pid) {
    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
    if (!hProcess) return UnknownIntegrity;
    
    HANDLE hToken;
    if (!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) {
        CloseHandle(hProcess);
        return UnknownIntegrity;
    }
    
    DWORD tokenInfoLength = 0;
    GetTokenInformation(hToken, TokenIntegrityLevel, NULL, 0, &tokenInfoLength);
    
    PTOKEN_MANDATORY_LABEL tokenLabel = (PTOKEN_MANDATORY_LABEL)malloc(tokenInfoLength);
    if (!GetTokenInformation(hToken, TokenIntegrityLevel, tokenLabel, 
                            tokenInfoLength, &tokenInfoLength)) {
        free(tokenLabel);
        CloseHandle(hToken);
        CloseHandle(hProcess);
        return UnknownIntegrity;
    }
    
    DWORD integrityLevel = *GetSidSubAuthority(tokenLabel->Label.Sid, 
                                             (DWORD)(UCHAR)(*GetSidSubAuthorityCount(tokenLabel->Label.Sid) - 1));
    
    free(tokenLabel);
    CloseHandle(hToken);
    CloseHandle(hProcess);
    
    if (integrityLevel < SECURITY_MANDATORY_MEDIUM_RID) {
        return LowIntegrity;
    } else if (integrityLevel < SECURITY_MANDATORY_HIGH_RID) {
        return MediumIntegrity;
    } else if (integrityLevel < SECURITY_MANDATORY_SYSTEM_RID) {
        return HighIntegrity;
    } else {
        return SystemIntegrity;
    }
}

// 完整进程信息结构
typedef struct _FULL_PROCESS_INFO {
    DWORD pid;
    DWORD parentPid;
    std::string exeName;
    std::string fullPath;
    PROCESS_MEMORY_INFO memory;
    FILETIME createTime;
    DWORD priority;
    bool is64Bit;
    INTEGRITY_LEVEL integrity;
} FULL_PROCESS_INFO;

// 获取完整进程信息
FULL_PROCESS_INFO GetFullProcessInfo(DWORD pid) {
    FULL_PROCESS_INFO info = {0};
    info.pid = pid;
    
    // 基本信息
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnapshot != INVALID_HANDLE_VALUE) {
        PROCESSENTRY32 pe = { sizeof(PROCESSENTRY32) };
        if (Process32First(hSnapshot, &pe)) {
            do {
                if (pe.th32ProcessID == pid) {
                    info.parentPid = pe.th32ParentProcessID;
                    info.exeName = pe.szExeFile;
                    break;
                }
            } while (Process32Next(hSnapshot, &pe));
        }
        CloseHandle(hSnapshot);
    }
    
    // 完整路径
    HANDLE hProcess = OpenProcess(
        PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
    if (hProcess) {
        char path[MAX_PATH];
        DWORD size = MAX_PATH;
        if (QueryFullProcessImageNameA(hProcess, 0, path, &size)) {
            info.fullPath = path;
        }
        CloseHandle(hProcess);
    }
    
    // 内存信息
    GetProcessMemoryInfoEx(pid, &info.memory);
    
    // 创建时间
    GetProcessTimesEx(pid, &info.createTime, NULL, NULL, NULL);
    
    // 优先级
    info.priority = GetProcessPriority(pid);
    
    // 架构
    info.is64Bit = IsProcess64Bit(pid);
    
    // 完整性级别
    info.integrity = GetProcessIntegrityLevel(pid);
    
    return info;
}

void PrintFullProcessInfo(const FULL_PROCESS_INFO& info) {
    printf("\n=== Process Details ===\n");
    printf("PID: %lu\n", info.pid);
    printf("Parent PID: %lu\n", info.parentPid);
    printf("Name: %s\n", info.exeName.c_str());
    printf("Path: %s\n", info.fullPath.c_str());
    printf("Architecture: %s\n", info.is64Bit ? "64-bit" : "32-bit");
    printf("Priority: 0x%lX\n", info.priority);
    
    const char* integrityNames[] = {
        "Unknown", "Low", "Medium", "High", "System"
    };
    printf("Integrity: %s\n", integrityNames[info.integrity]);
    
    printf("Memory Usage: %llu KB\n", info.memory.workingSetSize / 1024);
}

int main() {
    printf("========================================\n");
    printf("     Advanced Process Information       \n");
    printf("========================================\n");
    
    // 获取当前进程信息
    FULL_PROCESS_INFO info = GetFullProcessInfo(GetCurrentProcessId());
    PrintFullProcessInfo(info);
    
    return 0;
}

3、课后作业

3.1、作业1:实现进程树显示

显示进程父子关系的树状结构。

3.2、作业2:添加进程监控功能

实时监控进程创建和退出事件。

3.3、作业3:进程权限分析

分析各进程的访问令牌和权限。