• Win64 驱动内核编程-29.强制解锁文件


    强制解锁文件

        强制解锁因其他进程占用而无法删除的文件。

    1.调用 ZwQuerySystemInformation 的 16 功能号来枚举系统里的句柄

    2.打开拥有此句柄的进程并把此句柄复制到自己的进程

    3.用 ZwQueryObject 查询句柄的类型和名称

    4.如果 发现此句柄的类型是文件句柄, 名称和被锁定的文件一致,就关闭此句柄

    5.重复 2、3、4 步,直到遍历完系统里所有的句柄

    第4步中因为是要解锁其他进程占用的文件所以有如下细节:

    1.用 KeStackAttachProcess“依附”到目标进程

    2.用 ObSetHandleAttributes 设置句柄为“可以关闭”

    3.用 ZwClose 关闭句柄

    4.用 KeUnstackDetachProcess 脱离“依附”目标进程

    以下代码适用于Win7  X64,如果想支持全系统,请对应调教。

    #include <ntddk.h>
     
    #define kprintf	DbgPrint
    #define kmalloc(_s)	ExAllocatePoolWithTag(NonPagedPool, _s, 'SYSQ')
    #define kfree(_p)	ExFreePool(_p)
     
    typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO{
    USHORT	UniqueProcessId;
    USHORT	CreatorBackTraceIndex;
    UCHAR	ObjectTypeIndex;
    UCHAR	HandleAttributes;
    USHORT	HandleValue;
    PVOID	Object;
    ULONG	GrantedAccess;
    } SYSTEM_HANDLE_TABLE_ENTRY_INFO, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO;
     
    typedef struct _SYSTEM_HANDLE_INFORMATION {
        ULONG64 NumberOfHandles;
    SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1];
    } SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
     
    NTSYSAPI
    NTSTATUS
    NTAPI
    ZwQueryObject
    (
    HANDLE	Handle,
    ULONG	ObjectInformationClass,
    PVOID	ObjectInformation,
    ULONG	ObjectInformationLength,
    PULONG	ReturnLength OPTIONAL
    );
     
    NTSYSAPI
    NTSTATUS
    NTAPI
    ZwQuerySystemInformation
    (   
    ULONG	SystemInformationClass,
    PVOID	SystemInformation,
    ULONG	SystemInformationLength,
    PULONG	ReturnLength
    );
     
    NTSYSAPI
    NTSTATUS
    NTAPI
    ZwDuplicateObject
    (
    HANDLE	SourceProcessHandle,
    HANDLE	SourceHandle,
    HANDLE	TargetProcessHandle OPTIONAL,
    PHANDLE 	TargetHandle OPTIONAL,
    ACCESS_MASK	DesiredAccess,
    ULONG	HandleAttributes,
    ULONG	Options
    );
     
    NTSYSAPI
    NTSTATUS
    NTAPI
    ZwOpenProcess
    (    
    PHANDLE	ProcessHandle,
    ACCESS_MASK	AccessMask,
    POBJECT_ATTRIBUTES	ObjectAttributes,
    PCLIENT_ID	ClientId
    );
     
    typedef enum _OBJECT_INFORMATION_CLASS {
        ObjectBasicInformation,
        ObjectNameInformation,
        ObjectTypeInformation,
        ObjectAllInformation,
        ObjectDataInformation
    } OBJECT_INFORMATION_CLASS, *POBJECT_INFORMATION_CLASS;
     
    typedef struct _OBJECT_BASIC_INFORMATION {
      ULONG                   Attributes;
      ACCESS_MASK             DesiredAccess;
      ULONG                   HandleCount;
      ULONG                   ReferenceCount;
      ULONG                   PagedPoolUsage;
      ULONG                   NonPagedPoolUsage;
      ULONG                   Reserved[3];
      ULONG                   NameInformationLength;
      ULONG                   TypeInformationLength;
      ULONG                   SecurityDescriptorLength;
      LARGE_INTEGER           CreationTime;
    } OBJECT_BASIC_INFORMATION, *POBJECT_BASIC_INFORMATION;
     
    /*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 struct _KAPC_STATE 
    {
    LIST_ENTRY ApcListHead[2];
    PVOID Process;
    BOOLEAN KernelApcInProgress;
    BOOLEAN KernelApcPending;
    BOOLEAN UserApcPending;
    }KAPC_STATE, *PKAPC_STATE;
     
    typedef struct _OBJECT_HANDLE_FLAG_INFORMATION{
    BOOLEAN Inherit;
    BOOLEAN ProtectFromClose;
    }OBJECT_HANDLE_FLAG_INFORMATION, *POBJECT_HANDLE_FLAG_INFORMATION;
     
    NTKERNELAPI 
    NTSTATUS 
    ObSetHandleAttributes (HANDLE Handle, POBJECT_HANDLE_FLAG_INFORMATION HandleFlags, KPROCESSOR_MODE PreviousMode);
     
    NTKERNELAPI 
    VOID 
    KeStackAttachProcess(PEPROCESS PROCESS, PKAPC_STATE ApcState);
     
    NTKERNELAPI 
    VOID 
    KeUnstackDetachProcess(PKAPC_STATE ApcState);
     
    NTKERNELAPI 
    NTSTATUS 
    PsLookupProcessByProcessId (IN HANDLE ProcessId,OUT PEPROCESS *Process);
     
    PEPROCESS LookupProcess(HANDLE Pid)
    {
    PEPROCESS eprocess=NULL;
    if( NT_SUCCESS(PsLookupProcessByProcessId(Pid, &eprocess)) )
    return eprocess;
    else
    return NULL;
    }
     
    VOID UnicodeStringToCharArray(PUNICODE_STRING dst, char *src)
    {
    ANSI_STRING string;
    if( dst->Length>260 ) return;
    RtlUnicodeStringToAnsiString(&string,dst, TRUE); 
    strcpy(src,string.Buffer);
    RtlFreeAnsiString(&string); 
    }
     
    VOID ForceCloseHandle(PEPROCESS Process, ULONG64 HandleValue)
    {
    HANDLE h;
    KAPC_STATE ks;
    OBJECT_HANDLE_FLAG_INFORMATION ohfi;
    if( Process==NULL )
    return;
    if( !MmIsAddressValid(Process) )
    return;
    KeStackAttachProcess(Process, &ks);
    h=(HANDLE)HandleValue;
    ohfi.Inherit=0;
    ohfi.ProtectFromClose=0;
    ObSetHandleAttributes(h, &ohfi, KernelMode);
    ZwClose(h);
    KeUnstackDetachProcess(&ks);
    }
     
    VOID CloseFileHandle(char *szFileName)
    {
    PVOID Buffer;
    ULONG BufferSize = 0x20000, rtl=0;
    NTSTATUS Status, qost=0;
    NTSTATUS ns = STATUS_SUCCESS;
    ULONG64 i=0;
    ULONG64 qwHandleCount;
    SYSTEM_HANDLE_TABLE_ENTRY_INFO *p;
        OBJECT_BASIC_INFORMATION BasicInfo;
        POBJECT_NAME_INFORMATION pNameInfo;
        ULONG ulProcessID;
        HANDLE hProcess;
        HANDLE hHandle;
        HANDLE hDupObj;
    CLIENT_ID cid;
    OBJECT_ATTRIBUTES oa;
    CHAR szFile[260]={0};
    Buffer=kmalloc(BufferSize);
    memset(Buffer,0,BufferSize);
    Status = ZwQuerySystemInformation(16, Buffer, BufferSize, 0);	//SystemHandleInformation
    while(Status == 0xC0000004)	//STATUS_INFO_LENGTH_MISMATCH
    {
    kfree(Buffer);
    BufferSize = BufferSize * 2;
    Buffer=kmalloc(BufferSize);
    memset(Buffer,0,BufferSize);
    Status = ZwQuerySystemInformation(16, Buffer, BufferSize, 0);
    }
    if (!NT_SUCCESS(Status)) return;
    qwHandleCount=((SYSTEM_HANDLE_INFORMATION *)Buffer)->NumberOfHandles;
    p=(SYSTEM_HANDLE_TABLE_ENTRY_INFO *)((SYSTEM_HANDLE_INFORMATION *)Buffer)->Handles;
     
    //ENUM HANDLE PROC
    for(i=0;i<qwHandleCount;i++)
    {
    ulProcessID = (ULONG)p[i].UniqueProcessId;
    cid.UniqueProcess = (HANDLE)ulProcessID;
    cid.UniqueThread = (HANDLE)0;
    hHandle = (HANDLE)p[i].HandleValue;
    InitializeObjectAttributes( &oa ,NULL ,0 ,NULL ,NULL );
    ns = ZwOpenProcess( &hProcess ,PROCESS_DUP_HANDLE ,&oa ,&cid );
    if ( !NT_SUCCESS( ns ) )
    {
    KdPrint(( "ZwOpenProcess : Fail " ));
    continue;
    }
    ns = ZwDuplicateObject( hProcess ,hHandle ,NtCurrentProcess() ,&hDupObj , PROCESS_ALL_ACCESS ,0 ,DUPLICATE_SAME_ACCESS );
    if ( !NT_SUCCESS( ns ) )
    {
    KdPrint(( "ZwDuplicateObject : Fail " ));
    continue;
    }
    //get basic information
    ZwQueryObject( hDupObj ,ObjectBasicInformation ,&BasicInfo , sizeof( OBJECT_BASIC_INFORMATION ) ,NULL );
    //get name information
    pNameInfo = ExAllocatePoolWithTag( PagedPool ,1024 ,'ONON');
    RtlZeroMemory( pNameInfo ,1024 );
    qost=ZwQueryObject( hDupObj, ObjectNameInformation, pNameInfo, 1024, &rtl );
    //get information and close handle
    UnicodeStringToCharArray(&(pNameInfo->Name),szFile);
    ExFreePool( pNameInfo );
    ZwClose(hDupObj);
    ZwClose(hProcess);
    //if(!_stricmp(szFile,szFileName))
    if(strstr(_strlwr(szFile),szFileName))
    {
    PEPROCESS ep=LookupProcess((HANDLE)(p[i].UniqueProcessId));
    ForceCloseHandle(ep,p[i].HandleValue);
    ObDereferenceObject(ep);
    }
    }
    }
     


    执行结果:

    之前:

    启动驱动之后可以成功删除因为其他进程占用而导致的文件无法删除。

    宋孖健,13

  • 相关阅读:
    linux nfs
    gsoap
    error: ignoring return value of 编译错误处理
    SSIS可靠性和扩展性—错误输出
    SSIS中的脚本—脚本组件
    SQL点滴24—监测表的变化(转载)
    SSIS中的脚本—脚本任务
    SSIS可靠性和扩展性—简介
    SSIS中的脚本—表达式
    SSIS可靠性和扩展性—可扩展性
  • 原文地址:https://www.cnblogs.com/csnd/p/12061986.html
Copyright © 2020-2023  润新知