Win32:进程相关的API

获取所有进程的进程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) ); 
    

获取模块的文件名(根据进程句柄、模块句柄)

  • 通过截取模块的文件全路径可以得到模块文件名
  • 传入模块句柄=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);
发布了56 篇原创文章 · 获赞 5 · 访问量 7457

猜你喜欢

转载自blog.csdn.net/forchoosen/article/details/103001920