32位程式獲取32/64位進程文件地址通用方法

32位程式獲取32/64位進程文件地址通用方法

引子

一般來說,限於32位程式GetModuleFileNameEx對於64位程式來說是不管用的,我們如果需要在32位程式獲得64位進程的運行目錄可能需要用到wow64或者是QueryFullProcessImageName

但是

前者雖然通用,但是實現起來過於複雜,還需要用到彙編,後者

Minimum supported client Windows Vista [desktop apps only]
Minimum supported server Windows Server 2008 [desktop apps only]

上為ms docs給出的限制條件,顯然無法支援到諸如XP之類的系統

顯然這個API不是通用的,那麼如果我們需要一個通用且方便的方法怎麼辦呢?

這時候就可以祭出我們的GetProcessImageFileNameA

Minimum supported client Windows XP [desktop apps only]
Minimum supported server Windows Server 2003 [desktop apps only]
Target Platform Windows
Header psapi.h
Library Kernel32.lib on Windows 7 and Windows Server 2008 R2; Psapi.lib (if PSAPI_VERSION=1) on Windows 7 and Windows Server 2008 R2; Psapi.lib on Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP
DLL Kernel32.dll on Windows 7 and Windows Server 2008 R2; Psapi.dll (if PSAPI_VERSION=1) on Windows 7 and Windows Server 2008 R2; Psapi.dll on Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP

支援還是蠻全的

但是注意到這個API返回的是Native Path(\\**\****),而不是我們熟悉的Dos Path(X:\**\***)

所以我們還需要QueryDosDeviceA進行轉換

值得一提的是,根據這個API所屬DLL的變更,我們有理由認為QueryFullProcessImageName實際上就是這個API的封裝

程式碼實現

/*
    Created on: 2022-02-01
    Created by: Icys
*/

#include <iostream>
#include <cstring>
#include <windows.h>
#include <psapi.h>
#include <cstring>

//將Nt文件路徑轉為Dos文件路徑
std::string NTFilePath2DosFilePath(std::string name)
{
    char szDriveStr[MAX_PATH] = {0};
    char szDeviceStr[MAX_PATH] = {0};
    char szDrive[3] = {0};
    int cchDevName = 0;

    if (GetLogicalDriveStringsA(sizeof(szDriveStr), szDriveStr) == 0)
    {
        return "";
    }
    for (int i = 0; szDriveStr[i]; i += 4)
    {
        memcpy(szDrive, szDriveStr + i, 2);
        if (!QueryDosDeviceA(szDrive, szDeviceStr, sizeof(szDeviceStr)))
        {
            return "";
        }
        cchDevName = lstrlenA(szDeviceStr);
        if (strnicmp(szDeviceStr, name.c_str(), cchDevName) == 0) //比較前綴
        {
            name.replace(0, cchDevName, szDrive);
            return name;
        }
    }
    return "";
}

std::string GetProcessPath(int PID)
{
    auto hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, PID);
    if (!hProcess)
        return "";
    char *FileNativePath = new char[MAX_PATH + 1];
    if (!GetProcessImageFileNameA(hProcess, FileNativePath, MAX_PATH + 1))
        return "";
    std::string FilePath = NTFilePath2DosFilePath(FileNativePath);
    delete[] FileNativePath;
    return FilePath;
}

int main()
{
    std::cout << GetProcessPath(15572) << std::endl;
    return 0;
}

後記

本文由Icys編纂並發表,僅發表於CNBLOG,如果在其他地方所見,均為未經允許的盜竊。