美文网首页
获取打开的文件的全路径(2)

获取打开的文件的全路径(2)

作者: 看点书 | 来源:发表于2018-05-24 17:56 被阅读0次

方法二:

搜索进程空间中的所有句柄,获取句柄的文件名即可。

1 首先遍历进程寻找打开文件的进程,比如 word.exe 和PowerPoint.exe

HANDLE hSnapProcess = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapProcess == INVALID_HANDLE_VALUE)
{
    return 1;
}
PROCESSENTRY32W ProcessEntry;
ProcessEntry.dwSize = sizeof(ProcessEntry);
BOOL bret = Process32FirstW(hSnapProcess, &ProcessEntry);
WCHAR wszProcessInfo[MAX_PATH] = { 0 };

do
{
    WCHAR Name[MAX_PATH] = { 0 };

    if (!lstrcmp(ProcessEntry.szExeFile, L"POWERPNT.EXE") | !lstrcmp(ProcessEntry.szExeFile, L"WINWORD.EXE"))
    {
        …….
    }

2 寻找到目标进程以后,获取进程中的句柄

这里利用了未文档化的一个函数

ZwQuerySystemInformation,这是ntdll.dll中的函数

HMODULE hNtDLL = LoadLibrary(L"NTDLL.DLL");
if (!hNtDLL)
{
    return 1;
}
ZwQuerySystemInformation = (ZWQUERYSYSTEMINFORMATION)GetProcAddress(hNtDLL, "ZwQuerySystemInformation");

typedef NTSTATUS(WINAPI *ZWQUERYSYSTEMINFORMATION)(unsigned long, PVOID, ULONG, PULONG);
ZWQUERYSYSTEMINFORMATION ZwQuerySystemInformation;

函数原型如下:

NTSTATUS WINAPI ZwQuerySystemInformation(
  _In_      SYSTEM_INFORMATION_CLASS SystemInformationClass,
  _Inout_   PVOID                    SystemInformation,
  _In_      ULONG                    SystemInformationLength,
  _Out_opt_ PULONG                   ReturnLength
);

SYSTEM_INFORMATION_CLASS结构体如下:

typedef enum _SYSTEMINFOCLASS
{
    SystemBasicInformation,             // 0x002C
    SystemProcessorInformation,         // 0x000C
    SystemPerformanceInformation,       // 0x0138
    SystemTimeInformation,              // 0x0020
    SystemPathInformation,              // not implemented
    SystemProcessInformation,           // 0x00C8+ per process
    SystemCallInformation,              // 0x0018 + (n * 0x0004)
    SystemConfigurationInformation,     // 0x0018
    SystemProcessorCounters,            // 0x0030 per cpu
    SystemGlobalFlag,                   // 0x0004 (fails if size != 4)
    SystemCallTimeInformation,          // not implemented
    SystemModuleInformation,            // 0x0004 + (n * 0x011C)
    SystemLockInformation,              // 0x0004 + (n * 0x0024)
    SystemStackTraceInformation,        // not implemented
    SystemPagedPoolInformation,         // checked build only
    SystemNonPagedPoolInformation,      // checked build only
    SystemHandleInformation,            // 0x0004  + (n * 0x0010)
    SystemObjectTypeInformation,        // 0x0038+ + (n * 0x0030+)
    SystemPageFileInformation,          // 0x0018+ per page file
    SystemVdmInstemulInformation,       // 0x0088
    SystemVdmBopInformation,            // invalid info class
    SystemCacheInformation,             // 0x0024
    SystemPoolTagInformation,           // 0x0004 + (n * 0x001C)
    SystemInterruptInformation,         // 0x0000, or 0x0018 per cpu
    SystemDpcInformation,               // 0x0014
    SystemFullMemoryInformation,        // checked build only
    SystemLoadDriver,                   // 0x0018, set mode only
    SystemUnloadDriver,                 // 0x0004, set mode only
    SystemTimeAdjustmentInformation,    // 0x000C, 0x0008 writeable
    SystemSummaryMemoryInformation,     // checked build only
    SystemNextEventIdInformation,       // checked build only
    SystemEventIdsInformation,          // checked build only
    SystemCrashDumpInformation,         // 0x0004
    SystemExceptionInformation,         // 0x0010
    SystemCrashDumpStateInformation,    // 0x0004
    SystemDebuggerInformation,          // 0x0002
    SystemContextSwitchInformation,     // 0x0030
    SystemRegistryQuotaInformation,     // 0x000C
    SystemAddDriver,                    // 0x0008, set mode only
    SystemPrioritySeparationInformation,// 0x0004, set mode only
    SystemPlugPlayBusInformation,       // not implemented
    SystemDockInformation,              // not implemented
    SystemPowerInfo,             // 0x0060 (XP only!)
    SystemProcessorSpeedInformation,    // 0x000C (XP only!)
    SystemTimeZoneInformation,          // 0x00AC
    SystemLookasideInformation,         // n * 0x0020
    SystemSetTimeSlipEvent,
    SystemCreateSession,    // set mode only
    SystemDeleteSession,    // set mode only
    SystemInvalidInfoClass1,   // invalid info class
    SystemRangeStartInformation,   // 0x0004 (fails if size != 4)
    SystemVerifierInformation,
    SystemAddVerifier,
    SystemSessionProcessesInformation, // checked build only
    MaxSystemInfoClass
} SYSTEMINFOCLASS, *PSYSTEMINFOCLASS;

这个结构再MSDN上只列举了一部分,这是网上搜索的结构,可以访问http://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ex/sysinfo/query.htm查看详细的信息,其包含了我们所需要的一个参数SystemHandleInformation 用来获取系统中进程的句柄信息,第二个参数是缓冲区指针,第三个参数是大小,最后一个参数是实际的返回的数据大小。
传入SystemHandleInformation 将会返回一个SYSTEM_HANDLE_INFORMATION结构,结构如下:

typedef struct _SYSTEM_HANDLE_INFORMATION
{
    ULONG   uCount;
    SYSTEM_HANDLE aSH[];
} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;

typedef struct _SYSTEM_HANDLE
{
    ULONG  uIdProcess;
    UCHAR  ObjectType;    // OB_TYPE_* (OB_TYPE_TYPE, etc.)
    UCHAR  Flags;         // HANDLE_FLAG_* (HANDLE_FLAG_INHERIT, etc.)
    USHORT  Handle;
    PVOID  pObject;
    ACCESS_MASK GrantedAccess;
} SYSTEM_HANDLE, *PSYSTEM_HANDLE;

3 查找句柄对应的进程,获取句柄对应的文件名

通过查询返回句柄的进程pid与传入的PID比较。若符合,OpenProcess 打开该进程,DuplicateHanle复制句柄,然后获取句柄的文件名,然后相对路径转换为绝对路径。
获取句柄的详细信息用到了ZwQueryInformationFile 函数,这个函数同样是一个未文档化的函数,

HMODULE hNtDLL = LoadLibrary(L"NTDLL.DLL");
if (!hNtDLL)
{
    return 1;
}

ZwQueryInformationFile = (ZWQUERYINFORMATIONFILE)GetProcAddress(hNtDLL, "ZwQueryInformationFile");

typedef NTSTATUS(WINAPI *ZWQUERYINFORMATIONFILE)(HANDLE, PIO_STATUS_BLOCK, PVOID,ULONG, FILE_INFORMATION_CLASS);
ZWQUERYINFORMATIONFILE ZwQueryInformationFile;

NTSTATUS 
  ZwQueryInformationFile(
    IN HANDLE  FileHandle,
    OUT PIO_STATUS_BLOCK  IoStatusBlock,
    OUT PVOID  FileInformation,
    IN ULONG  Length,
    IN FILE_INFORMATION_CLASS  FileInformationClass
    );

第一个参数是文件句柄,第二个参数是接收最终完成状态的IO_STATUS_BLOCK结构的指针。第三个参数是存储返回的文件对象的信息,第四个参数是缓冲区大小,第五个参数是文件信息的类型,我们传入FileNameInformation。在这里我们定义了一个结构体 PNM_INFO ,用来存储信息

typedef struct _NM_INFO
{
    HANDLE  hFile;
    FILE_NAME_INFORMATION Info;
    WCHAR Name[MAX_PATH];
} NM_INFO, *PNM_INFO;

第三个成员即为文件名包括路径,不过是相对路径,调用 PathResolve
获取绝对路径。到此文件的全路径就获取到了。
代码地址如下:
https://github.com/scuzhangzhang/GetFileFullPath/tree/master/GetFileFullPath

相关文章

网友评论

      本文标题:获取打开的文件的全路径(2)

      本文链接:https://www.haomeiwen.com/subject/cznsjftx.html