方法二:
搜索进程空间中的所有句柄,获取句柄的文件名即可。
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
网友评论