Win32:进程相关的API
程序员文章站
2022-07-05 13:24:13
...
文章目录
- 获取所有进程的进程ID和EXE文件名
- 打开进程句柄(通过进程ID)
- 打开模块句柄/基址(根据进程句柄、模块名)
- 获取模块的文件全路径(根据进程句柄、模块句柄)
- 获取模块的文件名(根据进程句柄、模块句柄)
- 获取模块的镜像大小、入口地址(通过进程句柄、模块起始地址)
- 读取进程的内存
- 获取进程的所有模块的句柄
获取所有进程的进程ID和EXE文件名
方式1:通过进程快照CreateToolhelp32Snapshot(),获取所有进程的ID和进程EXE名(不是路径)
#include <tlHelp32.h>
#include <vector>
//**
// Method: GetPEntryList
// Description:获取进程ENTRY32列表(CreateToolhelp32Snapshot进程快照方式),获取进程ID和EXE名
// Parameter: OUT std::vector<char > & list -
// Returns: void -
//**
void MyTools::GetPEntryList(OUT std::vector<PROCESSENTRY32>& list)
{
HANDLE handle;
handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); //调用CreatToolhelp32Snapshot来获取快照,用THREADENTRY32来获取线程信息等 就会用到'tlHelp32.h'头文件
PROCESSENTRY32 info = new PROCESSENTRY32;
info->dwSize = sizeof(PROCESSENTRY32);
Process32First(handle, info);
while (Process32Next(handle, info) != FALSE)
{
DWORD PID = info->th32ProcessID; //获取进程ID
wchar_t ExeName = info->szExeFile; //获取进程的EXE名(注意不是全路径)
PROCESSENTRY32 copyInfo = new PROCESSENTRY32; //将造成内存泄漏
copyInfo = info;
list.push_back(copyInfo); //进程结构体PROCESSENTRY32存入vector
}
delete(info);
CloseHandle(handle);
return;
}
方式2:通过枚举进程EnumProcesses(),只能获取所有进程的ID
//** // Method: GetPIDList // Description:获取进程ID列表(EnumProcesses方式) // Parameter: OUT std::vector<int
> & PIDList - // Returns: void - //** void GetPIDList(OUT std::vector<int>& PIDList) { //获取PID数组 DWORD PIDs[500]; //PID数组 DWORD NeededSize; //数组有效字节数 EnumProcesses(OUT PIDs, sizeof(PIDs), OUT & NeededSize); //计算PID个数 int numberOfPID = (NeededSize / sizeof(DWORD)); //遍历PID数组 for (int i = 0; i < numberOfPID; i++) { PIDList.push_back(PIDs[i]); //写入vector } return; }
- 注意,不论是CreateToolhelp32Snapshot()还是EnumProcesses(),得到的进程数量都是一样的。盲猜CreateToolhelp32Snapshot的内部是调用了EnumProcesses()。
打开进程句柄(通过进程ID)
- OpenProcess() 打开某进程,且声明需要的权限,一般可以声明PROCESS_ALL_ACCESS即所有权限。
- 有的进程无法打开,尝试用管理员身份运行EXE后可以打开一部分进程(如svhost.exe),但仍有一些进程无法打开(如System、smss.exe等)。
//** // Method: OpenProcessByPID // Description: // Parameter: int PID - // Parameter: HANDLE & hProcess - // Returns: void - //** void OpenProcessByPID(int PID,OUT HANDLE& hProcess) { hProcess = 0; //打开进程 hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, PID); if (hProcess == 0) { MessageBox(0, L"打开进程失败:是否开启管理员身份?是否在32位进程中尝试打开64位进程?", 0, 0); } return; }
- 打开当前进程的句柄
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,FALSE,GetCurrentProcessId());
- 32位进程中无法打开64位进程,而64位进程既可以打开32位进程也可以打开64位进程。
- 可以使用IsWow64Process宏判断目标进程的位数。
//判断是32位还是64位进程,isWow64Process用于判断某进程是否运行在WOW64下。 //对于64位程序,Wow64Process参数会返回FALSE! BOOL Wow64Process; IsWow64Process(hProcess, &Wow64Process); if(Wow64Process==TRUE){printf("目标进程是32位进程");}
- 提权函数:经测试发现没有任何效果,可能win10不再需要提权令牌了?只需管理员权限就够了?
//** // Method: UpPrivileges // Description:提权函数,但暂时看不到效果,很多进程提权后仍打不开: // Returns: bool - //** bool UpPrivileges() { HANDLE hToken; TOKEN_PRIVILEGES tp; TOKEN_PRIVILEGES oldtp; DWORD dwSize = sizeof(TOKEN_PRIVILEGES); LUID luid; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { MessageBox(0, L"OpenProcessToken is FALSE ", 0, 0); if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { printf("OpenProcessToken GetLastError() == ERROR_CALL_NOT_IMPLEMENTED \n"); return true; } else { printf("OpenProcessToken GetLastError() ==Others \n"); return false; } } if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) { CloseHandle(hToken); MessageBox(0, L"LookupPrivilegeValue is FALSE ", 0, 0); return false; } ZeroMemory(&tp, sizeof(tp)); tp.PrivilegeCount = 1; tp.Privileges[0].Luid = luid; tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; / Adjust Token Privileges / if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &oldtp, &dwSize)) { CloseHandle(hToken); MessageBox(0, L"AdjustTokenPrivileges == FALSE ", 0, 0); return false; } // close handles printf("UpPrivileges Success ! \n"); CloseHandle(hToken); return true; }
打开模块句柄/基址(根据进程句柄、模块名)
- 通过GetModuleHandle(NULL)只能获取当前进程的模块基址,参数为NULL表示获取主模块基址
- 通过EnumProcessModulesEx()可以枚举任意进程的所有模块句柄,其中首个模块句柄就是主模块的基址。
//** // Method: OpenModuleByName // Description:获取模块基址(根据进程句柄、模块名称) // Parameter: HANDLE hProcess - // Parameter: wchar_t destModuleName - // Parameter: OUT HMODULE hModule - // Returns: void - //** void OpenModuleByName(HANDLE hProcess, wchar_t destModuleName, OUT HMODULE& hModule) { if (hProcess == 0) { hModule = 0; return; } //枚举进程的所有模块的句柄 HMODULE moduleArray[500] = { 0 }; DWORD neededSize = 0; EnumProcessModulesEx(hProcess, OUT moduleArray, sizeof(moduleArray), OUT & neededSize, LIST_MODULES_ALL); //获取主模块基址:进程第0个模块的句柄就是进程主模块的句柄/基址/载入地址 if (destModuleName == NULL) { hModule = moduleArray[0]; } //获取指定模块名称的模块基址 else { int NumOfModule = neededSize / sizeof(HMODULE); //计算模块个数 for (int i = 0; i < NumOfModule; i++) { WCHAR moduleFileName[50] = { 0 }; MyTools::GetModuleName(hProcess, moduleArray[i], moduleFileName); if (wcscmp(moduleFileName, destModuleName) == 0) { hModule = moduleArray[i]; return; } } } }
获取模块的文件全路径(根据进程句柄、模块句柄)
- 获取目标进程的主模块全路径(根据模块句柄)
- 参数hModule表示模块的在目标进程的载入地址/基址+
- 如果传入hModule=NULL,则表示获取主模块全路径,即进程全路径。
WCHAR filePath[200] = { 0 }; GetModuleFileNameEx(hProcess, hModule,OUT filePath, sizeof(filePath) );
- 1
- 2
获取模块的文件名(根据进程句柄、模块句柄)
- 通过截取模块的文件全路径可以得到模块文件名
- 传入模块句柄=NULL表示主模块的文件名,即’进程名’。
//**
// Method: GetModuleName
// Description:获取模块的文件名(根据进程句柄、模块句柄)
// Parameter: HANDLE hProcess -
// Parameter: HMODULE hModule - 参数为NULL时表示获取主模块的文件名
// Parameter: OUT WCHAR ModuleFileName - 是文件名,不是全路径
// Returns: void -
//**
void MyTools::GetModuleName(HANDLE hProcess, HMODULE hModule, OUT WCHAR ModuleFileName)
{
if (hProcess == 0)return;
//获取进程全路径:进程主模块(第0个模块)的全路径
WCHAR fullPath[200] = { 0 };
DWORD bufferSize = GetModuleFileNameEx(hProcess, hModule, OUT fullPath, sizeof(fullPath));
//从全路径中截取EXE文件名
int len = wcslen(fullPath);
for (int i = len - 1; i >= 0; i--)
{
if (fullPath[i] == L'\')
{
wcscpy(ModuleFileName, &fullPath[i + 1]);
break;
}
}
}
获取模块的镜像大小、入口地址(通过进程句柄、模块起始地址)
- GetModuleInformation()实际上是通过分析模块的PE头结构,从而返回ImageSize和EntryPoint的,所以参数hModule必须是模块的起始镜像地址,所以传入hModule=NULL并不能得到主模块的信息。
MODULEINFO moduleInfo = { 0 }; GetModuleInformation(hProcess, hModule, OUT & moduleInfo, sizeof(moduleInfo)); moduleInfo.lpBaseOfDll;//模块基址,实际上就是传入的hModule参数值 moduleInfo.SizeOfImage;//模块镜像大小 moduleInfo.EntryPoint; //模块入口地址
读取进程的内存
//打开进程(读取权限)
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, PID);
//读取内存
LPVOID destAddr=(LPVOID)0x7ff7e1e40000;
BYTE buffer[1024] = { 0 };
unsigned __int64 numberOfReadedByte = 0; //成功读取的内存字节数
ReadProcessMemory(hProcess, destAddr, OUT buffer, sizeof(buffer), &numberOfReadedByte );
if (numberOfReadedByte == 0)
{
DWORD code = GetLastError();
MessageBox(0, L"读取进程内存失败", 0, 0);
return false;
}
获取进程的所有模块的句柄
- 获取其他进程的所有模块
HMODULE moduleArray[500] = { 0 };
DWORD neededSize = 0;
//枚举进程的模块
EnumProcessModulesEx(hProcess, OUT moduleArray, sizeof(moduleArray), OUT & neededSize, LIST_MODULES_ALL);
- 获取当前进程的所有模块
HMODULE moduleArray[500] = { 0 };
DWORD neededSize = 0;
//打开当前进程的句柄
HANDLE hCurrentProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,FALSE,GetCurrentProcessId());
//枚举当前进程的模块
EnumProcessModulesEx(hCurrentProcess , OUT moduleArray, sizeof(moduleArray), OUT & neededSize, LIST_MODULES_ALL);
推荐阅读
-
探讨:Oracle数据库查看一个进程是如何执行相关的实际SQL语句
-
以实例全面讲解PHP中多进程编程的相关函数的使用
-
C#获取进程或线程相关信息的方法
-
linux 创建守护进程的相关知识
-
linux 查找进程及终止进程操作的相关命令
-
JAVA WEB快速入门之从编写一个基于SpringBoot+Mybatis快速创建的REST API项目了解SpringBoot、SpringMVC REST API、Mybatis等相关知识
-
探讨:Oracle数据库查看一个进程是如何执行相关的实际SQL语句
-
C#调用Win32的API函数--User32.dll
-
Web API---DOM---元素相关的操作方法
-
linux 创建守护进程的相关知识