之所以产生这个想法,是在删除文件的时候有时会提示文件被占用了,然后让我们先关闭之后在来删除,但是我怎么知道哪个进程打开了我的文件?
于是就去网上了找了一份代码然后改了改,接着来说说是怎么实现功能的。首先我们需要遍历所有的进程,所有要找到遍历进程的代码。
//遍历进程
WCHAR * szServerName = NULL;
HANDLE WtsServerHandle = WTSOpenServer(szServerName);
PWTS_PROCESS_INFO pWtspi;
DWORD dwCount;
if (!WTSEnumerateProcesses(WtsServerHandle, 0, 1, &pWtspi, &dwCount))
return 0;
//printf("tottal process %d", dwCount);
for (DWORD i = 0; i < dwCount; i++){
printf("ProcessID: %d (%ls)\n", pWtspi[i].ProcessId,pWtspi[i].pProcessName);
}
现在我们能够拿到每一个进程的id,那么怎么通过进程的id拿到它的句柄信息呢?这里可以通过ZwQueryInformationProcess未文档话的函数,得到它的句柄总数,具体的参数如下
typedef NTSTATUS (WINAPI *ZWQUERYINFORMATIONPROCESS)(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength);
其中它的第二个参数表示的是我们需要查询的内容,第三个是返回的内容,第四个是长度,最后一个不管。
通过上述函数我们能拿到当前进程的所有句柄的总数,但是需要注意的是句柄的后两位代表的是句柄的属性,也就是说,所有的句柄都是4的倍数,举一个例子,后两位不能使用了是吧,那么现在最小能使用的就是4=100二进制数,每增加一个就是增加4的倍数8=1000。拿pchunter随便看一个进程的伪句柄表,直观的看到句柄都是4的倍数。
我们现在有了每一个进程的进程句柄总数,那么只需要枚举所有的句柄不就行了吗,但是问题又来了,我们现在拿到的是伪句柄不能正常的使用,需要使用DuplicateHandle复制句柄。之后又会用到例外一个未文档话的函数ZwQueryObject,它可以查看得到当前的对象的类型和对象的名字,
typedef NTSTATUS (WINAPI *ZWQUERYOBJECT)(HANDLE OPTIONAL, OBJECT_INFORMATION_CLASS, PVOID OPTIONAL, ULONG, PULONG OPTIONAL);
最后还有一个问题,就算我们知道了每一个进程的句柄种类和名字,我们又怎么修改它呢?DuplicateHandle不仅可以复制句柄,还可以关闭源句柄。
DUPLICATE_CLOSE_SOURCE(0x00000001) Closes the source handle. This occurs regardless of any error status returned.
DUPLICATE_SAME_ACCESS(0x00000002) Ignores the dwDesiredAccess parameter. The duplicate handle has the same access as the source handle.
那么最后重新整理一下思路,首先是遍历所有进程得到每一个进程的伪句柄,之后使用DuplicateHandlede复制真实的句柄,判断句柄的属性,判断句柄名字是不是我们想要的,是在干掉句柄。这里有一个小细节需要说一下就是在使用ZwQueryObject的查询句柄名字的时候会出现卡死的情况。这时我们需要创建一个新的线程来执行这个操作,避免在主线程中一直卡住。最后整理的代码如下。
#include<windows.h>
#include<stdio.h>
#include <Wtsapi32.h>
#pragma comment (lib,"Wtsapi32.lib")
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
typedef enum _POOL_TYPE {
NonPagedPool,
NonPagedPoolExecute,
PagedPool,
NonPagedPoolMustSucceed,
DontUseThisType,
NonPagedPoolCacheAligned,
PagedPoolCacheAligned,
NonPagedPoolCacheAlignedMustS,
MaxPoolType,
NonPagedPoolBase,
NonPagedPoolBaseMustSucceed,
NonPagedPoolBaseCacheAligned,
NonPagedPoolBaseCacheAlignedMustS,
NonPagedPoolSession,
PagedPoolSession,
NonPagedPoolMustSucceedSession,
DontUseThisTypeSession,
NonPagedPoolCacheAlignedSession,
PagedPoolCacheAlignedSession,
NonPagedPoolCacheAlignedMustSSession,
NonPagedPoolNx,
NonPagedPoolNxCacheAligned,
NonPagedPoolSessionNx
} POOL_TYPE;
typedef enum _OBJECT_INFORMATION_CLASS {
ObjectBasicInformation,
ObjectNameInformation,
ObjectTypeInformation,
ObjectAllInformation,
ObjectDataInformation
} OBJECT_INFORMATION_CLASS, *POBJECT_INFORMATION_CLASS;
typedef struct
{
USHORT Length; //当前名称长度
USHORT MaxLen; //缓冲区最大长度
USHORT *Buffer; //Unicode 名称指针
}UNICODE_STRING, *PUNICODE_STRING;
typedef struct _OBJECT_NAME_INFORMATION {
UNICODE_STRING Name;
WCHAR NameBuffer[0];
} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;
typedef struct _OBJECT_TYPE_INFORMATION {
UNICODE_STRING TypeName;
ULONG TotalNumberOfHandles;
ULONG TotalNumberOfObjects;
WCHAR Unused1[8];
ULONG HighWaterNumberOfHandles;
ULONG HighWaterNumberOfObjects;
WCHAR Unused2[8];
ACCESS_MASK InvalidAttributes;
GENERIC_MAPPING GenericMapping;
ACCESS_MASK ValidAttributes;
BOOLEAN SecurityRequired;
BOOLEAN MaintainHandleCount;
USHORT MaintainTypeList;
POOL_TYPE PoolType;
ULONG DefaultPagedPoolCharge;
ULONG DefaultNonPagedPoolCharge;
} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;
typedef enum _SYSTEM_INFORMATION_CLASS {
SystemBasicInformation, // 0 Y N
SystemProcessorInformation, // 1 Y N
SystemPerformanceInformation, // 2 Y N
SystemTimeOfDayInformation, // 3 Y N
SystemNotImplemented1, // 4 Y N
SystemProcessesAndThreadsInformation, // 5 Y N
SystemCallCounts, // 6 Y N
SystemConfigurationInformation, // 7 Y N
SystemProcessorTimes, // 8 Y N
SystemGlobalFlag, // 9 Y Y
SystemNotImplemented2, // 10 Y N
SystemModuleInformation, // 11 Y N
SystemLockInformation, // 12 Y N
SystemNotImplemented3, // 13 Y N
SystemNotImplemented4, // 14 Y N
SystemNotImplemented5, // 15 Y N
SystemHandleInformation, // 16 Y N
SystemObjectInformation, // 17 Y N
SystemPagefileInformation, // 18 Y N
SystemInstructionEmulationCounts, // 19 Y N
SystemInvalidInfoClass1, // 20
SystemCacheInformation, // 21 Y Y
SystemPoolTagInformation, // 22 Y N
SystemProcessorStatistics, // 23 Y N
SystemDpcInformation, // 24 Y Y
SystemNotImplemented6, // 25 Y N
SystemLoadImage, // 26 N Y
SystemUnloadImage, // 27 N Y
SystemTimeAdjustment, // 28 Y Y
SystemNotImplemented7, // 29 Y N
SystemNotImplemented8, // 30 Y N
SystemNotImplemented9, // 31 Y N
SystemCrashDumpInformation, // 32 Y N
SystemExceptionInformation, // 33 Y N
SystemCrashDumpStateInformation, // 34 Y Y/N
SystemKernelDebuggerInformation, // 35 Y N
SystemContextSwitchInformation, // 36 Y N
SystemRegistryQuotaInformation, // 37 Y Y
SystemLoadAndCallImage, // 38 N Y
SystemPrioritySeparation, // 39 N Y
SystemNotImplemented10, // 40 Y N
SystemNotImplemented11, // 41 Y N
SystemInvalidInfoClass2, // 42
SystemInvalidInfoClass3, // 43
SystemTimeZoneInformation, // 44 Y N
SystemLookasideInformation, // 45 Y N
SystemSetTimeSlipEvent, // 46 N Y
SystemCreateSession, // 47 N Y
SystemDeleteSession, // 48 N Y
SystemInvalidInfoClass4, // 49
SystemRangeStartInformation, // 50 Y N
SystemVerifierInformation, // 51 Y Y
SystemAddVerifier, // 52 N Y
SystemSessionProcessesInformation // 53 Y N
} SYSTEM_INFORMATION_CLASS;
typedef enum _PROCESSINFOCLASS
{
ProcessBasicInformation = 0, // 0, q: PROCESS_BASIC_INFORMATION, PROCESS_EXTENDED_BASIC_INFORMATION
ProcessQuotaLimits, // qs: QUOTA_LIMITS, QUOTA_LIMITS_EX
ProcessIoCounters, // q: IO_COUNTERS
ProcessVmCounters, // q: VM_COUNTERS, VM_COUNTERS_EX
ProcessTimes, // q: KERNEL_USER_TIMES
ProcessBasePriority, // s: KPRIORITY
ProcessRaisePriority, // s: ULONG
ProcessDebugPort, // q: HANDLE
ProcessExceptionPort, // s: HANDLE
ProcessAccessToken, // s: PROCESS_ACCESS_TOKEN
ProcessLdtInformation, // 10
ProcessLdtSize,
ProcessDefaultHardErrorMode, // qs: ULONG
ProcessIoPortHandlers, // (kernel-mode only)
ProcessPooledUsageAndLimits, // q: POOLED_USAGE_AND_LIMITS
ProcessWorkingSetWatch, // q: PROCESS_WS_WATCH_INFORMATION[]; s: void
ProcessUserModeIOPL,
ProcessEnableAlignmentFaultFixup, // s: BOOLEAN
ProcessPriorityClass, // qs: PROCESS_PRIORITY_CLASS
ProcessWx86Information,
ProcessHandleCount, // 20, q: ULONG, PROCESS_HANDLE_INFORMATION
ProcessAffinityMask, // s: KAFFINITY
ProcessPriorityBoost, // qs: ULONG
ProcessDeviceMap, // qs: PROCESS_DEVICEMAP_INFORMATION, PROCESS_DEVICEMAP_INFORMATION_EX
ProcessSessionInformation, // q: PROCESS_SESSION_INFORMATION
ProcessForegroundInformation, // s: PROCESS_FOREGROUND_BACKGROUND
ProcessWow64Information, // q: ULONG_PTR
ProcessImageFileName, // q: UNICODE_STRING
ProcessLUIDDeviceMapsEnabled, // q: ULONG
ProcessBreakOnTermination, // qs: ULONG
ProcessDebugObjectHandle, // 30, q: HANDLE
ProcessDebugFlags, // qs: ULONG
ProcessHandleTracing, // q: PROCESS_HANDLE_TRACING_QUERY; s: size 0 disables, otherwise enables
ProcessIoPriority, // qs: ULONG
ProcessExecuteFlags, // qs: ULONG
ProcessResourceManagement,
ProcessCookie, // q: ULONG
ProcessImageInformation, // q: SECTION_IMAGE_INFORMATION
ProcessCycleTime, // q: PROCESS_CYCLE_TIME_INFORMATION
ProcessPagePriority, // q: ULONG
ProcessInstrumentationCallback, // 40
ProcessThreadStackAllocation, // s: PROCESS_STACK_ALLOCATION_INFORMATION, PROCESS_STACK_ALLOCATION_INFORMATION_EX
ProcessWorkingSetWatchEx, // q: PROCESS_WS_WATCH_INFORMATION_EX[]
ProcessImageFileNameWin32, // q: UNICODE_STRING
ProcessImageFileMapping, // q: HANDLE (input)
ProcessAffinityUpdateMode, // qs: PROCESS_AFFINITY_UPDATE_MODE
ProcessMemoryAllocationMode, // qs: PROCESS_MEMORY_ALLOCATION_MODE
ProcessGroupInformation, // q: USHORT[]
ProcessTokenVirtualizationEnabled, // s: ULONG
ProcessConsoleHostProcess, // q: ULONG_PTR
ProcessWindowInformation, // 50, q: PROCESS_WINDOW_INFORMATION
ProcessHandleInformation, // q: PROCESS_HANDLE_SNAPSHOT_INFORMATION // since WIN8
ProcessMitigationPolicy, // s: PROCESS_MITIGATION_POLICY_INFORMATION
ProcessDynamicFunctionTableInformation,
ProcessHandleCheckingMode,
ProcessKeepAliveCount, // q: PROCESS_KEEPALIVE_COUNT_INFORMATION
ProcessRevokeFileHandles, // s: PROCESS_REVOKE_FILE_HANDLES_INFORMATION
MaxProcessInfoClass
}PROCESSINFOCLASS;
//上面为需要用到的结构体和枚举
//定义函数指针
typedef NTSTATUS (NTAPI *ZWQUERYSYSTEMINFORMATION)( SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength OPTIONAL);
ZWQUERYSYSTEMINFORMATION ZwQuerySystemInformation = NULL;
typedef NTSTATUS (WINAPI *ZWQUERYOBJECT)(HANDLE OPTIONAL, OBJECT_INFORMATION_CLASS, PVOID OPTIONAL, ULONG, PULONG OPTIONAL);
ZWQUERYOBJECT ZwQueryObject = NULL;
typedef NTSTATUS (WINAPI *ZWQUERYINFORMATIONPROCESS)(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength);
ZWQUERYINFORMATIONPROCESS ZwQueryInformationProcess = NULL;
//初始化未文档化函数
BOOL InitUnDocumentProc()
{
HMODULE hNtdll = GetModuleHandle("Ntdll.dll");
if (hNtdll == NULL) return FALSE;
ZwQuerySystemInformation = (ZWQUERYSYSTEMINFORMATION)GetProcAddress(hNtdll, "NtQuerySystemInformation");
ZwQueryObject = (ZWQUERYOBJECT)GetProcAddress(hNtdll, "NtQueryObject");
ZwQueryInformationProcess = (ZWQUERYINFORMATIONPROCESS)GetProcAddress(hNtdll, "NtQueryInformationProcess");
if ((ZwQuerySystemInformation == NULL) || (ZwQueryObject == NULL) || (ZwQueryInformationProcess == NULL))
return FALSE;
return TRUE;
}
//象征性的提权,其实用处不大
BOOL EnableDebugPrivilege()
{
HANDLE hToken;
LUID sedebugnameValue;
TOKEN_PRIVILEGES tkp;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)){
return FALSE;
}
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue)){
CloseHandle(hToken);
return FALSE;
}
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Luid = sedebugnameValue;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL)){
CloseHandle(hToken);
return FALSE;
}
return TRUE;
}
//查询名字的时候会卡死
HANDLE hDuplicate = NULL;
OBJECT_NAME_INFORMATION *ObjectName;
char BufferForObjectName[1024];
UINT WINAPI ZwThreadProc(PVOID lpParma){
ZwQueryObject((HANDLE)hDuplicate, ObjectNameInformation, BufferForObjectName, sizeof(BufferForObjectName), NULL);
ObjectName = (POBJECT_NAME_INFORMATION)BufferForObjectName;
//MessageBoxA(0,0,0,0);
}
int main()
{
EnableDebugPrivilege();
InitUnDocumentProc();
NTSTATUS Status;
HANDLE hSource = NULL;
DWORD HandleCount;
OBJECT_TYPE_INFORMATION *ObjectType;
char BufferForObjectType[1024];
//遍历进程
WCHAR * szServerName = NULL;
HANDLE WtsServerHandle = WTSOpenServer(szServerName);
PWTS_PROCESS_INFO pWtspi;
DWORD dwCount;
if (!WTSEnumerateProcesses(WtsServerHandle, 0, 1, &pWtspi, &dwCount))
return 0;
//printf("tottal process %d", dwCount);
/*for (DWORD i = 0; i < dwCount; i++){
printf("ProcessID: %d (%ls)\n", pWtspi[i].ProcessId,pWtspi[i].pProcessName);
}*/
for (DWORD j = 0; j < dwCount; j++) {
hSource = OpenProcess(PROCESS_ALL_ACCESS | PROCESS_DUP_HANDLE | PROCESS_SUSPEND_RESUME, FALSE, pWtspi[j].ProcessId);
if (hSource != NULL) {
DWORD dwHandle;
Status = ZwQueryInformationProcess(hSource, ProcessHandleCount, &HandleCount, sizeof(HandleCount), NULL);
//printf("total size %d \n", HandleCount);
for (DWORD i = 1; i <= HandleCount; i++) {//穷举句柄
dwHandle = i * 4;
//复制一个句柄对象 && 判断此句柄是否有效
if (DuplicateHandle(hSource, (HANDLE)dwHandle, GetCurrentProcess(), &hDuplicate, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
ZeroMemory(BufferForObjectName, 1024);
ZeroMemory(BufferForObjectType, 1024);
//获取句柄类型
Status = ZwQueryObject(hDuplicate, ObjectTypeInformation, BufferForObjectType, sizeof(BufferForObjectType), NULL);
ObjectType = (OBJECT_TYPE_INFORMATION*)BufferForObjectType;
if (Status == STATUS_INFO_LENGTH_MISMATCH || !NT_SUCCESS(Status))
continue;
//获取句柄名,会卡死,所以这里只有开一个线程
//Status = ZwQueryObject((HANDLE)hDuplicate, ObjectNameInformation, BufferForObjectName, sizeof(BufferForObjectName), NULL);
//ObjectName = (POBJECT_NAME_INFORMATION)BufferForObjectName;
//if (Status == STATUS_INFO_LENGTH_MISMATCH || !NT_SUCCESS(Status))
//continue;
HANDLE hThread = CreateThread(NULL, 0, ZwThreadProc, NULL, 0, NULL);
DWORD dwSatu = WaitForSingleObject(hThread, 53); // 等待,直到线程被激发
if (dwSatu == WAIT_TIMEOUT) {
hThread = OpenThread(THREAD_TERMINATE, FALSE, hThread);
if (!TerminateThread(hThread, 0)) {
CloseHandle(hThread);
}
CloseHandle(hThread);
//MessageBoxA(0, 0, 0, 0);
continue;
}
//关闭复制的句柄
CloseHandle(hDuplicate);
//printf("Type:%S\tName:%S\tHandle:%X\n", ObjectType->TypeName.Buffer,ObjectName->Name.Buffer, hDuplicate);
if (ObjectName->Name.Buffer!=NULL&&!strcmp(ObjectType->TypeName.Buffer, L"File")&& wcsstr(ObjectName->Name.Buffer,L"msyh.ttc")) {//判断是不是文件类型,判断关闭文件对不对
printf("pid %d \tName:%S\tHandle:%X\n", pWtspi[j].ProcessId, ObjectName->Name.Buffer, hDuplicate);
//printf("pid %d \tName:%S\n", pWtspi[j].ProcessId, ObjectType->TypeName.Buffer);
//关闭符合的句柄
DuplicateHandle(hSource, (HANDLE)dwHandle, GetCurrentProcess(), &hDuplicate,0,FALSE,DUPLICATE_CLOSE_SOURCE);
CloseHandle(hDuplicate);
}
}
}
CloseHandle(hSource);
}
}
system("pause");
return 0;
}