一、什么是进程
进程可以看作是一个运行中的程序,通常由一个可执行程序(.exe)所产生。一个进程最少包含了以下几个部分:
- 1. 一个用于描述自己的进程内核对象。
- 2. 最少一个的线程内核对象。
- 3. 一个虚拟的地址空间(4GB[32位下])。
- 4. 提供相应数据和代码的一系列模块。
二、什么是模块
windows 下的可执行文件通常称之为模块,主要用于提供需要用到的代码和数据。在 VS 中,可以在程序断下后,通过:菜单 -> 调试 -> 窗口 -> 模块中查看到当前程序中所加载的所有模块。
三、进程操作
创建进程的基本方式: ```cpp
include
int main() {
// 传入参数: 必须初始化,用于设置进程的启动信息
STARTUPINFOA StartupInfo{ sizeof(STARTUPINFOA) };
// 传出参数: 用于接收创建出的进程和线程的句柄以及 id
PROCESS_INFORMATION ProcessInfomation{};
// 可以使用函数 CreateWindow 通过传入的路径创建一个进程
BOOL Result = CreateProcessA(
"C:\\Windows\\System32\\notepad.exe", // 指定用于创建进程的可执行文件
NULL, // 命令行参数,如果不写可以为 NULL
NULL, // 表示为进程使用默认的安全属性
NULL, // 表示为进程中主线程使用的安全属性
FALSE, // 是否需要继承父进程的可继承对象
NULL, // 创建进程的标志位: 使用新控制台\调试
NULL, // 使用到的环境变量,NULL 表示使用默认的
NULL, // 设置当前的工作路径,供相对路径参考
&StartupInfo, // 提供进程的启动信息
&ProcessInfomation); // 接收进程和线程句柄以及相应的 id
// 如果进程创建成功,会返回新的进程和线程的句柄,为了防止句柄泄露,
// 应该使用 CloseHandle 来关闭句柄
if (Result != FALSE)
{
CloseHandle(ProcessInfomation.hThread);
CloseHandle(ProcessInfomation.hProcess);
}
return 0;
}
- 进程的操作
```cpp
#include <windows.h>
int main()
{
// 1. 可以使用 FindWindow 函数来查找到窗口句柄
HWND hWnd = FindWindow(NULL, L"无标题 - 记事本");
// 2. 通过函数 GetWindowThreadProcessId 可以找到对应窗口的 PID
DWORD Pid = 0;
GetWindowThreadProcessId(hWnd, &Pid);
// 3. 使用获取到的进程 ID 以指定的权限打开目标进程
// 3.1 表示当前需要一个拥有什么权限的内核对象句柄
// 3.2 表示当前的句柄是否是一个可继承句柄,需要配合继承
// 3.3 一个 PID 表示需要打开的是哪一个进程内核对象
HANDLE Process = OpenProcess(PROCESS_TERMINATE, FALSE, Pid);
// 4. 传入目标进程句柄,执行相应的操作,例如关闭它
TerminateProcess(Process, -1);
// 5. 操作完成后为了避免句柄泄露,需要关闭内核对象句柄
CloseHandle(Process);
// 6. 有的时候,也可以使用这个函数来结束当前的进程
ExitProcess(-1);
return 0;
}
int main() { // 1. 拍摄一个进程快照,保存的是调用函数的这一刻系统内的进程情况,第二个参数 // 没有意义 HANDLE Snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
// 2. 创建 PROCESSENTRY32 用于保存遍历到的进程的信息
PROCESSENTRY32 ProcessInfo{ sizeof(PROCESSENTRY32) };
// 3. 通过 Process32First 查看快照内的第一个进程的信息
if (TRUE == Process32First(Snapshot, &ProcessInfo))
{
do {
// 4. 输出进程快照给我们提供的一系列信息
printf("%08X[%08X](%d): %S\n",
ProcessInfo.th32ProcessID, // 进程ID
ProcessInfo.th32ParentProcessID, // 父进程ID
ProcessInfo.cntThreads, // 线程ID
ProcessInfo.szExeFile); // 进程名称
// 通过下面的函数可以找到指定进程对应模块的的全路径
DWORD Size{ MAX_PATH };
WCHAR Path[MAX_PATH]{};
HANDLE Process = OpenProcess(PROCESS_QUERY_INFORMATION,
FALSE,
ProcessInfo.th32ProcessID);
QueryFullProcessImageName(Process, 0, Path, &Size);
printf("\t%S\n", Path);
CloseHandle(Process);
// 5. 尝试继续读取到快照中的下一个进程信息
} while (Process32Next(Snapshot, &ProcessInfo));
}
CloseHandle(Snapshot);
return 0;
}
进程是操作系统管理的,遍历的时候,能够遍历出系统中的所有进程的信息:进程名,路径,进程ID<br />遍历进程的用处:通常来说我们都是知道进程名,然后去找到ID(ID每一次程序运行的时候都是不一样的),我们如果要操作进程,就需要使用OpenProcess函数得到它的句柄,OpenProcess这个函数,就是根据进程ID得到句柄的。
- 模块的遍历
```cpp
#include <iostream>
#include <Windows.h>
#include <Tlhelp32.h>
int main()
{
// 1. 拍摄一个模块快照,保存的是调用函数的这一刻系统内的进程情况,第二个参数是进程id
HANDLE Snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 18388);
// 2. 创建 MODULEENTRY32 用于保存遍历到的模块的信息
MODULEENTRY32 ModuleInfo{ sizeof(MODULEENTRY32) };
// 3. 通过 Module32First 查看快照内的第一个模块的信息
if (TRUE == Module32First(Snapshot, &ModuleInfo))
{
do {
// 4. 输出进程快照给我们提供的一系列信息
printf("模块名称[%08X]: %S\n", ModuleInfo.th32ProcessID, ModuleInfo.szModule);
printf("模块句柄: %p\n", ModuleInfo.hModule);
printf("加载基址: %p\n", ModuleInfo.modBaseAddr);
printf("模块大小: %d\n", ModuleInfo.modBaseSize);
printf("模块路径: %S\n\n", ModuleInfo.szExePath);
// 5. 尝试继续读取到快照中的下一个进程信息
} while (Module32Next(Snapshot, &ModuleInfo));
}
CloseHandle(Snapshot);
return 0;
}