欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Win32:进程相关的API

程序员文章站 2022-07-05 13:24:13
...

文章目录

 

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