SetExceptionBPX C0000005, 1
SetExceptionBPX C000001D, 1
SetExceptionBPX C0000096, 1
SetExceptionBPX 80000003, 1
SetExceptionBPX 80000004, 1
SetExceptionBPX C0000005, 1
SetExceptionBPX C000001D, 1
SetExceptionBPX C0000096, 1
SetExceptionBPX 80000003, 1
SetExceptionBPX 80000004, 1
WriteProcessMemory 是一个 Windows API 函数,允许一个进程向另一个进程的内存空间写入数据。这是进程间通信和内存操作的关键函数。
// 就像给邻居家送包裹 你的进程.写内存(邻居家进程, 邻居家地址, 你的数据, 数据大小); // 需要邻居家的"门牌号"和"门禁权限"
BOOL WriteProcessMemory( HANDLE hProcess, // [目标进程] - 要写入的进程句柄 LPVOID lpBaseAddress, // [目标地址] - 要写入的内存地址 LPCVOID lpBuffer, // [数据源] - 包含数据的缓冲区 SIZE_T nSize, // [数据大小] - 要写入的字节数 SIZE_T *lpNumberOfBytesWritten // [实际写入] - 实际写入的字节数 );
hProcess – 目标进程句柄// 必须具有 PROCESS_VM_WRITE 和 PROCESS_VM_OPERATION 权限 HANDLE hProcess = OpenProcess( PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, // 不继承句柄 targetPID // 目标进程ID );
lpBaseAddress – 目标内存地址// 必须是目标进程中有效的可写地址 // 通常通过以下方式获得: LPVOID remoteAddr = VirtualAllocEx(hProcess, NULL, size, MEM_COMMIT, PAGE_READWRITE); // 或者写入已知的固定地址
lpBuffer – 源数据缓冲区// 当前进程中的数据,可以是任何类型 char data[] = "Hello from another process!"; int value = 12345; BYTE shellcode[] = { 0x90, 0x90, 0xC3 }; // NOP, NOP, RET
nSize – 要写入的大小// 要写入的字节数,不能超过缓冲区大小 DWORD size = strlen(data) + 1; // 包括字符串结束符
lpNumberOfBytesWritten – 实际写入大小// 输出参数,接收实际写入的字节数 SIZE_T bytesWritten;
#include <windows.h> #include <iostream> void DemoBasicWriteProcessMemory() { std::cout << "📝 WriteProcessMemory 基础示例" << std::endl; // 1. 打开目标进程(比如记事本) DWORD targetPID = 1234; // 替换为实际PID HANDLE hProcess = OpenProcess( PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, targetPID ); if (hProcess == NULL) { std::cout << "❌ 无法打开目标进程" << std::endl; return; } // 2. 在目标进程分配内存 LPVOID remoteMemory = VirtualAllocEx( hProcess, NULL, 1024, // 1KB MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE ); if (remoteMemory == NULL) { std::cout << "❌ 无法在目标进程分配内存" << std::endl; CloseHandle(hProcess); return; } std::cout << "✅ 在目标进程分配内存: " << remoteMemory << std::endl; // 3. 准备要写入的数据 const char* message = "Hello from WriteProcessMemory!"; SIZE_T messageSize = strlen(message) + 1; // 包括null终止符 // 4. 写入数据到目标进程 SIZE_T bytesWritten; BOOL success = WriteProcessMemory( hProcess, // 目标进程 remoteMemory, // 目标地址 message, // 源数据 messageSize, // 数据大小 &bytesWritten // 实际写入字节数 ); if (success && bytesWritten == messageSize) { std::cout << "✅ 成功写入 " << bytesWritten << " 字节到目标进程" << std::endl; // 验证写入(可选 - 需要读取权限) char verifyBuffer[1024]; SIZE_T bytesRead; if (ReadProcessMemory(hProcess, remoteMemory, verifyBuffer, messageSize, &bytesRead)) { std::cout << "验证读取: " << verifyBuffer << std::endl; } } else { std::cout << "❌ 写入失败" << std::endl; if (GetLastError() == ERROR_PARTIAL_COPY) { std::cout << "错误: 部分拷贝 - 可能是地址无效" << std::endl; } } // 5. 清理资源 VirtualFreeEx(hProcess, remoteMemory, 0, MEM_RELEASE); CloseHandle(hProcess); }
#include <windows.h> BOOL InjectShellcode(DWORD targetPID, BYTE* shellcode, SIZE_T shellcodeSize) { std::cout << "🎯 Shellcode 注入示例" << std::endl; // 1. 打开目标进程 HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, // 需要所有权限 FALSE, targetPID ); if (!hProcess) { std::cout << "❌ 无法打开目标进程" << std::endl; return FALSE; } // 2. 在目标进程分配可读写内存 LPVOID remoteMemory = VirtualAllocEx( hProcess, NULL, shellcodeSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE // 初始为可读写 ); if (!remoteMemory) { std::cout << "❌ 内存分配失败" << std::endl; CloseHandle(hProcess); return FALSE; } std::cout << "✅ 分配远程内存: " << remoteMemory << std::endl; // 3. 写入 Shellcode SIZE_T bytesWritten; BOOL writeSuccess = WriteProcessMemory( hProcess, remoteMemory, shellcode, shellcodeSize, &bytesWritten ); if (!writeSuccess || bytesWritten != shellcodeSize) { std::cout << "❌ Shellcode 写入失败" << std::endl; VirtualFreeEx(hProcess, remoteMemory, 0, MEM_RELEASE); CloseHandle(hProcess); return FALSE; } std::cout << "✅ Shellcode 写入成功: " << bytesWritten << " 字节" << std::endl; // 4. 修改内存权限为可执行 DWORD oldProtect; BOOL protectSuccess = VirtualProtectEx( hProcess, remoteMemory, shellcodeSize, PAGE_EXECUTE_READ, // 改为可执行 &oldProtect ); if (!protectSuccess) { std::cout << "❌ 内存权限修改失败" << std::endl; VirtualFreeEx(hProcess, remoteMemory, 0, MEM_RELEASE); CloseHandle(hProcess); return FALSE; } std::cout << "✅ 内存权限改为可执行" << std::endl; // 5. 创建远程线程执行 Shellcode HANDLE hThread = CreateRemoteThread( hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)remoteMemory, NULL, 0, NULL ); if (!hThread) { std::cout << "❌ 远程线程创建失败" << std::endl; VirtualFreeEx(hProcess, remoteMemory, 0, MEM_RELEASE); CloseHandle(hProcess); return FALSE; } std::cout << "🎉 Shellcode 注入成功!" << std::endl; // 6. 等待线程完成(可选) WaitForSingleObject(hThread, INFINITE); // 7. 清理资源 CloseHandle(hThread); VirtualFreeEx(hProcess, remoteMemory, 0, MEM_RELEASE); CloseHandle(hProcess); return TRUE; }
#include <windows.h> #include <tlhelp32.h> BOOL ModifyProcessMemory(DWORD targetPID, LPVOID targetAddress, int newValue) { std::cout << "🔧 修改进程内存数据示例" << std::endl; // 1. 打开目标进程(只需要写入权限) HANDLE hProcess = OpenProcess( PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, targetPID ); if (!hProcess) { std::cout << "❌ 无法打开目标进程" << std::endl; return FALSE; } // 2. 检查目标地址是否可写 MEMORY_BASIC_INFORMATION mbi; if (VirtualQueryEx(hProcess, targetAddress, &mbi, sizeof(mbi))) { if (!(mbi.Protect & (PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READWRITE))) { std::cout << "❌ 目标内存不可写,当前保护: " << mbi.Protect << std::endl; // 尝试修改内存保护 DWORD oldProtect; if (VirtualProtectEx(hProcess, targetAddress, sizeof(newValue), PAGE_READWRITE, &oldProtect)) { std::cout << "✅ 临时修改内存保护为可写" << std::endl; } else { CloseHandle(hProcess); return FALSE; } } } // 3. 写入新值 SIZE_T bytesWritten; BOOL success = WriteProcessMemory( hProcess, targetAddress, &newValue, sizeof(newValue), &bytesWritten ); if (success && bytesWritten == sizeof(newValue)) { std::cout << "✅ 成功修改内存值: " << targetAddress << " -> " << newValue << std::endl; } else { std::cout << "❌ 内存修改失败" << std::endl; } CloseHandle(hProcess); return success; }
BOOL SafeWriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize) { SIZE_T bytesWritten; BOOL success = WriteProcessMemory(hProcess, lpBaseAddress, lpBuffer, nSize, &bytesWritten); if (!success) { DWORD error = GetLastError(); switch (error) { case ERROR_ACCESS_DENIED: std::cout << "❌ 访问被拒绝 - 权限不足" << std::endl; break; case ERROR_INVALID_HANDLE: std::cout << "❌ 无效的进程句柄" << std::endl; break; case ERROR_PARTIAL_COPY: std::cout << "❌ 部分拷贝 - 地址范围无效" << std::endl; break; case ERROR_WRITE_FAULT: std::cout << "❌ 写入错误 - 内存不可写" << std::endl; break; default: std::cout << "❌ 未知错误: " << error << std::endl; } return FALSE; } if (bytesWritten != nSize) { std::cout << "⚠️ 部分写入: " << bytesWritten << "/" << nSize << " 字节" << std::endl; return FALSE; } return TRUE; }
BOOL CheckProcessAccess(HANDLE hProcess) { // 尝试读取进程基本信息来验证访问权限 DWORD exitCode; return GetExitCodeProcess(hProcess, &exitCode); } BOOL CanWriteToProcess(DWORD pid) { HANDLE hProcess = OpenProcess(PROCESS_VM_WRITE, FALSE, pid); if (hProcess) { CloseHandle(hProcess); return TRUE; } return FALSE; }
class GameHacker { HANDLE hGameProcess; DWORD gamePID; public: BOOL Initialize(DWORD pid) { gamePID = pid; hGameProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); return hGameProcess != NULL; } BOOL WriteInt(LPVOID address, int value) { SIZE_T bytesWritten; return WriteProcessMemory(hGameProcess, address, &value, sizeof(value), &bytesWritten); } BOOL WriteFloat(LPVOID address, float value) { SIZE_T bytesWritten; return WriteProcessMemory(hGameProcess, address, &value, sizeof(value), &bytesWritten); } BOOL WriteBytes(LPVOID address, BYTE* data, SIZE_T size) { SIZE_T bytesWritten; return WriteProcessMemory(hGameProcess, address, data, size, &bytesWritten); } };
class Debugger { HANDLE hDebugee; public: BOOL SetBreakpoint(LPVOID address, BYTE originalByte) { BYTE int3 = 0xCC; // INT 3 断点指令 // 备份原始字节 SIZE_T bytesWritten; BOOL success = WriteProcessMemory(hDebugee, address, &int3, 1, &bytesWritten); if (success) { // 保存原始字节以便恢复 breakpoints[address] = originalByte; } return success; } BOOL RestoreByte(LPVOID address) { auto it = breakpoints.find(address); if (it != breakpoints.end()) { SIZE_T bytesWritten; return WriteProcessMemory(hDebugee, address, &it->second, 1, &bytesWritten); } return FALSE; } };
BOOL PatchProcessFunction(DWORD pid, LPVOID functionAddress, BYTE* patch, SIZE_T patchSize) { HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); if (!hProcess) return FALSE; // 修改内存保护为可写 DWORD oldProtect; if (!VirtualProtectEx(hProcess, functionAddress, patchSize, PAGE_EXECUTE_READWRITE, &oldProtect)) { CloseHandle(hProcess); return FALSE; } // 应用补丁 SIZE_T bytesWritten; BOOL success = WriteProcessMemory(hProcess, functionAddress, patch, patchSize, &bytesWritten); // 恢复原始保护 VirtualProtectEx(hProcess, functionAddress, patchSize, oldProtect, &oldProtect); CloseHandle(hProcess); return success && (bytesWritten == patchSize); }
// 安全软件可以监控可疑的 WriteProcessMemory 调用 BOOL IsSuspiciousWriteOperation(HANDLE hProcess, LPVOID lpBaseAddress, SIZE_T nSize) { // 检查目标进程 if (IsSystemProcess(hProcess)) { return TRUE; // 向系统进程写入可疑 } // 检查目标地址 if (IsCodeSectionAddress(hProcess, lpBaseAddress)) { return TRUE; // 向代码段写入可疑 } // 检查写入大小 if (nSize > 0x10000) { // 大于64KB return TRUE; // 大块写入可疑 } return FALSE; }
class AntiInjection { public: static BOOL ProtectProcess() { // 使用 Process Protection 防止外部写入 return SetProcessMitigationPolicy(ProcessSignaturePolicy, &policy, sizeof(policy)); } static BOOL MonitorMemoryWrites() { // 定期检查进程内存是否被修改 return SetupMemoryIntegrityCheck(); } };
BOOL WriteMultipleRegions(HANDLE hProcess, const std::vector<std::pair<LPVOID, std::vector<BYTE>>>& regions) { for (const auto& region : regions) { LPVOID address = region.first; const std::vector<BYTE>& data = region.second; SIZE_T bytesWritten; if (!WriteProcessMemory(hProcess, address, data.data(), data.size(), &bytesWritten)) { return FALSE; } } return TRUE; }
跨进程操作:允许一个进程修改另一个进程的内存
权限要求:需要 PROCESS_VM_WRITE 和 PROCESS_VM_OPERATION 权限
地址有效性:目标地址必须在目标进程的地址空间内且可写
错误处理:必须检查返回值和实际写入字节数
✅ 合法用途:调试器、性能分析工具、系统维护工具
⚠️ 灰色地带:游戏修改器、自动化工具
❌ 恶意用途:病毒、木马、恶意软件注入
// 标准写入流程: 1. OpenProcess() // 打开目标进程 2. VirtualAllocEx() // 分配目标内存(如需要) 3. VirtualProtectEx() // 确保内存可写(如需要) 4. WriteProcessMemory() // 执行写入 5. 验证结果和清理资源
记住:能力越大,责任越大! WriteProcessMemory 是一个强大的系统级函数,必须谨慎合法地使用。
| 特性 | OpenProcess | CreateProcess |
|---|---|---|
| 核心功能 | 打开已存在的进程 | 创建新的进程 |
| 目标对象 | 运行中的进程 | 可执行文件 |
| 返回值 | 进程句柄 | 进程和线程句柄 |
| 使用场景 | 进程操作、注入、监控 | 程序启动、子进程创建 |
// 就像获取已开业公司的管理权限 HANDLE OpenProcess( DWORD dwDesiredAccess, // [访问权限] - 需要的操作权限 BOOL bInheritHandle, // [继承选项] - 子进程是否继承句柄 DWORD dwProcessId // [公司ID] - 目标进程ID );
// 就像创办一家新公司 BOOL CreateProcess( LPCTSTR lpApplicationName, // [公司名称] - 可执行文件路径 LPTSTR lpCommandLine, // [经营指令] - 命令行参数 LPSECURITY_ATTRIBUTES lpProcessAttributes, // [公司规章] - 进程安全属性 LPSECURITY_ATTRIBUTES lpThreadAttributes, // [员工规章] - 线程安全属性 BOOL bInheritHandles, // [继承资产] - 继承句柄 DWORD dwCreationFlags, // [创立方式] - 创建标志 LPVOID lpEnvironment, // [办公环境] - 环境变量 LPCTSTR lpCurrentDirectory, // [办公地点] - 当前目录 LPSTARTUPINFO lpStartupInfo, // [开业信息] - 启动信息 LPPROCESS_INFORMATION lpProcessInformation // [公司档案] - 进程信息 );
// 你是一个投资者,想接管一家已存在的公司 公司句柄 = 接管公司(公司ID, 管理权限, 是否允许继承); // 公司已经存在,你只是获取管理权
// 你是一个创业者,要创办全新的公司 创办公司(公司名称, 经营计划, 公司章程, 员工制度, 继承资产, 创立方式, 办公环境, 办公地点, 开业筹备, 公司档案); // 从零开始创建全新的公司
#include <windows.h> #include <iostream> #include <tlhelp32.h> // 查找进程ID DWORD FindProcessId(const wchar_t* processName) { HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); PROCESSENTRY32 pe32; pe32.dwSize = sizeof(PROCESSENTRY32); if (Process32First(hSnapshot, &pe32)) { do { if (wcscmp(pe32.szExeFile, processName) == 0) { CloseHandle(hSnapshot); return pe32.th32ProcessID; } } while (Process32Next(hSnapshot, &pe32)); } CloseHandle(hSnapshot); return 0; } void DemoOpenProcess() { std::cout << "🔑 OpenProcess 示例:打开现有进程" << std::endl; // 1. 查找目标进程(比如记事本) DWORD notepadPID = FindProcessId(L"notepad.exe"); if (notepadPID == 0) { std::cout << "❌ 找不到记事本进程" << std::endl; return; } std::cout << "✅ 找到记事本进程,PID: " << notepadPID << std::endl; // 2. 打开进程(获取公司管理权) HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, // 需要所有权限 FALSE, // 子进程不继承句柄 notepadPID // 目标进程ID ); if (hProcess == NULL) { DWORD error = GetLastError(); std::cout << "❌ 打开进程失败,错误码: " << error << std::endl; if (error == ERROR_ACCESS_DENIED) { std::cout << "💡 提示: 可能需要以管理员权限运行" << std::endl; } return; } std::cout << "🎯 成功打开进程,句柄: " << hProcess << std::endl; // 3. 使用句柄进行操作... // 例如:读取进程信息、注入代码、终止进程等 // 获取进程退出码(验证句柄有效) DWORD exitCode; if (GetExitCodeProcess(hProcess, &exitCode)) { if (exitCode == STILL_ACTIVE) { std::cout << "📊 进程正在运行中" << std::endl; } else { std::cout << "💀 进程已退出,代码: " << exitCode << std::endl; } } // 4. 关闭句柄(释放管理权) CloseHandle(hProcess); std::cout << "🗑️ 进程句柄已关闭" << std::endl; } // 不同权限级别的 OpenProcess 示例 void DemoDifferentAccessLevels() { std::cout << "\n🔐 不同权限级别的 OpenProcess 示例" << std::endl; DWORD targetPID = FindProcessId(L"notepad.exe"); if (targetPID == 0) return; // 方式1:只读权限(查看公司信息) HANDLE hReadOnly = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, targetPID); if (hReadOnly) { std::cout << "✅ 获取只读权限成功" << std::endl; // 可以查询进程信息,但不能修改 CloseHandle(hReadOnly); } // 方式2:终止权限(关闭公司) HANDLE hTerminate = OpenProcess(PROCESS_TERMINATE, FALSE, targetPID); if (hTerminate) { std::cout << "✅ 获取终止权限成功" << std::endl; // 可以终止进程:TerminateProcess(hTerminate, 0); CloseHandle(hTerminate); } // 方式3:内存操作权限(修改公司运营) HANDLE hMemory = OpenProcess( PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, targetPID ); if (hMemory) { std::cout << "✅ 获取内存操作权限成功" << std::endl; // 可以读写进程内存 CloseHandle(hMemory); } // 方式4:所有权限(完全控制) HANDLE hAllAccess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, targetPID); if (hAllAccess) { std::cout << "✅ 获取所有权限成功" << std::endl; // 可以执行任何操作 CloseHandle(hAllAccess); } }
#include <windows.h> #include <iostream> void DemoCreateProcess() { std::cout << "🚀 CreateProcess 示例:创建新进程" << std::endl; STARTUPINFO si = {0}; PROCESS_INFORMATION pi = {0}; si.cb = sizeof(si); // 必须设置结构体大小 // 1. 创建新进程(创办新公司) BOOL success = CreateProcess( NULL, // 使用命令行指定程序 "notepad.exe", // 命令行:启动记事本 NULL, // 进程安全属性(默认) NULL, // 线程安全属性(默认) FALSE, // 不继承句柄 0, // 无特殊创建标志 NULL, // 使用父进程环境变量 NULL, // 使用父进程当前目录 &si, // 启动信息 &pi // 进程信息(输出) ); if (!success) { std::cout << "❌ 创建进程失败,错误码: " << GetLastError() << std::endl; return; } std::cout << "🎉 成功创建新进程!" << std::endl; std::cout << "📊 进程ID: " << pi.dwProcessId << std::endl; std::cout << "📊 线程ID: " << pi.dwThreadId << std::endl; std::cout << "📊 进程句柄: " << pi.hProcess << std::endl; std::cout << "📊 线程句柄: " << pi.hThread << std::endl; // 2. 等待进程结束(可选) std::cout << "⏳ 等待进程结束..." << std::endl; WaitForSingleObject(pi.hProcess, INFINITE); // 3. 获取退出码 DWORD exitCode; GetExitCodeProcess(pi.hProcess, &exitCode); std::cout << "🏁 进程退出,代码: " << exitCode << std::endl; // 4. 关闭句柄(重要!) CloseHandle(pi.hProcess); CloseHandle(pi.hThread); std::cout << "🗑️ 句柄已关闭" << std::endl; } // 高级 CreateProcess 示例 void DemoAdvancedCreateProcess() { std::cout << "\n🎛️ 高级 CreateProcess 示例" << std::endl; STARTUPINFO si = {0}; PROCESS_INFORMATION pi = {0}; si.cb = sizeof(si); // 设置窗口显示方式 si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_SHOWMINIMIZED; // 最小化启动 // 创建进程(隐藏窗口启动计算器) BOOL success = CreateProcess( NULL, "calc.exe", // 启动计算器 NULL, NULL, FALSE, CREATE_NEW_CONSOLE, // 创建新控制台 NULL, NULL, &si, &pi ); if (success) { std::cout << "✅ 计算器已启动(最小化)" << std::endl; std::cout << "PID: " << pi.dwProcessId << std::endl; // 不等待,立即继续执行 CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } } // 创建挂起的进程(用于进程注入) void DemoCreateSuspendedProcess() { std::cout << "\n⏸️ 创建挂起的进程示例" << std::endl; STARTUPINFO si = {0}; PROCESS_INFORMATION pi = {0}; si.cb = sizeof(si); // 创建挂起的进程 BOOL success = CreateProcess( NULL, "notepad.exe", NULL, NULL, FALSE, CREATE_SUSPENDED, // 关键:创建后挂起 NULL, NULL, &si, &pi ); if (success) { std::cout << "✅ 已创建挂起的记事本进程" << std::endl; std::cout << "PID: " << pi.dwProcessId << std::endl; std::cout << "进程已创建但未执行,可以执行注入操作..." << std::endl; // 这里可以执行进程注入操作 // 例如:修改内存、注入DLL等 // 恢复进程执行 ResumeThread(pi.hThread); std::cout << "▶️ 进程已恢复执行" << std::endl; CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } }
// OpenProcess - 需要目标进程的访问权限 HANDLE hProcess = OpenProcess( PROCESS_VM_READ, // 只需要读取权限 FALSE, targetPID ); // CreateProcess - 需要文件执行权限 BOOL success = CreateProcess( "C:\\Program Files\\App\\app.exe", // 需要文件访问权限 NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi );
// OpenProcess 错误处理 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); if (hProcess == NULL) { DWORD error = GetLastError(); if (error == ERROR_ACCESS_DENIED) { // 权限不足 } else if (error == ERROR_INVALID_PARAMETER) { // 进程不存在 } } // CreateProcess 错误处理 if (!CreateProcess(NULL, "app.exe", NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { DWORD error = GetLastError(); if (error == ERROR_FILE_NOT_FOUND) { // 文件不存在 } else if (error == ERROR_ACCESS_DENIED) { // 访问被拒绝 } }
// OpenProcess - 只需要关闭一个句柄 HANDLE hProcess = OpenProcess(...); // 使用句柄... CloseHandle(hProcess); // CreateProcess - 需要关闭两个句柄 CreateProcess(..., &pi); // 使用句柄... CloseHandle(pi.hProcess); // 必须关闭 CloseHandle(pi.hThread); // 必须关闭
// 场景1:进程监控工具 class ProcessMonitor { public: BOOL MonitorProcess(DWORD pid) { HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); if (hProcess) { // 监控进程状态、内存使用等 MonitorProcessResources(hProcess); CloseHandle(hProcess); return TRUE; } return FALSE; } }; // 场景2:进程注入 class ProcessInjector { public: BOOL InjectDLL(DWORD targetPID, const char* dllPath) { HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, targetPID); if (!hProcess) return FALSE; // 执行注入操作... LPVOID remoteMem = VirtualAllocEx(hProcess, ...); WriteProcessMemory(hProcess, ...); CreateRemoteThread(hProcess, ...); CloseHandle(hProcess); return TRUE; } }; // 场景3:进程终止工具 BOOL TerminateProcessById(DWORD pid) { HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid); if (hProcess) { BOOL success = TerminateProcess(hProcess, 0); CloseHandle(hProcess); return success; } return FALSE; }
// 场景1:程序启动器 class ApplicationLauncher { public: BOOL LaunchApplication(const char* appPath, const char* parameters) { STARTUPINFO si = {0}; PROCESS_INFORMATION pi = {0}; si.cb = sizeof(si); string commandLine = string(appPath) + " " + (parameters ? parameters : ""); BOOL success = CreateProcess( NULL, (LPSTR)commandLine.c_str(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi ); if (success) { CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } return success; } }; // 场景2:服务进程管理 class ServiceManager { public: BOOL StartServiceProcess() { STARTUPINFO si = {0}; PROCESS_INFORMATION pi = {0}; si.cb = sizeof(si); // 以服务方式启动进程 return CreateProcess( "C:\\MyService\\service.exe", NULL, NULL, NULL, FALSE, CREATE_NO_WINDOW, // 无窗口 NULL, NULL, &si, &pi ); } }; // 场景3:进程空洞(Process Hollowing) class ProcessHollowing { public: BOOL HollowProcess(const char* targetExe, BYTE* maliciousCode, SIZE_T codeSize) { STARTUPINFO si = {0}; PROCESS_INFORMATION pi = {0}; si.cb = sizeof(si); // 创建挂起的进程 if (CreateProcess(targetExe, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) { // 在这里执行进程空洞操作 // 1. 获取线程上下文 // 2. 读取PE头 // 3. 卸载原始镜像 // 4. 分配新内存并写入恶意代码 // 5. 修改入口点 // 6. 恢复线程执行 ResumeThread(pi.hThread); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return TRUE; } return FALSE; } };
// 恶意使用示例:进程内存窃取 BOOL StealProcessMemory(DWORD targetPID) { HANDLE hProcess = OpenProcess(PROCESS_VM_READ, FALSE, targetPID); if (hProcess) { // 读取敏感数据 ReadProcessMemory(hProcess, sensitiveAddress, buffer, size, NULL); CloseHandle(hProcess); return TRUE; } return FALSE; } // 防御措施:进程保护 BOOL ProtectCurrentProcess() { // 使用进程保护策略限制 OpenProcess 访问 return SetProcessMitigationPolicy(ProcessSignaturePolicy, ...); }
// 恶意使用示例:恶意子进程创建 BOOL CreateMaliciousProcess() { // 启动恶意程序 return CreateProcess("malware.exe", NULL, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi); } // 防御措施:应用程序控制 // 使用 AppLocker、Windows Defender Application Control 等
// 场景:创建进程并监控它 class ProcessCreatorAndMonitor { public: BOOL CreateAndMonitor(const char* appPath) { STARTUPINFO si = {0}; PROCESS_INFORMATION pi = {0}; si.cb = sizeof(si); // 1. 创建进程 if (!CreateProcess(NULL, (LPSTR)appPath, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { return FALSE; } std::cout << "✅ 进程创建成功,PID: " << pi.dwProcessId << std::endl; // 2. 立即关闭不需要的句柄 CloseHandle(pi.hThread); // 3. 使用 OpenProcess 重新打开(为了特定权限) HANDLE hMonitorProcess = OpenProcess( PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, pi.dwProcessId ); if (hMonitorProcess) { // 4. 监控进程 MonitorProcess(hMonitorProcess); CloseHandle(hMonitorProcess); } CloseHandle(pi.hProcess); return TRUE; } private: void MonitorProcess(HANDLE hProcess) { // 等待进程结束 WaitForSingleObject(hProcess, INFINITE); DWORD exitCode; GetExitCodeProcess(hProcess, &exitCode); std::cout << "🏁 进程结束,退出码: " << exitCode << std::endl; } };
OpenProcess = 获取已存在公司的管理权限
CreateProcess = 创办全新公司并获取管理权
// 问自己:要操作现有进程还是创建新进程? if (需要操作正在运行的进程) { // 使用 OpenProcess HANDLE hProcess = OpenProcess(desiredAccess, FALSE, targetPID); } else if (需要启动新程序) { // 使用 CreateProcess CreateProcess(appName, commandLine, ..., &processInfo); }
目标对象:现有进程 vs 可执行文件
功能:获取句柄 vs 创建进程+获取句柄
复杂度:相对简单 vs 参数复杂
资源管理:单个句柄 vs 两个句柄
应用场景:进程操作 vs 程序启动
记住这个简单规则:
🔑 OpenProcess → 接管现有公司
🚀 CreateProcess → 创办全新公司
两者都是进程操作的核心API,理解它们的区别对于Windows系统编程至关重要!
// 1. 内存分配 VirtualAlloc/VirtualAllocEx() // 2. 内存写入 WriteProcessMemory() // 或直接内存操作 // 3. 权限修改 VirtualProtect/VirtualProtectEx() // 4. 代码执行 CreateThread/CreateRemoteThread() // 或 SetThreadContext() + ResumeThread() // 或 QueueUserAPC()
1.1 打开 API Monitor 并创建新过滤器
// 过滤器名称:Shellcode_Monitor // 包含以下关键 API 类别: - kernel32.dll 中的关键函数: ✓ VirtualAlloc ✓ VirtualAllocEx ✓ VirtualProtect ✓ VirtualProtectEx ✓ WriteProcessMemory ✓ CreateThread ✓ CreateRemoteThread ✓ SetThreadContext ✓ ResumeThread ✓ QueueUserAPC ✓ GetThreadContext - ntdll.dll 中的底层函数: ✓ NtAllocateVirtualMemory ✓ NtProtectVirtualMemory ✓ NtWriteVirtualMemory ✓ ZwCreateThreadEx - 其他相关函数: ✓ OpenProcess ✓ LoadLibraryA/W ✓ GetProcAddress
1.2 设置过滤器规则
// 在过滤器中设置: - 监控所有模块的上述函数 - 记录参数和返回值 - 启用堆栈跟踪 - 设置深度监控(Deep Monitor Mode)
2.1 启动监控会话
// 方法1:监控新启动的进程 File → Monitor New Process → 选择目标 EXE // 方法2:附加到运行中的进程 File → Monitor Running Process → 选择目标 PID
2.2 设置高级选项
// 在监控选项中启用: ✓ Monitor child processes // 监控子进程 ✓ Monitor DLL loads // 监控 DLL 加载 ✓ Monitor registry access // 监控注册表访问 ✓ Monitor file system // 监控文件系统操作 ✓ Capture stack traces // 捕获堆栈跟踪
<!-- 保存为: shellcode_monitor.apm --> <APIMonitor> <Filters> <Filter Name="Shellcode_APIs" Enabled="true"> <Include> <!-- 内存管理 API --> <API Module="kernel32.dll" Name="VirtualAlloc"/> <API Module="kernel32.dll" Name="VirtualAllocEx"/> <API Module="kernel32.dll" Name="VirtualFree"/> <API Module="kernel32.dll" Name="VirtualFreeEx"/> <!-- 内存保护 API --> <API Module="kernel32.dll" Name="VirtualProtect"/> <API Module="kernel32.dll" Name="VirtualProtectEx"/> <!-- 内存写入 API --> <API Module="kernel32.dll" Name="WriteProcessMemory"/> <API Module="kernel32.dll" Name="ReadProcessMemory"/> <!-- 线程操作 API --> <API Module="kernel32.dll" Name="CreateThread"/> <API Module="kernel32.dll" Name="CreateRemoteThread"/> <API Module="kernel32.dll" Name="SetThreadContext"/> <API Module="kernel32.dll" Name="GetThreadContext"/> <API Module="kernel32.dll" Name="ResumeThread"/> <API Module="kernel32.dll" Name="QueueUserAPC"/> <!-- 进程操作 API --> <API Module="kernel32.dll" Name="OpenProcess"/> <API Module="kernel32.dll" Name="CreateProcessA"/> <API Module="kernel32.dll" Name="CreateProcessW"/> <!-- DLL 操作 API --> <API Module="kernel32.dll" Name="LoadLibraryA"/> <API Module="kernel32.dll" Name="LoadLibraryW"/> <API Module="kernel32.dll" Name="GetProcAddress"/> <!-- 底层 NT API --> <API Module="ntdll.dll" Name="NtAllocateVirtualMemory"/> <API Module="ntdll.dll" Name="NtProtectVirtualMemory"/> <API Module="ntdll.dll" Name="NtWriteVirtualMemory"/> <API Module="ntdll.dll" Name="ZwCreateThreadEx"/> </Include> </Filter> </Filters> <Options> <Option Name="CaptureStackTraces" Value="true"/> <Option Name="DeepMonitor" Value="true"/> <Option Name="MonitorChildren" Value="true"/> </Options> </APIMonitor>
模式1:经典的 Shellcode 注入
// 预期的 API 调用序列: 1. OpenProcess() // 打开目标进程 2. VirtualAllocEx(PAGE_READWRITE) // 分配可读写内存 3. WriteProcessMemory() // 写入 shellcode 4. VirtualProtectEx(PAGE_EXECUTE) // 修改为可执行权限 5. CreateRemoteThread() // 执行 shellcode // 在 API Monitor 中查找这个调用序列
模式2:进程空洞(Process Hollowing)
// 预期的 API 调用序列: 1. CreateProcess(CREATE_SUSPENDED) // 创建挂起的进程 2. GetThreadContext() // 获取线程上下文 3. VirtualAllocEx() // 分配新内存 4. WriteProcessMemory() // 写入恶意代码 5. SetThreadContext() // 修改入口点 6. ResumeThread() // 恢复执行
模式3:APC 注入
// 预期的 API 调用序列: 1. OpenProcess() // 打开目标进程 2. VirtualAllocEx() // 分配内存 3. WriteProcessMemory() // 写入 shellcode 4. VirtualProtectEx() // 修改权限 5. QueueUserAPC() // 通过 APC 执行
分析 VirtualAlloc 调用:
// 关注这些参数: LPVOID VirtualAlloc( lpAddress, // 通常为 NULL(系统自动分配) dwSize, // 大小 - 可疑的大小(如 0x1000, 0x2000) flAllocationType, // MEM_COMMIT | MEM_RESERVE flProtect // 初始保护:PAGE_READWRITE(可疑) );
分析 VirtualProtect 调用:
// 特别关注权限变化: BOOL VirtualProtect( lpAddress, dwSize, flNewProtect, // 从 PAGE_READWRITE 变为 PAGE_EXECUTE_READ lpflOldProtect ); // 可疑模式:读写 → 可执行
分析 WriteProcessMemory 调用:
// 关注写入内容: BOOL WriteProcessMemory( hProcess, // 目标进程 lpBaseAddress, // 写入地址 lpBuffer, // 写入的数据(可能是加密的 shellcode) nSize, // 数据大小 lpNumberOfBytesWritten );
1. 准备监控环境
// 在 API Monitor 中: 1. 加载 shellcode_monitor.apm 配置文件 2. 设置输出文件:C:\monitor_results.log 3. 启用详细日志记录 4. 设置断点可疑的 API 组合
2. 启动监控
// 监控目标 EXE: File → Monitor New Process → 选择: C:\suspicious.exe 参数: (如有命令行参数) 工作目录: C:\
3. 实时分析技巧
// 在监控过程中关注: // 实时过滤器设置: Filter → Add Live Filter → 条件: (FunctionName contains "Virtual") OR (FunctionName contains "Write") OR (FunctionName contains "Thread") // 颜色高亮: 设置 VirtualAlloc → 黄色 设置 VirtualProtect → 红色 设置 CreateRemoteThread → 紫色
4. 事后分析脚本示例
# 分析 API Monitor 日志的 Python 脚本思路 import re def analyze_shellcode_pattern(log_file): patterns = { 'memory_allocation': r'VirtualAlloc.*dwSize=(0x[0-9A-F]+)', 'protection_change': r'VirtualProtect.*flNewProtect=(0x[0-9A-F]+)', 'remote_thread': r'CreateRemoteThread', 'memory_write': r'WriteProcessMemory.*nSize=([0-9]+)' } # 检测可疑序列 sequence = [] with open(log_file, 'r') as f: for line in f: for pattern_name, pattern in patterns.items(): if re.search(pattern, line): sequence.append(pattern_name) # 检查典型的 shellcode 模式 if ('memory_allocation' in sequence and 'memory_write' in sequence and 'protection_change' in sequence and 'remote_thread' in sequence): print("⚠️ 检测到可能的 Shellcode 注入行为!")
设置条件断点:
// 在 VirtualAlloc 上设置断点: 条件: dwSize > 0x1000 // 分配大于 4KB 内存时中断 // 在 VirtualProtect 上设置断点: 条件: flNewProtect == 0x20 // PAGE_EXECUTE_READ 时中断 // 在 CreateRemoteThread 上设置断点: 条件: 始终中断(监控所有远程线程创建)
配置内存转储:
// 在 API Monitor 选项中: ✓ Dump memory on WriteProcessMemory calls ✓ Dump memory on VirtualProtect calls ✓ Limit dump size: 4096 bytes // 避免转储过大 // 这样可以在 shellcode 被写入和权限更改时捕获其内容
启用详细堆栈跟踪:
// 在监控选项中: ✓ Capture stack traces for all APIs ✓ Maximum stack depth: 32 // 分析堆栈可以揭示: - 调用来源(哪个模块调用) - 调用链关系 - 可能的代码注入点
1. 导出调用序列
// 在 API Monitor 中: Reports → Generate Call Sequence Report 格式: HTML/XML/CSV 包含: 时间戳、参数、返回值、堆栈
2. 时间线分析
// 关注 API 调用时间间隔: VirtualAlloc → WriteProcessMemory → VirtualProtect → CreateThread // 正常程序:间隔较均匀 // Shellcode 注入:快速连续调用
3. 统计报告
// 生成统计信息: - 每个 API 的调用次数 - 内存分配总量 - 权限更改次数 - 线程创建统计
配置正确的过滤器 – 包含所有相关 API
关注调用序列 – 特别是内存分配→写入→权限更改→执行
分析参数模式 – 可疑的内存大小和权限变化
使用堆栈跟踪 – 确定调用来源
设置条件断点 – 在关键时刻中断分析
// 在 API Monitor 中看到的可疑模式: 1. 快速连续的内存操作 API 调用 2. 内存权限从读写变为可执行 3. 在非自身进程中创建线程 4. 写入的可执行代码块 5. 异常的 API 调用序列
通过精心配置 API Monitor,你可以有效地检测和分析 EXE 文件加载和执行 shellcode 的行为!
| 特性 | ReadFile | ReadFileEx |
|---|---|---|
| 操作模式 | 同步或异步 | 纯异步 |
| 完成通知 | 事件对象或阻塞等待 | 回调函数 |
| 线程要求 | 可阻塞线程 | 需要可警报状态线程 |
| 编程复杂度 | 相对简单 | 相对复杂但更高效 |
// 就像普通快递收货 - 可以等货到,也可以留地址后离开 BOOL ReadFile( HANDLE hFile, // [快递单号] - 文件句柄 LPVOID lpBuffer, // [收货箱] - 数据缓冲区 DWORD nNumberOfBytesToRead, // [预期数量] - 要读取的字节数 LPDWORD lpNumberOfBytesRead, // [实际数量] - 实际读取的字节数 LPOVERLAPPED lpOverlapped // [取货安排] - 重叠结构(用于异步) );
// 就像智能快递柜 - 货到后自动通知你 BOOL ReadFileEx( HANDLE hFile, // [快递单号] - 文件句柄 LPVOID lpBuffer, // [收货箱] - 数据缓冲区 DWORD nNumberOfBytesToRead, // [预期数量] - 要读取的字节数 LPOVERLAPPED lpOverlapped, // [取货安排] - 扩展重叠结构 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine // [通知方式] - 完成回调函数 );
// 方式1:同步 - 在家等快递 快递.取件(等待直到送达); // 阻塞等待 // 方式2:异步 - 留下取件码,时不时查看 快递.取件(留下取件码); while(!检查是否送达()) { 做其他事; } // 轮询检查
// 异步回调 - 快递放入柜子后自动发短信通知 快递.取件(放入快递柜, 短信通知我); // 你可以完全专注做其他事,收到通知再去取
#include <windows.h> #include <iostream> void DemoSyncReadFile() { std::cout << "📖 ReadFile 同步读取示例" << std::endl; // 1. 打开文件(同步方式) HANDLE hFile = CreateFile( L"example.txt", // 文件名 GENERIC_READ, // 只读 0, // 不共享 NULL, // 默认安全属性 OPEN_EXISTING, // 必须存在 FILE_ATTRIBUTE_NORMAL, // 普通文件 NULL ); if (hFile == INVALID_HANDLE_VALUE) { std::cout << "❌ 无法打开文件" << std::endl; return; } // 2. 准备缓冲区 char buffer[1024]; DWORD bytesRead; // 3. 同步读取 - 阻塞直到读取完成 BOOL success = ReadFile( hFile, // 文件句柄 buffer, // 缓冲区 sizeof(buffer) - 1, // 要读取的字节数 &bytesRead, // 实际读取的字节数 NULL // 同步操作,不需要OVERLAPPED ); if (success && bytesRead > 0) { buffer[bytesRead] = '\0'; // 添加字符串结束符 std::cout << "✅ 读取成功: " << bytesRead << " 字节" << std::endl; std::cout << "内容: " << buffer << std::endl; } else { std::cout << "❌ 读取失败" << std::endl; } // 4. 关闭文件 CloseHandle(hFile); }
#include <windows.h> #include <iostream> void DemoAsyncReadFile() { std::cout << "📖 ReadFile 异步读取示例" << std::endl; // 1. 打开文件(异步方式) HANDLE hFile = CreateFile( L"example.txt", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, // 关键:重叠I/O标志 NULL ); if (hFile == INVALID_HANDLE_VALUE) { std::cout << "❌ 无法打开文件" << std::endl; return; } // 2. 准备异步操作结构 OVERLAPPED overlapped = {0}; overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); char buffer[1024]; DWORD bytesRead; // 3. 发起异步读取 BOOL success = ReadFile( hFile, buffer, sizeof(buffer) - 1, &bytesRead, &overlapped // 关键:提供OVERLAPPED结构 ); // 4. 检查操作状态 if (!success) { DWORD error = GetLastError(); if (error == ERROR_IO_PENDING) { std::cout << "⏳ 读取操作进行中,等待完成..." << std::endl; // 等待操作完成 DWORD waitResult = WaitForSingleObject(overlapped.hEvent, INFINITE); if (waitResult == WAIT_OBJECT_0) { // 获取操作结果 if (GetOverlappedResult(hFile, &overlapped, &bytesRead, FALSE)) { buffer[bytesRead] = '\0'; std::cout << "✅ 异步读取成功: " << bytesRead << " 字节" << std::endl; std::cout << "内容: " << buffer << std::endl; } } } else { std::cout << "❌ 读取失败,错误码: " << error << std::endl; } } else { // 立即完成的情况 buffer[bytesRead] = '\0'; std::cout << "✅ 立即读取成功: " << bytesRead << " 字节" << std::endl; } // 5. 清理资源 CloseHandle(overlapped.hEvent); CloseHandle(hFile); }
#include <windows.h> #include <iostream> // 完成回调函数 VOID CALLBACK ReadCompletionRoutine( DWORD dwErrorCode, // 错误代码 DWORD dwNumberOfBytesTransfered, // 传输的字节数 LPOVERLAPPED lpOverlapped // 重叠结构 ) { std::cout << "🔔 回调函数被调用!" << std::endl; if (dwErrorCode == 0) { std::cout << "✅ 读取操作完成: " << dwNumberOfBytesTransfered << " 字节" << std::endl; // 这里可以处理读取到的数据 // 注意:缓冲区在发起请求时指定 } else { std::cout << "❌ 读取失败,错误码: " << dwErrorCode << std::endl; } } void DemoReadFileEx() { std::cout << "📖 ReadFileEx 异步回调读取示例" << std::endl; // 1. 打开文件(异步方式) HANDLE hFile = CreateFile( L"example.txt", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, // 必须使用重叠I/O NULL ); if (hFile == INVALID_HANDLE_VALUE) { std::cout << "❌ 无法打开文件" << std::endl; return; } // 2. 准备异步操作结构 OVERLAPPED overlapped = {0}; char buffer[1024]; // 3. 发起异步读取(带回调) BOOL success = ReadFileEx( hFile, // 文件句柄 buffer, // 缓冲区 sizeof(buffer) - 1, // 要读取的字节数 &overlapped, // 重叠结构 ReadCompletionRoutine // 关键:完成回调函数 ); if (!success) { std::cout << "❌ 发起异步读取失败" << std::endl; CloseHandle(hFile); return; } std::cout << "⏳ 异步读取已发起,线程进入可警报等待状态..." << std::endl; // 4. 线程必须进入可警报等待状态,回调才会执行 // SleepEx 会让线程进入可警报状态,期间可以执行回调 DWORD waitResult = SleepEx(INFINITE, TRUE); std::cout << "🏁 主线程继续执行,等待结果: " << waitResult << std::endl; // 5. 关闭文件 CloseHandle(hFile); }
// ReadFile - 基于事件的通知 OVERLAPPED overlapped = {0}; overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); ReadFile(hFile, buffer, size, NULL, &overlapped); // 需要手动等待事件 WaitForSingleObject(overlapped.hEvent, INFINITE); GetOverlappedResult(hFile, &overlapped, &bytesRead, FALSE); // ReadFileEx - 基于回调的通知 ReadFileEx(hFile, buffer, size, &overlapped, CompletionRoutine); // 自动调用回调,无需手动检查 // 但线程必须处于可警报等待状态
// ReadFile - 无特殊要求 // 可以在任何线程状态使用 // ReadFileEx - 需要可警报等待状态 // 必须在以下函数中等待: DWORD result = SleepEx(INFINITE, TRUE); // 可警报睡眠 DWORD result = WaitForSingleObjectEx(hEvent, INFINITE, TRUE); // 可警报等待 DWORD result = MsgWaitForMultipleObjectsEx(...); // 可警报消息等待
// ReadFile 错误处理 BOOL success = ReadFile(...); if (!success) { DWORD error = GetLastError(); if (error == ERROR_IO_PENDING) { // 异步操作进行中 } else { // 其他错误 } } // ReadFileEx 错误处理在回调中 VOID CALLBACK CompletionRoutine(DWORD dwErrorCode, ...) { if (dwErrorCode != 0) { // 处理错误 } }
// 场景1:简单的同步读取 class SimpleFileReader { public: std::string ReadEntireFile(const std::string& filename) { HANDLE hFile = CreateFileA(filename.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); DWORD fileSize = GetFileSize(hFile, NULL); std::vector<char> buffer(fileSize + 1); DWORD bytesRead; ReadFile(hFile, buffer.data(), fileSize, &bytesRead, NULL); CloseHandle(hFile); return std::string(buffer.data(), bytesRead); } }; // 场景2:有限的异步操作 class AsyncFileChunker { HANDLE hFile; OVERLAPPED overlapped; public: void ReadChunkAsync() { // 使用ReadFile + OVERLAPPED进行异步读取 // 然后使用WaitForSingleObject等待完成 } };
// 场景1:高性能I/O完成端口替代 class CallbackFileProcessor { public: void StartAsyncRead() { ReadFileEx(hFile, buffer, size, &overlapped, [](DWORD error, DWORD bytes, LPOVERLAPPED ov) { if (error == 0) { // 处理数据 ProcessData(buffer, bytes); // 继续读取下一块 ContinueReading(); } }); // 进入可警报等待 SleepEx(INFINITE, TRUE); } }; // 场景2:多个异步操作并行 class MultipleAsyncReads { struct ReadContext { OVERLAPPED overlapped; char buffer[4096]; int requestId; }; std::vector<ReadContext> contexts; static VOID CALLBACK CompletionHandler(DWORD error, DWORD bytes, LPOVERLAPPED ov) { ReadContext* ctx = CONTAINING_RECORD(ov, ReadContext, overlapped); if (error == 0) { std::cout << "请求 " << ctx->requestId << " 完成: " << bytes << " 字节" << std::endl; } } public: void StartMultipleReads(HANDLE hFile) { for (int i = 0; i < 5; i++) { contexts[i].requestId = i; ReadFileEx(hFile, contexts[i].buffer, 4096, &contexts[i].overlapped, CompletionHandler); } // 所有操作并行执行,完成后分别回调 SleepEx(INFINITE, TRUE); } };
// ReadFile + 事件 (传统异步) // 需要维护事件对象数组 // 使用WaitForMultipleObjects等待多个操作 // 代码相对复杂,但控制精细 // ReadFileEx + 回调 (现代异步) // 回调自动执行,无需手动等待 // 更适合大量并发I/O操作 // 代码更清晰,但需要理解可警报状态
// 选择 ReadFile 当: if (操作数量较少 || 需要精确控制 || 同步操作足够) { // 使用 ReadFile } // 选择 ReadFileEx 当: if (大量并发I/O || 需要更高性能 || 代码清晰度重要) { // 使用 ReadFileEx }
ReadFile = 传统快递,可以等货到或留条后轮询
ReadFileEx = 智能快递,货到后自动电话通知
// 问自己:需要什么样的I/O完成通知? if (简单的同步读取 || 少量异步操作) { // 使用 ReadFile ReadFile(hFile, buffer, size, &bytesRead, [&overlapped]); } else if (大量并发异步I/O || 希望代码更清晰) { // 使用 ReadFileEx ReadFileEx(hFile, buffer, size, &overlapped, CompletionRoutine); // 记得让线程进入可警报等待状态! }
通知机制:事件等待 vs 回调函数
线程要求:普通线程 vs 可警报状态线程
编程模型:手动检查 vs 自动回调
性能特点:适合少量操作 vs 适合大量并发操作
记住这个简单规则:
📞 ReadFile → 自己打电话查询快递状态
🔔 ReadFileEx → 快递自动通知你货已到
两者都是强大的文件读取工具,选择哪个取决于你的并发需求和编程偏好!
| 特性 | CreateThread | CreateRemoteThread |
|---|---|---|
| 目标进程 | 当前进程 | 任意指定进程 |
| 线程函数位置 | 当前进程地址空间 | 目标进程地址空间 |
| 权限要求 | 普通权限 | 需要目标进程权限 |
| 应用场景 | 程序内部并发 | 进程注入、调试、外挂等 |
// 就像在自己公司招聘新员工 HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, // [员工权限] - 安全属性 SIZE_T dwStackSize, // [工作台大小] - 栈空间 LPTHREAD_START_ROUTINE lpStartAddress, // [工作手册] - 线程函数地址 LPVOID lpParameter, // [工具材料] - 传给线程的参数 DWORD dwCreationFlags, // [雇佣方式] - 创建标志 LPDWORD lpThreadId // [工牌号码] - 线程ID );
// 就像在竞争对手工厂安插自己的员工 HANDLE CreateRemoteThread( HANDLE hProcess, // [目标工厂] - 目标进程句柄 LPSECURITY_ATTRIBUTES lpThreadAttributes, // [员工权限] - 安全属性 SIZE_T dwStackSize, // [工作台大小] - 栈空间 LPTHREAD_START_ROUTINE lpStartAddress, // [工作手册] - 线程函数地址(在目标进程中) LPVOID lpParameter, // [工具材料] - 传给线程的参数(在目标进程中) DWORD dwCreationFlags, // [雇佣方式] - 创建标志 LPDWORD lpThreadId // [工牌号码] - 线程ID );
// 你在自己工厂操作 自家工厂.招聘员工(工作手册, 工具材料, 雇佣方式); // 完全自主,不需要任何人同意
// 你需要进入竞争对手工厂 竞争对手工厂 = 获取工厂访问权限(PROCESS_ALL_ACCESS); 竞争对手工厂.安插员工(间谍工作手册, 间谍工具, 隐蔽雇佣); // 需要特殊手段和权限
#include <windows.h> #include <iostream> // 线程函数 - 在自家工厂工作 DWORD WINAPI MyWorkerThread(LPVOID lpParam) { const char* taskName = (const char*)lpParam; for (int i = 1; i <= 5; i++) { std::cout << "员工[" << GetCurrentThreadId() << "] 正在" << taskName << " - 步骤 " << i << "/5" << std::endl; Sleep(1000); } std::cout << "员工[" << GetCurrentThreadId() << "] 完成工作!" << std::endl; return 0; } void DemoCreateThread() { std::cout << "🏭 CreateThread 示例:自家工厂招聘" << std::endl; DWORD threadId; // 创建线程 - 就像招聘新员工 HANDLE hThread = CreateThread( NULL, // 默认安全属性 0, // 默认栈大小 MyWorkerThread, // 工作手册(线程函数) (LPVOID)"生产零件", // 工作材料(参数) 0, // 立即开始工作 &threadId // 记录员工ID ); if (hThread == NULL) { std::cout << "❌ 招聘员工失败!" << std::endl; return; } std::cout << "✅ 成功招聘员工,工号: " << threadId << std::endl; // 主线程继续其他工作 for (int i = 1; i <= 3; i++) { std::cout << "经理正在处理报表 - 步骤 " << i << "/3" << std::endl; Sleep(1500); } // 等待员工完成工作 WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread); std::cout << "🎉 所有工作完成!" << std::endl; }
#include <windows.h> #include <iostream> #include <tlhelp32.h> // 查找目标进程ID DWORD FindProcessId(const wchar_t* processName) { HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); PROCESSENTRY32 pe32; pe32.dwSize = sizeof(PROCESSENTRY32); if (Process32First(hSnapshot, &pe32)) { do { if (wcscmp(pe32.szExeFile, processName) == 0) { CloseHandle(hSnapshot); return pe32.th32ProcessID; } } while (Process32Next(hSnapshot, &pe32)); } CloseHandle(hSnapshot); return 0; } // DLL注入演示 - 最常见的CreateRemoteThread用法 BOOL InjectDLL(DWORD targetPID, const char* dllPath) { std::cout << "🕵️ CreateRemoteThread 示例:DLL注入" << std::endl; // 1. 打开目标进程(获取工厂门禁卡) HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, // 需要所有权限 FALSE, targetPID ); if (hProcess == NULL) { std::cout << "❌ 无法打开目标进程" << std::endl; return FALSE; } std::cout << "✅ 成功打开目标进程 PID: " << targetPID << std::endl; // 2. 在目标进程分配内存(在对方工厂准备办公桌) LPVOID pRemoteMemory = VirtualAllocEx( hProcess, NULL, strlen(dllPath) + 1, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE ); if (pRemoteMemory == NULL) { std::cout << "❌ 无法在目标进程分配内存" << std::endl; CloseHandle(hProcess); return FALSE; } std::cout << "📦 在目标进程分配内存 at: " << pRemoteMemory << std::endl; // 3. 写入DLL路径到目标进程(放置工作手册) SIZE_T bytesWritten; BOOL success = WriteProcessMemory( hProcess, pRemoteMemory, (LPVOID)dllPath, strlen(dllPath) + 1, &bytesWritten ); if (!success) { std::cout << "❌ 无法写入目标进程内存" << std::endl; VirtualFreeEx(hProcess, pRemoteMemory, 0, MEM_RELEASE); CloseHandle(hProcess); return FALSE; } std::cout << "📝 成功写入 " << bytesWritten << " 字节到目标进程" << std::endl; // 4. 获取LoadLibraryA地址(所有进程共享的系统函数) LPTHREAD_START_ROUTINE pLoadLibrary = (LPTHREAD_START_ROUTINE) GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA"); if (pLoadLibrary == NULL) { std::cout << "❌ 无法找到LoadLibraryA函数" << std::endl; VirtualFreeEx(hProcess, pRemoteMemory, 0, MEM_RELEASE); CloseHandle(hProcess); return FALSE; } std::cout << "🔧 LoadLibraryA函数地址: " << pLoadLibrary << std::endl; // 5. 创建远程线程(在目标工厂安插员工) HANDLE hRemoteThread = CreateRemoteThread( hProcess, // 目标进程 NULL, // 默认安全属性 0, // 默认栈大小 pLoadLibrary, // 线程函数(LoadLibraryA) pRemoteMemory, // 参数(DLL路径) 0, // 立即运行 NULL // 不需要线程ID ); if (hRemoteThread == NULL) { std::cout << "❌ 创建远程线程失败" << std::endl; VirtualFreeEx(hProcess, pRemoteMemory, 0, MEM_RELEASE); CloseHandle(hProcess); return FALSE; } std::cout << "🎯 成功创建远程线程!" << std::endl; // 6. 等待远程线程完成(等待DLL加载) WaitForSingleObject(hRemoteThread, INFINITE); // 7. 获取线程退出码(DLL模块句柄) DWORD exitCode; GetExitCodeThread(hRemoteThread, &exitCode); if (exitCode != 0) { std::cout << "✅ DLL注入成功!模块句柄: 0x" << std::hex << exitCode << std::dec << std::endl; } else { std::cout << "❌ DLL注入失败" << std::endl; } // 8. 清理资源 CloseHandle(hRemoteThread); VirtualFreeEx(hProcess, pRemoteMemory, 0, MEM_RELEASE); CloseHandle(hProcess); return (exitCode != 0); } void DemoCreateRemoteThread() { // 查找目标进程(比如记事本) DWORD targetPID = FindProcess
| 性 | VirtualProtect | VirtualProtectEx |
|---|---|---|
| 目标进程 | 当前进程 | 任意指定进程 |
| 功能 | 修改当前进程内存保护属性 | 修改其他进程内存保护属性 |
| 权限要求 | 普通权限 | 需要目标进程权限 |
| 应用场景 | 进程内部内存保护修改 | 跨进程内存保护修改 |
// 就像修改自己家房间的锁具权限 BOOL VirtualProtect( LPVOID lpAddress, // [房间位置] - 内存地址 SIZE_T dwSize, // [区域大小] - 内存大小 DWORD flNewProtect, // [新锁类型] - 新的保护属性 PDWORD lpflOldProtect // [旧锁记录] - 旧保护属性存储 );
// 就像修改邻居家房间的锁具权限(需要对方同意) BOOL VirtualProtectEx( HANDLE hProcess, // [邻居家门牌] - 目标进程句柄 LPVOID lpAddress, // [房间位置] - 内存地址 SIZE_T dwSize, // [区域大小] - 内存大小 DWORD flNewProtect, // [新锁类型] - 新的保护属性 PDWORD lpflOldProtect // [旧锁记录] - 旧保护属性存储 );
// 你在自己家里操作 自家房子.修改门锁(卧室, 新锁类型, 记录旧锁类型); // 完全自主,不需要任何人同意
// 你需要邻居的许可才能进他家操作 邻居房子 = 获取邻居许可(PROCESS_ALL_ACCESS); 邻居房子.修改门锁(客房, 新锁类型, 记录旧锁类型); // 需要特殊关系或权限
核心区别一句话:
VirtualAlloc = 管理自己家的内存
VirtualAllocEx = 管理别人家的内存(需要对方同意)
// 就像管理自己家的房间 LPVOID VirtualAlloc( LPVOID lpAddress, // [希望的位置] - 想要的内存地址 SIZE_T dwSize, // [房间大小] - 需要的内存大小 DWORD flAllocationType, // [用途] - 分配类型(住人/储物) DWORD flProtect // [安全设置] - 访问权限(只读/可写等) );
// 就像管理邻居家的房间(需要对方同意) LPVOID VirtualAllocEx( HANDLE hProcess, // [邻居家门牌] - 目标进程句柄 LPVOID lpAddress, // [希望的位置] - 想要的内存地址 SIZE_T dwSize, // [房间大小] - 需要的内存大小 DWORD flAllocationType, // [用途] - 分配类型 DWORD flProtect // [安全设置] - 访问权限 );
// 你在自己家里操作 自家房子.分配房间(卧室, 20平米, 居住用途, 私人权限); // 完全自主,不需要任何人同意
// 你需要邻居的许可才能进他家操作 邻居房子 = 获取邻居许可(PROCESS_ALL_ACCESS); 邻居房子.分配房间(客房, 15平米, 储物用途, 客人权限); // 需要特殊关系或权限
FLOSS(FireEye Labs Obfuscated String Solver)是一个非常实用的恶意样本分析工具,用于自动提取被编码或混淆的字符串。
它能识别出经过 Base64、XOR、栈解码、函数解码等技术隐藏的文本,常用于快速找出 C2 地址、文件名、命令行参数 等关键信息。
下面我教你 FLOSS 的安装与下载方法 👇
适用于 Windows / Linux / macOS
确保你系统已安装 Python 3.8+
python --version
然后直接运行:
pip install floss
安装完成后验证:
floss --version
如果显示版本号(例如 v2.2.0),说明安装成功。
适合不想装 Python 的用户。
前往 FLOSS 官方发布页:
🔗 https://github.com/mandiant/flare-floss/releases
找到最新版本(如 floss-2.2.0-windows.zip 或 floss-2.2.0-linux.tar.gz)
下载并解压后,你会得到一个可执行文件:
floss.exe
将它放入系统路径(或当前分析目录),然后命令行执行:
floss sample.exe
如果你想自己编译:
git clone https://github.com/mandiant/flare-floss.git
cd flare-floss
pip install -r requirements.txt
python setup.py install
| 目标 | 命令 |
|---|---|
| 提取样本中所有字符串 | floss sample.exe |
| 保存结果到文件 | floss sample.exe > decoded.txt |
| 提取并显示 API 调用 | floss --functions sample.exe |
| 指定输出格式(JSON) | floss -j sample.exe |
strings 或 radare2。