WriteProcessMemory

核心功能概述

WriteProcessMemory 是一个 Windows API 函数,允许一个进程向另一个进程的内存空间写入数据。这是进程间通信和内存操作的关键函数。

基本比喻:

cpp
// 就像给邻居家送包裹
你的进程.写内存(邻居家进程, 邻居家地址, 你的数据, 数据大小);
// 需要邻居家的"门牌号"和"门禁权限"

📖 函数原型详解

cpp
BOOL WriteProcessMemory(
  HANDLE  hProcess,              // [目标进程] - 要写入的进程句柄
  LPVOID  lpBaseAddress,         // [目标地址] - 要写入的内存地址
  LPCVOID lpBuffer,              // [数据源] - 包含数据的缓冲区
  SIZE_T  nSize,                 // [数据大小] - 要写入的字节数
  SIZE_T  *lpNumberOfBytesWritten // [实际写入] - 实际写入的字节数
);

🔍 参数深度解析

1. hProcess – 目标进程句柄

cpp
// 必须具有 PROCESS_VM_WRITE 和 PROCESS_VM_OPERATION 权限
HANDLE hProcess = OpenProcess(
    PROCESS_VM_WRITE | PROCESS_VM_OPERATION,
    FALSE,           // 不继承句柄
    targetPID        // 目标进程ID
);

2. lpBaseAddress – 目标内存地址

cpp
// 必须是目标进程中有效的可写地址
// 通常通过以下方式获得:
LPVOID remoteAddr = VirtualAllocEx(hProcess, NULL, size, MEM_COMMIT, PAGE_READWRITE);
// 或者写入已知的固定地址

3. lpBuffer – 源数据缓冲区

cpp
// 当前进程中的数据,可以是任何类型
char data[] = "Hello from another process!";
int value = 12345;
BYTE shellcode[] = { 0x90, 0x90, 0xC3 }; // NOP, NOP, RET

4. nSize – 要写入的大小

cpp
// 要写入的字节数,不能超过缓冲区大小
DWORD size = strlen(data) + 1;  // 包括字符串结束符

5. lpNumberOfBytesWritten – 实际写入大小

cpp
// 输出参数,接收实际写入的字节数
SIZE_T bytesWritten;

💻 完整使用示例

示例1:基础数据写入

cpp
#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);
}

示例2:Shellcode 注入(典型应用)

cpp
#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;
}

示例3:修改已有内存数据

cpp
#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;
}

⚠️ 错误处理和常见问题

常见错误代码及处理:

cpp
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;
}

权限检查函数:

cpp
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;
}

🔧 实际应用场景

场景1:游戏外挂(内存修改)

cpp
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);
    }
};

场景2:调试器实现

cpp
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;
    }
};

场景3:进程修补

cpp
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 的使用:

cpp
// 安全软件可以监控可疑的 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;
}

防御代码注入:

cpp
class AntiInjection {
public:
    static BOOL ProtectProcess() {
        // 使用 Process Protection 防止外部写入
        return SetProcessMitigationPolicy(ProcessSignaturePolicy, 
                                        &policy, sizeof(policy));
    }
    
    static BOOL MonitorMemoryWrites() {
        // 定期检查进程内存是否被修改
        return SetupMemoryIntegrityCheck();
    }
};

📊 性能优化技巧

批量写入优化:

cpp
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;
}

🎯 总结

核心要点:

  1. 跨进程操作:允许一个进程修改另一个进程的内存

  2. 权限要求:需要 PROCESS_VM_WRITE 和 PROCESS_VM_OPERATION 权限

  3. 地址有效性:目标地址必须在目标进程的地址空间内且可写

  4. 错误处理:必须检查返回值和实际写入字节数

典型用途:

  • ✅ 合法用途:调试器、性能分析工具、系统维护工具

  • ⚠️ 灰色地带:游戏修改器、自动化工具

  • ❌ 恶意用途:病毒、木马、恶意软件注入

使用模式:

cpp
// 标准写入流程:
1. OpenProcess()           // 打开目标进程
2. VirtualAllocEx()        // 分配目标内存(如需要)
3. VirtualProtectEx()      // 确保内存可写(如需要)  
4. WriteProcessMemory()    // 执行写入
5. 验证结果和清理资源

记住:能力越大,责任越大! WriteProcessMemory 是一个强大的系统级函数,必须谨慎合法地使用。

 

发表在 安全分析 | 留下评论

OpenProcess和CreateProcess

OpenProcess 与 CreateProcess 深度解析

🎯 核心区别概览

特性 OpenProcess CreateProcess
核心功能 打开已存在的进程 创建新的进程
目标对象 运行中的进程 可执行文件
返回值 进程句柄 进程和线程句柄
使用场景 进程操作、注入、监控 程序启动、子进程创建

📖 函数原型对比

OpenProcess – 打开现有进程

cpp
// 就像获取已开业公司的管理权限
HANDLE OpenProcess(
  DWORD dwDesiredAccess,  // [访问权限] - 需要的操作权限
  BOOL  bInheritHandle,   // [继承选项] - 子进程是否继承句柄
  DWORD dwProcessId       // [公司ID] - 目标进程ID
);

CreateProcess – 创建新进程

cpp
// 就像创办一家新公司
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   // [公司档案] - 进程信息
);

🏭 生活化比喻

OpenProcess:接管现有公司

cpp
// 你是一个投资者,想接管一家已存在的公司
公司句柄 = 接管公司(公司ID, 管理权限, 是否允许继承);
// 公司已经存在,你只是获取管理权

CreateProcess:创办新公司

cpp
// 你是一个创业者,要创办全新的公司
创办公司(公司名称, 经营计划, 公司章程, 员工制度, 
         继承资产, 创立方式, 办公环境, 办公地点, 
         开业筹备, 公司档案);
// 从零开始创建全新的公司

💻 代码实例对比

示例1:OpenProcess 使用场景

cpp
#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);
    }
}

示例2:CreateProcess 使用场景

cpp
#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);
    }
}

🔧 关键技术差异

1. 权限需求差异

cpp
// 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
);

2. 错误处理差异

cpp
// 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) {
        // 访问被拒绝
    }
}

3. 资源管理差异

cpp
// OpenProcess - 只需要关闭一个句柄
HANDLE hProcess = OpenProcess(...);
// 使用句柄...
CloseHandle(hProcess);

// CreateProcess - 需要关闭两个句柄
CreateProcess(..., &pi);
// 使用句柄...
CloseHandle(pi.hProcess);  // 必须关闭
CloseHandle(pi.hThread);   // 必须关闭

🎯 实际应用场景

OpenProcess 的典型应用:

cpp
// 场景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;
}

CreateProcess 的典型应用:

cpp
// 场景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;
    }
};

⚠️ 安全注意事项

OpenProcess 的安全风险:

cpp
// 恶意使用示例:进程内存窃取
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, ...);
}

CreateProcess 的安全风险:

cpp
// 恶意使用示例:恶意子进程创建
BOOL CreateMaliciousProcess() {
    // 启动恶意程序
    return CreateProcess("malware.exe", NULL, NULL, NULL, FALSE, 
                        CREATE_NO_WINDOW, NULL, NULL, &si, &pi);
}

// 防御措施:应用程序控制
// 使用 AppLocker、Windows Defender Application Control 等

🔄 协同使用示例

cpp
// 场景:创建进程并监控它
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 = 创办全新公司并获取管理权

选择指南:

cpp
// 问自己:要操作现有进程还是创建新进程?

if (需要操作正在运行的进程) {
    // 使用 OpenProcess
    HANDLE hProcess = OpenProcess(desiredAccess, FALSE, targetPID);
    
} else if (需要启动新程序) {
    // 使用 CreateProcess  
    CreateProcess(appName, commandLine, ..., &processInfo);
}

关键差异总结:

  1. 目标对象:现有进程 vs 可执行文件

  2. 功能:获取句柄 vs 创建进程+获取句柄

  3. 复杂度:相对简单 vs 参数复杂

  4. 资源管理:单个句柄 vs 两个句柄

  5. 应用场景:进程操作 vs 程序启动

记住这个简单规则:

  • 🔑 OpenProcess → 接管现有公司

  • 🚀 CreateProcess → 创办全新公司

两者都是进程操作的核心API,理解它们的区别对于Windows系统编程至关重要!

 

发表在 安全分析 | 留下评论

API Monitor 监控 EXE 加载 Shellcode 的 API 调用

使用 API Monitor 监控 EXE 加载 Shellcode 的 API 调用

🎯 监控目标和关键 API

Shellcode 加载的典型 API 调用链:

cpp
// 1. 内存分配
VirtualAlloc/VirtualAllocEx()

// 2. 内存写入  
WriteProcessMemory()  // 或直接内存操作

// 3. 权限修改
VirtualProtect/VirtualProtectEx()

// 4. 代码执行
CreateThread/CreateRemoteThread()
// 或 SetThreadContext() + ResumeThread()
// 或 QueueUserAPC()

📋 配置 API Monitor 的详细步骤

步骤1:创建监控过滤器

1.1 打开 API Monitor 并创建新过滤器

cpp
// 过滤器名称: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 设置过滤器规则

cpp
// 在过滤器中设置:
- 监控所有模块的上述函数
- 记录参数和返回值
- 启用堆栈跟踪
- 设置深度监控(Deep Monitor Mode)

步骤2:配置监控会话

2.1 启动监控会话

cpp
// 方法1:监控新启动的进程
File → Monitor New Process → 选择目标 EXE

// 方法2:附加到运行中的进程  
File → Monitor Running Process → 选择目标 PID

2.2 设置高级选项

cpp
// 在监控选项中启用:
✓ Monitor child processes      // 监控子进程
✓ Monitor DLL loads           // 监控 DLL 加载
✓ Monitor registry access     // 监控注册表访问
✓ Monitor file system         // 监控文件系统操作
✓ Capture stack traces        // 捕获堆栈跟踪

🔧 具体监控配置示例

创建专门的 Shellcode 监控配置文件

xml
<!-- 保存为: 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>

🔍 监控数据分析技巧

识别 Shellcode 加载模式

模式1:经典的 Shellcode 注入

cpp
// 预期的 API 调用序列:
1. OpenProcess()                    // 打开目标进程
2. VirtualAllocEx(PAGE_READWRITE)  // 分配可读写内存
3. WriteProcessMemory()            // 写入 shellcode
4. VirtualProtectEx(PAGE_EXECUTE)  // 修改为可执行权限
5. CreateRemoteThread()            // 执行 shellcode

// 在 API Monitor 中查找这个调用序列

模式2:进程空洞(Process Hollowing)

cpp
// 预期的 API 调用序列:
1. CreateProcess(CREATE_SUSPENDED)  // 创建挂起的进程
2. GetThreadContext()              // 获取线程上下文
3. VirtualAllocEx()               // 分配新内存
4. WriteProcessMemory()           // 写入恶意代码
5. SetThreadContext()             // 修改入口点
6. ResumeThread()                 // 恢复执行

模式3:APC 注入

cpp
// 预期的 API 调用序列:
1. OpenProcess()                   // 打开目标进程
2. VirtualAllocEx()               // 分配内存
3. WriteProcessMemory()           // 写入 shellcode
4. VirtualProtectEx()             // 修改权限
5. QueueUserAPC()                 // 通过 APC 执行

关键参数分析要点

分析 VirtualAlloc 调用:

cpp
// 关注这些参数:
LPVOID VirtualAlloc(
  lpAddress,      // 通常为 NULL(系统自动分配)
  dwSize,         // 大小 - 可疑的大小(如 0x1000, 0x2000)
  flAllocationType, // MEM_COMMIT | MEM_RESERVE
  flProtect       // 初始保护:PAGE_READWRITE(可疑)
);

分析 VirtualProtect 调用:

cpp
// 特别关注权限变化:
BOOL VirtualProtect(
  lpAddress,
  dwSize, 
  flNewProtect,   // 从 PAGE_READWRITE 变为 PAGE_EXECUTE_READ
  lpflOldProtect
);

// 可疑模式:读写 → 可执行

分析 WriteProcessMemory 调用:

cpp
// 关注写入内容:
BOOL WriteProcessMemory(
  hProcess,       // 目标进程
  lpBaseAddress,  // 写入地址
  lpBuffer,       // 写入的数据(可能是加密的 shellcode)
  nSize,          // 数据大小
  lpNumberOfBytesWritten
);

💻 实际监控案例

案例:监控可疑的 EXE 文件

1. 准备监控环境

cpp
// 在 API Monitor 中:
1. 加载 shellcode_monitor.apm 配置文件
2. 设置输出文件:C:\monitor_results.log
3. 启用详细日志记录
4. 设置断点可疑的 API 组合

2. 启动监控

cpp
// 监控目标 EXE:
File → Monitor New Process → 
选择: C:\suspicious.exe
参数: (如有命令行参数)
工作目录: C:\

3. 实时分析技巧

cpp
// 在监控过程中关注:

// 实时过滤器设置:
Filter → Add Live Filter → 
条件: (FunctionName contains "Virtual") OR 
      (FunctionName contains "Write") OR
      (FunctionName contains "Thread")

// 颜色高亮:
设置 VirtualAlloc → 黄色
设置 VirtualProtect → 红色  
设置 CreateRemoteThread → 紫色

4. 事后分析脚本示例

python
# 分析 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 注入行为!")

🛡️ 高级监控技巧

使用 API Monitor 的断点功能

设置条件断点:

cpp
// 在 VirtualAlloc 上设置断点:
条件: dwSize > 0x1000  // 分配大于 4KB 内存时中断

// 在 VirtualProtect 上设置断点:
条件: flNewProtect == 0x20  // PAGE_EXECUTE_READ 时中断

// 在 CreateRemoteThread 上设置断点:
条件: 始终中断(监控所有远程线程创建)

内存内容转储

配置内存转储:

cpp
// 在 API Monitor 选项中:
✓ Dump memory on WriteProcessMemory calls
✓ Dump memory on VirtualProtect calls  
✓ Limit dump size: 4096 bytes  // 避免转储过大

// 这样可以在 shellcode 被写入和权限更改时捕获其内容

堆栈跟踪分析

启用详细堆栈跟踪:

cpp
// 在监控选项中:
✓ Capture stack traces for all APIs
✓ Maximum stack depth: 32

// 分析堆栈可以揭示:
- 调用来源(哪个模块调用)
- 调用链关系
- 可能的代码注入点

📊 结果分析和报告

生成监控报告

1. 导出调用序列

cpp
// 在 API Monitor 中:
Reports → Generate Call Sequence Report
格式: HTML/XML/CSV
包含: 时间戳、参数、返回值、堆栈

2. 时间线分析

cpp
// 关注 API 调用时间间隔:
VirtualAlloc → WriteProcessMemory → VirtualProtect → CreateThread

// 正常程序:间隔较均匀
// Shellcode 注入:快速连续调用

3. 统计报告

cpp
// 生成统计信息:
- 每个 API 的调用次数
- 内存分配总量
- 权限更改次数
- 线程创建统计

🎯 总结

监控 Shellcode 的关键要点:

  1. 配置正确的过滤器 – 包含所有相关 API

  2. 关注调用序列 – 特别是内存分配→写入→权限更改→执行

  3. 分析参数模式 – 可疑的内存大小和权限变化

  4. 使用堆栈跟踪 – 确定调用来源

  5. 设置条件断点 – 在关键时刻中断分析

典型 Shellcode 特征:

cpp
// 在 API Monitor 中看到的可疑模式:
1. 快速连续的内存操作 API 调用
2. 内存权限从读写变为可执行
3. 在非自身进程中创建线程
4. 写入的可执行代码块
5. 异常的 API 调用序列

通过精心配置 API Monitor,你可以有效地检测和分析 EXE 文件加载和执行 shellcode 的行为!


发表在 安全分析 | 留下评论

ReadFile和ReadFileEx

ReadFile 与 ReadFileEx 深度解析

🎯 核心区别概览

特性 ReadFile ReadFileEx
操作模式 同步或异步 纯异步
完成通知 事件对象或阻塞等待 回调函数
线程要求 可阻塞线程 需要可警报状态线程
编程复杂度 相对简单 相对复杂但更高效

📖 函数原型对比

ReadFile – 同步/异步文件读取

cpp
// 就像普通快递收货 - 可以等货到,也可以留地址后离开
BOOL ReadFile(
  HANDLE       hFile,                // [快递单号] - 文件句柄
  LPVOID       lpBuffer,             // [收货箱] - 数据缓冲区
  DWORD        nNumberOfBytesToRead, // [预期数量] - 要读取的字节数
  LPDWORD      lpNumberOfBytesRead,  // [实际数量] - 实际读取的字节数
  LPOVERLAPPED lpOverlapped          // [取货安排] - 重叠结构(用于异步)
);

ReadFileEx – 异步文件读取(带回调)

cpp
// 就像智能快递柜 - 货到后自动通知你
BOOL ReadFileEx(
  HANDLE                          hFile,                // [快递单号] - 文件句柄
  LPVOID                          lpBuffer,             // [收货箱] - 数据缓冲区
  DWORD                           nNumberOfBytesToRead, // [预期数量] - 要读取的字节数
  LPOVERLAPPED                    lpOverlapped,         // [取货安排] - 扩展重叠结构
  LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine   // [通知方式] - 完成回调函数
);

🏢 生活化比喻

ReadFile:传统快递

cpp
// 方式1:同步 - 在家等快递
快递.取件(等待直到送达);  // 阻塞等待

// 方式2:异步 - 留下取件码,时不时查看
快递.取件(留下取件码);
while(!检查是否送达()) { 做其他事; }  // 轮询检查

ReadFileEx:智能快递柜

cpp
// 异步回调 - 快递放入柜子后自动发短信通知
快递.取件(放入快递柜, 短信通知我);
// 你可以完全专注做其他事,收到通知再去取

💻 代码实例对比

示例1:ReadFile 同步读取

cpp
#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);
}

示例2:ReadFile 异步读取(使用事件)

cpp
#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);
}

示例3:ReadFileEx 异步读取(使用回调)

cpp
#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);
}

🔧 关键技术差异

1. 完成通知机制

cpp
// 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);

// 自动调用回调,无需手动检查
// 但线程必须处于可警报等待状态

2. 线程状态要求

cpp
// ReadFile - 无特殊要求
// 可以在任何线程状态使用

// ReadFileEx - 需要可警报等待状态
// 必须在以下函数中等待:
DWORD result = SleepEx(INFINITE, TRUE);        // 可警报睡眠
DWORD result = WaitForSingleObjectEx(hEvent, INFINITE, TRUE);  // 可警报等待
DWORD result = MsgWaitForMultipleObjectsEx(...);  // 可警报消息等待

3. 错误处理差异

cpp
// ReadFile 错误处理
BOOL success = ReadFile(...);
if (!success) {
    DWORD error = GetLastError();
    if (error == ERROR_IO_PENDING) {
        // 异步操作进行中
    } else {
        // 其他错误
    }
}

// ReadFileEx 错误处理在回调中
VOID CALLBACK CompletionRoutine(DWORD dwErrorCode, ...) {
    if (dwErrorCode != 0) {
        // 处理错误
    }
}

🎯 实际应用场景

ReadFile 适用场景:

cpp
// 场景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等待完成
    }
};

ReadFileEx 适用场景:

cpp
// 场景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);
    }
};

⚡ 性能对比

I/O 完成方式:

cpp
// ReadFile + 事件 (传统异步)
// 需要维护事件对象数组
// 使用WaitForMultipleObjects等待多个操作
// 代码相对复杂,但控制精细

// ReadFileEx + 回调 (现代异步)
// 回调自动执行,无需手动等待
// 更适合大量并发I/O操作
// 代码更清晰,但需要理解可警报状态

适用场景建议:

cpp
// 选择 ReadFile 当:
if (操作数量较少 || 需要精确控制 || 同步操作足够) {
    // 使用 ReadFile
}

// 选择 ReadFileEx 当:  
if (大量并发I/O || 需要更高性能 || 代码清晰度重要) {
    // 使用 ReadFileEx
}

🎯 总结

核心区别一句话:

  • ReadFile = 传统快递,可以等货到或留条后轮询

  • ReadFileEx = 智能快递,货到后自动电话通知

选择指南:

cpp
// 问自己:需要什么样的I/O完成通知?

if (简单的同步读取 || 少量异步操作) {
    // 使用 ReadFile
    ReadFile(hFile, buffer, size, &bytesRead, [&overlapped]);
    
} else if (大量并发异步I/O || 希望代码更清晰) {
    // 使用 ReadFileEx  
    ReadFileEx(hFile, buffer, size, &overlapped, CompletionRoutine);
    // 记得让线程进入可警报等待状态!
}

关键差异总结:

  1. 通知机制:事件等待 vs 回调函数

  2. 线程要求:普通线程 vs 可警报状态线程

  3. 编程模型:手动检查 vs 自动回调

  4. 性能特点:适合少量操作 vs 适合大量并发操作

记住这个简单规则:

  • 📞 ReadFile → 自己打电话查询快递状态

  • 🔔 ReadFileEx → 快递自动通知你货已到

两者都是强大的文件读取工具,选择哪个取决于你的并发需求和编程偏好!

 

发表在 安全分析 | 留下评论

CreateThread和CreateRemoteThread

核心区别概览

特性 CreateThread CreateRemoteThread
目标进程 当前进程 任意指定进程
线程函数位置 当前进程地址空间 目标进程地址空间
权限要求 普通权限 需要目标进程权限
应用场景 程序内部并发 进程注入、调试、外挂等

📖 函数原型对比

CreateThread – 在自家工厂招聘员工

cpp
// 就像在自己公司招聘新员工
HANDLE CreateThread(
  LPSECURITY_ATTRIBUTES   lpThreadAttributes,  // [员工权限] - 安全属性
  SIZE_T                  dwStackSize,         // [工作台大小] - 栈空间
  LPTHREAD_START_ROUTINE  lpStartAddress,      // [工作手册] - 线程函数地址
  LPVOID                  lpParameter,         // [工具材料] - 传给线程的参数
  DWORD                   dwCreationFlags,     // [雇佣方式] - 创建标志
  LPDWORD                 lpThreadId           // [工牌号码] - 线程ID
);

CreateRemoteThread – 在别人工厂安插员工

cpp
// 就像在竞争对手工厂安插自己的员工
HANDLE CreateRemoteThread(
  HANDLE                 hProcess,             // [目标工厂] - 目标进程句柄
  LPSECURITY_ATTRIBUTES  lpThreadAttributes,   // [员工权限] - 安全属性
  SIZE_T                 dwStackSize,          // [工作台大小] - 栈空间
  LPTHREAD_START_ROUTINE lpStartAddress,       // [工作手册] - 线程函数地址(在目标进程中)
  LPVOID                 lpParameter,          // [工具材料] - 传给线程的参数(在目标进程中)
  DWORD                  dwCreationFlags,      // [雇佣方式] - 创建标志
  LPDWORD                lpThreadId            // [工牌号码] - 线程ID
);

🏭 生活化比喻

CreateThread:自家工厂招聘

cpp
// 你在自己工厂操作
自家工厂.招聘员工(工作手册, 工具材料, 雇佣方式);
// 完全自主,不需要任何人同意

CreateRemoteThread:往竞争对手工厂派间谍

cpp
// 你需要进入竞争对手工厂
竞争对手工厂 = 获取工厂访问权限(PROCESS_ALL_ACCESS);
竞争对手工厂.安插员工(间谍工作手册, 间谍工具, 隐蔽雇佣);
// 需要特殊手段和权限

💻 代码实例对比

示例1:CreateThread – 当前进程创建线程

cpp
#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;
}

示例2:CreateRemoteThread – 跨进程创建线程

cpp
#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

核心区别概览

函数原型对比

VirtualProtect VirtualProtectEx
目标进程 当前进程 任意指定进程
功能 修改当前进程内存保护属性 修改其他进程内存保护属性
权限要求 普通权限 需要目标进程权限
应用场景 进程内部内存保护修改 跨进程内存保护修改

VirtualProtect – 修改自家内存权限

cpp
// 就像修改自己家房间的锁具权限
BOOL VirtualProtect(
  LPVOID lpAddress,        // [房间位置] - 内存地址
  SIZE_T dwSize,           // [区域大小] - 内存大小
  DWORD  flNewProtect,     // [新锁类型] - 新的保护属性
  PDWORD lpflOldProtect    // [旧锁记录] - 旧保护属性存储
);

VirtualProtectEx – 修改别人家内存权限

cpp
// 就像修改邻居家房间的锁具权限(需要对方同意)
BOOL VirtualProtectEx(
  HANDLE hProcess,         // [邻居家门牌] - 目标进程句柄
  LPVOID lpAddress,        // [房间位置] - 内存地址
  SIZE_T dwSize,           // [区域大小] - 内存大小
  DWORD  flNewProtect,     // [新锁类型] - 新的保护属性
  PDWORD lpflOldProtect    // [旧锁记录] - 旧保护属性存储
);

活化比喻

VirtualProtect:修改自家门锁

cpp
// 你在自己家里操作
自家房子.修改门锁(卧室, 新锁类型, 记录旧锁类型);
// 完全自主,不需要任何人同意

VirtualProtectEx:帮邻居修改门锁

cpp
// 你需要邻居的许可才能进他家操作
邻居房子 = 获取邻居许可(PROCESS_ALL_ACCESS);
邻居房子.修改门锁(客房, 新锁类型, 记录旧锁类型);
// 需要特殊关系或权限

 

发表在 逆向工程 | 留下评论

VirtualAlloc和VirtualAllocEx

核心区别一句话:

VirtualAlloc = 管理自己家的内存

VirtualAllocEx = 管理别人家的内存(需要对方同意)

函数原型对比

VirtualAlloc – 管理自家内存

cpp
// 就像管理自己家的房间
LPVOID VirtualAlloc(
  LPVOID lpAddress,        // [希望的位置] - 想要的内存地址
  SIZE_T dwSize,           // [房间大小] - 需要的内存大小
  DWORD  flAllocationType, // [用途] - 分配类型(住人/储物)
  DWORD  flProtect         // [安全设置] - 访问权限(只读/可写等)
);

VirtualAllocEx – 管理别人家内存

cpp
// 就像管理邻居家的房间(需要对方同意)
LPVOID VirtualAllocEx(
  HANDLE hProcess,         // [邻居家门牌] - 目标进程句柄
  LPVOID lpAddress,        // [希望的位置] - 想要的内存地址
  SIZE_T dwSize,           // [房间大小] - 需要的内存大小
  DWORD  flAllocationType, // [用途] - 分配类型
  DWORD  flProtect         // [安全设置] - 访问权限
);

生活化比喻

VirtualAlloc:装修自家房子

cpp
// 你在自己家里操作
自家房子.分配房间(卧室, 20平米, 居住用途, 私人权限);
// 完全自主,不需要任何人同意

VirtualAllocEx:帮邻居装修

cpp
// 你需要邻居的许可才能进他家操作
邻居房子 = 获取邻居许可(PROCESS_ALL_ACCESS);
邻居房子.分配房间(客房, 15平米, 储物用途, 客人权限);
// 需要特殊关系或权限
 
发表在 安全分析 | 留下评论

FLOSS

FLOSSFireEye Labs Obfuscated String Solver)是一个非常实用的恶意样本分析工具,用于自动提取被编码或混淆的字符串
它能识别出经过 Base64、XOR、栈解码、函数解码等技术隐藏的文本,常用于快速找出 C2 地址、文件名、命令行参数 等关键信息。

下面我教你 FLOSS 的安装与下载方法 👇


🧰 一、官方信息


💻 二、安装方式(推荐三种)

✅ 方法 1:直接用 pip 安装(最简单)

适用于 Windows / Linux / macOS

  1. 确保你系统已安装 Python 3.8+

    bash
    python --version
    
  2. 然后直接运行:

    bash
    pip install floss
    
  3. 安装完成后验证:

    bash
    floss --version
    

    如果显示版本号(例如 v2.2.0),说明安装成功。


✅ 方法 2:手动下载可执行文件(免安装版)

适合不想装 Python 的用户。

  1. 前往 FLOSS 官方发布页:
    🔗 https://github.com/mandiant/flare-floss/releases

  2. 找到最新版本(如 floss-2.2.0-windows.zipfloss-2.2.0-linux.tar.gz

  3. 下载并解压后,你会得到一个可执行文件:

    floss.exe
    
  4. 将它放入系统路径(或当前分析目录),然后命令行执行:

    bash
    floss sample.exe
    

✅ 方法 3:从源码构建(适合进阶用户)

如果你想自己编译:

bash
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

⚠️ 四、注意事项

  • FLOSS 只支持 PE 文件(.exe / .dll)
    若是 ELF / Mach-O,可以用 strings 或 radare2
  • 若样本使用复杂加密(如 RC4/AES),FLOSS 可能无法完全解码。
  • 运行时不要在联网主机上直接执行恶意样本(建议用虚拟机或沙箱)。
发表在 安全分析 | 留下评论

sysmon

Sysmon – Sysinternals | Microsoft Learn

发表在 安全分析 | 留下评论

fakenet-ng报错

 

 

ERROR: pip’s dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.
fakenet-ng 3.5 requires dpkt, which is not installed.
fakenet-ng 3.5 requires jinja2, which is not installed.

 

 

意思就是 FakeNet 运行需要这两个库:

  • dpkt(用于解析网络数据包)
  • jinja2(用于渲染 FakeNet 的网页模板)

✅ 一步解决方案

激活你的虚拟环境(如果尚未激活):

cd ~/tools/flare-fakenet-ng
source .venv/bin/activate

然后执行下面命令手动安装缺失依赖:

pip install dpkt jinja2

🧩 进一步建议:完整修复依赖环境

FakeNet-NG 常用依赖如下,可一次性全部补齐:

pip install dpkt jinja2 netaddr psutil pyOpenSSL netfilterqueue

(这些库用于 FakeNet 的流量分析、SSL 模拟、DNS 响应等模块)


🔁 验证安装是否成功

执行:

pip list | grep -E "dpkt|jinja2"

输出应类似:

dpkt              1.9.8
Jinja2            3.1.4

🚀 最后,重新运行 FakeNet

sudo .venv/bin/fakenet --config ./resources/fakenet.conf

你应当看到 FakeNet 正常启动:

[*] FakeNet-NG v3.5 starting...
[*] Loaded configuration file: ./resources/fakenet.conf
[*] Starting listeners:
    [HTTPListener] Listening on port 80
    [DNSListener] Listening on port 53
    [SSLListener] Listening on port 443
发表在 安全分析 | 留下评论