远程控制开发基础
2、客户端进程信息获取
1、课程目标
- 掌握Windows进程枚举技术
- 实现进程列表获取功能
- 获取进程详细信息(路径、PID等)
- 理解进程权限和访问控制
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:进程权限分析
分析各进程的访问令牌和权限。