<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          技術(shù)版:文件被占用無法刪除怎么辦?

          共 13900字,需瀏覽 28分鐘

           ·

          2021-01-14 20:37

          技術(shù)版:文件被占用無法刪除怎么辦?了解一點(diǎn)操作系統(tǒng)知識(shí)的同學(xué)們應(yīng)該都知道,文件占用無法刪除,是因?yàn)槟承┻M(jìn)程正在使用該文件。

          要?jiǎng)h除這樣的文件,就需要讓那些進(jìn)程關(guān)閉文件,然后自然可以刪除。

          一句話的事,那究竟要怎么用代碼來實(shí)現(xiàn)這個(gè)功能呢?

          打開和關(guān)閉文件

          還記得上大學(xué)第一門語(yǔ)言課-C語(yǔ)言,迄今為止還依然活躍并被一直使用的語(yǔ)言。

          比匯編容易理解,又更接近底層,所以Windows操作系統(tǒng)內(nèi)核大部分代碼都是用C語(yǔ)言來編寫的。

          在C的課程里,我們學(xué)過通過FILE來操作使用文件,比如:

          FILE *fp;
          fp = fopen("c:\\temp\\test.txt", "r")

          通過讀的方式打開一個(gè)文件,使用非常簡(jiǎn)單,后續(xù)通過fp這個(gè)結(jié)構(gòu)體指針操作文件即可。

          其實(shí)fopen并不接近操作系統(tǒng),他是對(duì)win32 API CreateFile的封裝。

          也就是前者是標(biāo)準(zhǔn)庫(kù)接口,在Windows、linux、unix等都是通用接口。

          而后者才是和操作系統(tǒng)關(guān)聯(lián)緊密,由微軟自己提供的API。

          要更好的理解進(jìn)程如何使用文件的,我們還得看看CreateFile這個(gè)API接口。

          HANDLE CreateFileA(
          LPCSTR lpFileName,
          DWORD dwDesiredAccess,
          DWORD dwShareMode,
          LPSECURITY_ATTRIBUTES lpSecurityAttributes,
          DWORD dwCreationDisposition,
          DWORD dwFlagsAndAttributes,
          HANDLE hTemplateFile
          );

          這是msdn對(duì)CreateFile的定義,簡(jiǎn)單來看我們可以只關(guān)注lpFileName和返回值,lpFileName傳遞你要打開的文件,返回值是操作系統(tǒng)給你的一個(gè)代表文件的句柄(handle)。

          HANDLE hFile = CreateFileA("c:\\temp\\test.txt", ...);

          要對(duì)文件進(jìn)行讀、寫等操作都需要這個(gè)句柄,也就是說這個(gè)句柄至關(guān)重要,它表示文件正在被使用。

          然后什么時(shí)候結(jié)束使用呢,我們需要看另一個(gè)API CloseHandle.

          BOOL CloseHandle(
          HANDLE hObject
          );

          CloseHandle用于關(guān)閉一個(gè)正在被使用的文件,通過句柄來關(guān)閉。

          現(xiàn)在明白過來了嗎,只要我們讓進(jìn)程調(diào)用CloseHandle這個(gè)API,關(guān)閉被占用的文件句柄,那么該文件也就被解除占用了。

          哈哈,是不是很簡(jiǎn)單。

          枚舉占用文件的進(jìn)程

          那么我就想問同學(xué)們一個(gè)問題,怎么知道哪些進(jìn)程在使用我們想刪除的文件呢?怎么去查找?

          帶著這個(gè)問題,我們繼續(xù)往下看。

          我們來想一個(gè)問題,操作系統(tǒng)給調(diào)用CreateFile的用戶返回了一個(gè)句柄,然后通過句柄來操作文件,那操作系統(tǒng)是如何知道句柄代表哪個(gè)文件呢?

          我們簡(jiǎn)單思考一下,我們要達(dá)到這個(gè)目的有沒有什么方法,比如我用一個(gè)數(shù)組來存用戶打開的文件路徑,而數(shù)組序號(hào)就返回給用戶,下次用戶就只需要把序號(hào)給我,我就知道要操作什么問題了。

          演示代碼,忽略細(xì)節(jié)
          LPWSTR FileTable[100] = {0};
          HANDLE CreateFileA(
          LPCSTR lpFileName,
          ...)
          {
          for(int i = 0; i < 100; i ++) {
          if(FileTable[i] == NULL) { //還有空位
          FileTable[i] = lpFileName; //保存路徑
          return (HANDLE)i; //返回句柄
          }
          }
          return NULL;
          }
          BOOL CloseHandle(
          HANDLE hObject
          ) {
          if((int)hObject < 100) {
          if(FileTable[hObject]) {
          FileTable[hObject] = NULL;//找到文件路徑
          return TRUE;
          }
          }
          return FALSE;
          }

          上面簡(jiǎn)單的代碼演示了一下我們粗略考略的文件和句柄的關(guān)系以及句柄的管理,那操作系統(tǒng)是不是這么做的呢?其實(shí)也差不多。

          任意進(jìn)程,只要每打開一個(gè)對(duì)象(包括文件、進(jìn)程、線程等等),就會(huì)獲得一個(gè)句柄。

          這個(gè)句柄用來標(biāo)志對(duì)某個(gè)對(duì)象的一次打開,通過句柄,可以直接找到對(duì)應(yīng)的內(nèi)核對(duì)象。

          每個(gè)進(jìn)程都有一個(gè)句柄表,用來記錄本進(jìn)程打開的所有內(nèi)核對(duì)象。

          句柄表可以簡(jiǎn)單看做為一個(gè)一維數(shù)組,每個(gè)表項(xiàng)就是一個(gè)句柄,一個(gè)結(jié)構(gòu)體,一個(gè)句柄描述符。

           struct _HANDLE_TABLE_ENTRY  //句柄描述符
          struct _HANDLE_TABLE //句柄表描述符

          好,更加細(xì)節(jié)的句柄表的原理我們不用再深究,我們只需要知道每個(gè)進(jìn)程都有一個(gè)句柄表,通過句柄表就可以找到打開的文件。

          這就是我們的目的,我們需要查到進(jìn)程是不是打開了我們要?jiǎng)h除的文件,我們需要查句柄表。

          那怎么查呢?

          操作系統(tǒng)給用戶提供了一個(gè)接口ZwQuerySystemInformation。

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

          它可以獲取系統(tǒng)非常多的信息,包括進(jìn)程、模塊、處理器、內(nèi)存等等各種信息。

          而SystemHandleInformation = 16就能獲取到系統(tǒng)所有的句柄信息。

          typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO
          {
          USHORT UniqueProcessId;//所屬進(jìn)程
          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
          {
          ULONG NumberOfHandles;
          SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1];
          } SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;

          既然知道了方法,下面就開始枚舉所有句柄,找到我們被占用的文件的進(jìn)程信息。

          Status = ZwQuerySystemInformation(SystemHandleInformation,
          Information,
          Length,
          &ReturnLength);

          for (i = 0; i < Information->NumberOfHandles; i++) {
          if (Information->Handles[i].UniqueProcessId != CurrentProcessId) {//不是當(dāng)前進(jìn)程
          Status = ZwQueryObject(TargetHandle, ObjectTypeInformation, &TypeInfo, sizeof(TypeInfo), NULL);
          RtlInitUnicodeString(&TargetType, L"File");
          if (!RtlEqualUnicodeString(&TypeInfo.Info.TypeName, &TargetType, FALSE)) {
          goto __next;
          }
          Status = ZwQueryObject(TargetHandle, ObjectNameInformation, &NameInfo, sizeof(NameInfo), NULL);
          if (RtlEqualUnicodeString(&NameInfo.Info.Name, &FileName, FALSE)) {
          printf("在進(jìn)程(%d)發(fā)現(xiàn)文件占用:(%x) %wZ\n",
          ProcessId,
          Information->Handles[i].HandleValue,
          &NameInfo.Info.Name);
          }
          }
          }

          ZwQuerySystemInformation獲取到所有句柄信息,通過循環(huán)枚舉Information->Handles,找到句柄類型屬于File,路徑是目標(biāo)文件的進(jìn)程。

          ZwQueryObject傳入ObjectTypeInformation可以獲取句柄類型,ZwQueryObject傳入ObjectNameInformation可以獲取文件路徑。

          如此兩個(gè)條件的對(duì)比,就能讓我們找到占用文件的進(jìn)程了。

          是不是感覺還挺簡(jiǎn)單,不復(fù)雜嘛。

          坑一:ZwQueryObject

          前面提到,每個(gè)進(jìn)程都有自己的句柄表,所以ZwQuerySystemInformation枚舉拿到的句柄并不能直接使用,還需要復(fù)制一份到本進(jìn)程才有效。

          系統(tǒng)也提供了API叫做DuplicateHandle:

          BOOL DuplicateHandle(
          HANDLE hSourceProcessHandle,
          HANDLE hSourceHandle,
          HANDLE hTargetProcessHandle,
          LPHANDLE lpTargetHandle,
          DWORD dwDesiredAccess,
          BOOL bInheritHandle,
          DWORD dwOptions
          );

          DuplicateHandle(hSrcProc, Information->Handles[i].HandleValue, hCurProc, TargetHandle, ...);

          上面我們使用的TargetHandle就是通過復(fù)制獲取的。

          這個(gè)地方并不是坑,而是在通過ZwQueryObject獲取句柄對(duì)應(yīng)的文件路徑時(shí),會(huì)發(fā)生阻塞,導(dǎo)致程序卡死無法繼續(xù)運(yùn)行。

          0: kd> kv
          # ChildEBP RetAddr Args to Child
          00 d7fdb7cc 828aacda 00000000 00000000 a7d73040 nt!KiSwapContext+0x19 (FPO: [Uses EBP] [1,0,4])
          01 d7fdb86c 828aa358 d7fdb930 a7d73120 a7d73040 nt!KiSwapThread+0x4aa (FPO: [Non-Fpo])
          02 d7fdb8c8 828a9d67 00000000 00000000 00000000 nt!KiCommitThreadWait+0x128 (FPO: [Non-Fpo])
          03 d7fdb978 829298a3 8ff18afc 00000000 a7d73300 nt!KeWaitForSingleObject+0x1f7 (FPO: [Non-Fpo])
          04 d7fdb9a4 82c0759f 88c0e801 d7fdba18 8ff18ab0 nt!IopWaitForLockAlertable+0x3f (FPO: [Non-Fpo])
          05 d7fdb9cc 82d3f75c 88c0e800 a7d733f8 d7fdb9ef nt!IopWaitAndAcquireFileObjectLock+0x41 (FPO: [Non-Fpo])
          06 d7fdba1c 82bed31a 000001ee d7fdbb01 9a651dc0 nt!IopQueryXxxInformation+0x150f3e
          07 d7fdba9c 82becf65 00000000 007af7a4 00000210 nt!IopQueryNameInternal+0x31a (FPO: [Non-Fpo])
          08 d7fdbab8 82bece25 8ff18ab0 87ff2400 007af7a4 nt!IopQueryName+0x1b (FPO: [Non-Fpo])
          09 d7fdbb40 82bec6a6 00000210 d7fdbc04 d7fdbb01 nt!ObQueryNameStringMode+0x495 (FPO: [Non-Fpo])
          0a d7fdbbf8 829cce6b 8ff18ab0 00000000 007af7a4 nt!NtQueryObject+0x186 (FPO: [SEH])
          0b d7fdbbf8 77cd5ef0 8ff18ab0 00000000 007af7a4 nt!KiSystemServicePostCall (FPO: [0,3] TrapFrame @ d7fdbc14)

          經(jīng)過一些簡(jiǎn)單的分析,如果文件被是同步(SYNCHRONIZE)打開的,內(nèi)核會(huì)等待一下鎖,等其他線程操作完成,本線程才能拿到所有權(quán)。

          //
          // Make a special check here to determine whether this is a synchronous
          // I/O operation. If it is, then wait here until the file is owned by
          // the current thread. If this is not a (serialized) synchronous I/O
          // operation, then initialize the local event.
          //

          if (FileObject->Flags & FO_SYNCHRONOUS_IO) {

          BOOLEAN interrupted;

          if (!IopAcquireFastLock( FileObject )) {
          status = IopAcquireFileObjectLock( FileObject,
          Mode,
          (BOOLEAN) ((FileObject->Flags & FO_ALERTABLE_IO) != 0),
          &interrupted );
          if (interrupted) {
          ObDereferenceObject( FileObject );
          return status;
          }
          }
          KeClearEvent( &FileObject->Event );
          synchronousIo = TRUE;
          }

          所以這里我們就需要通過線程和超時(shí)的方式來調(diào)用ZwQueryObject,讓程序可以不阻塞正常運(yùn)行。

          void
          QueryThread(
          IN PQUERY_CONTEXT Context
          ) {
          Status = ZwQueryObject(TargetHandle, ObjectNameInformation, &NameInfo, sizeof(NameInfo), NULL);
          }

          ThreadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)QueryThread, Context, 0, NULL);
          Result = WaitForSingleObject(ThreadHandle, 1000); //等待1秒超時(shí),線程退出
          TerminateThread(ThreadHandle, 0);
          CloseHandle(ThreadHandle);

          坑二:文件Map

          解決上面的問題之后,我們基本就解決了文件占用的問題,大部分情況下,我們可以正常刪除文件了。

          可是…

          某些時(shí)候,我們要?jiǎng)h除的文件并不是普通文件,可能是一個(gè)DLL、或者其他特殊文件。

          關(guān)閉所有占用的句柄后,依然無法刪除文件,還是提示占用。

          這可怎么辦?

          類似于DLL這種文件,進(jìn)程在使用中,操作系統(tǒng)會(huì)映射一份內(nèi)存到進(jìn)程空間,此時(shí)并沒有句柄與之對(duì)應(yīng)。

          但是它卻關(guān)聯(lián)了文件的內(nèi)核對(duì)象,專業(yè)術(shù)語(yǔ)說增加了一次文件對(duì)象的引用。

          我們要知道,為了能夠安全刪除一個(gè)文件,操作系統(tǒng)需要保證該文件的內(nèi)核對(duì)象在兩種引用計(jì)數(shù)上清零。

          一個(gè)是句柄引用計(jì)數(shù),一個(gè)是對(duì)象引用計(jì)數(shù)。

          前面我們通過枚舉句柄,將句柄引用計(jì)數(shù)清零。

          但是因?yàn)楣蚕韮?nèi)存的原因,對(duì)象引用計(jì)數(shù)仍未清零,所以無法刪除文件。

          0: kd> !handle 48

          PROCESS fffffa801b7c6060
          SessionId: 1 Cid: 0b70 Peb: 7efdf000 ParentCid: 0588
          DirBase: 1bfea000 ObjectTable: fffff8a0029f27e0 HandleCount: 157.
          Image: procexp.exe

          Handle table at fffff8a0029f27e0 with 157 entries in use

          0004: Object: fffffa801bdcca10 GrantedAccess: 00000003 Entry: fffff8a0020cc010
          Object: fffffa801bdcca10 Type: (fffffa8018dcfa30) File
          ObjectHeader: fffffa801bdcc9e0 (new version)
          HandleCount: 0//句柄引用計(jì)數(shù) PointerCount: 1 //對(duì)象引用計(jì)數(shù)

          我們通過!vad倆看看內(nèi)存map。

          0: kd> !vad fffffa8019d34e00
          VAD Level Start End Commit
          fffffa8019d34e00 0 1000 12ce 0 Mapped READONLY \Windows\Globalization\Sorting\SortDefault.nls

          0: kd> dt _mmvad fffffa8019d34e00
          nt!_MMVAD
          +0x000 u1 :
          +0x008 LeftChild : (null)
          +0x010 RightChild : (null)
          +0x018 StartingVpn : 0x1000
          +0x020 EndingVpn : 0x12ce
          +0x028 u :
          +0x030 PushLock : _EX_PUSH_LOCK
          +0x038 u5 :
          +0x040 u2 :
          +0x048 Subsection : 0xfffffa80`1b56ef90 _SUBSECTION
          +0x048 MappedSubsection : 0xfffffa80`1b56ef90 _MSUBSECTION
          +0x050 FirstPrototypePte : 0xfffff8a0`00b02000 _MMPTE
          +0x058 LastContiguousPte : 0xfffff8a0`00b03670 _MMPTE
          +0x060 ViewLinks : _LIST_ENTRY [ 0xfffffa80`18ec81c0 - 0xfffffa80`18fcd190 ]
          +0x070 VadsProcess : 0xfffffa80`1b7c6061 _EPROCESS
          0: kd> dt 0xfffffa80`1b56ef90 _SUBSECTION
          nt!_SUBSECTION
          +0x000 ControlArea : 0xfffffa80`1b56ef10 _CONTROL_AREA
          +0x008 SubsectionBase : 0xfffff8a0`00b02000 _MMPTE
          +0x010 NextSubsection : 0xfffffa80`193a0a60 _SUBSECTION
          +0x018 PtesInSubsection : 0x2cf
          +0x020 UnusedPtes : 0
          +0x020 GlobalPerSessionHead : (null)
          +0x028 u :
          +0x02c StartingSector : 0
          +0x030 NumberOfFullSectors : 0x2cf
          0: kd> dt 0xfffffa80`1b56ef10 _CONTROL_AREA
          nt!_CONTROL_AREA
          +0x000 Segment : 0xfffff8a0`03b31fd0 _SEGMENT
          +0x008 DereferenceList : _LIST_ENTRY [ 0x00000000`00000000 - 0x00000000`00000000 ]
          +0x018 NumberOfSectionReferences : 0
          +0x020 NumberOfPfnReferences : 0x101
          +0x028 NumberOfMappedViews : 0x2a
          +0x030 NumberOfUserReferences : 0x2a
          +0x038 u :
          +0x03c FlushInProgressCount : 0
          +0x040 FilePointer : _EX_FAST_REF
          +0x048 ControlAreaLock : 0n0
          +0x04c ModifiedWriteCount : 0
          +0x04c StartingFrame : 0
          +0x050 WaitList : (null)
          +0x058 u2 :
          +0x068 LockedPages : 1
          +0x070 ViewList : _LIST_ENTRY [ 0xfffffa80`1be91570 - 0xfffffa80`1abbe690 ]
          0: kd> dx -id 0,0,fffffa801b7c6060 -r1 (*((ntkrnlmp!_EX_FAST_REF *)0xfffffa801b56ef50))
          (*((ntkrnlmp!_EX_FAST_REF *)0xfffffa801b56ef50)) [Type: _EX_FAST_REF]
          [+0x000] Object : 0xfffffa801b61fa14 [Type: void *]
          [+0x000 ( 3: 0)] RefCnt : 0x4 [Type: unsigned __int64]
          [+0x000] Value : 0xfffffa801b61fa14 [Type: unsigned __int64]
          0: kd> !object 0xfffffa801b61fa10
          Object: fffffa801b61fa10 Type: (fffffa8018dcfa30) File
          ObjectHeader: fffffa801b61f9e0 (new version)
          HandleCount: 0 PointerCount: 5
          Directory Object: 00000000 Name: \Windows\Globalization\Sorting\SortDefault.nls {HarddiskVolume2}

          0: kd> dt _file_object 0xfffffa801b61fa10
          nt!_FILE_OBJECT
          +0x000 Type : 0n5
          +0x002 Size : 0n216
          +0x008 DeviceObject : 0xfffffa80`19e9d530 _DEVICE_OBJECT
          +0x010 Vpb : 0xfffffa80`19eca270 _VPB
          +0x018 FsContext : 0xfffff8a0`00ad0140 Void
          +0x020 FsContext2 : 0xfffff8a0`00ad0330 Void
          +0x028 SectionObjectPointer : 0xfffffa80`1b61f808 _SECTION_OBJECT_POINTERS
          0: kd> dx -id 0,0,fffffa801b7c6060 -r1 ((ntkrnlmp!_SECTION_OBJECT_POINTERS *)0xfffffa801b61f808)
          ((ntkrnlmp!_SECTION_OBJECT_POINTERS *)0xfffffa801b61f808) : 0xfffffa801b61f808 [Type: _SECTION_OBJECT_POINTERS *]
          [+0x000] DataSectionObject : 0xfffffa801b56ef10 [Type: void *] //其實(shí)就是前面的_mmvad->Subsection->ControlArea
          [+0x008] SharedCacheMap : 0x0 [Type: void *]
          [+0x010] ImageSectionObject : 0x0 [Type: void *]

          SortDefault.nls是被映射到了進(jìn)程中,通過_mmvad->Subsection->ControlArea->FilePointer我們可以一步步定位到它引用的文件對(duì)象。

          !object 0xfffffa801b61fa10看到確實(shí)是該文件,也可以通過fileobject->SectionObjectPointer->DataSectionObject找到對(duì)應(yīng)的映射內(nèi)存。

          如此我們初步理解了文件map導(dǎo)致文件占用無法刪除文件的原理。

          下面我們就需要找到方法怎么解決這個(gè)問題。

          首先,需要枚舉進(jìn)程的虛擬內(nèi)存,找到是否有我們需要查找的文件的map,然后對(duì)該進(jìn)程有兩種操作:

          1. 非常暴力但是簡(jiǎn)單的方法,那就是直接關(guān)閉進(jìn)程

          2. 或者unmap這塊內(nèi)存,解除對(duì)象引用計(jì)數(shù)(經(jīng)過測(cè)試,未成功)

          如何枚舉虛擬內(nèi)存呢,使用ZwQueryVirtualMemory.

          NTSTATUS ZwQueryVirtualMemory(
          _In_ HANDLE ProcessHandle,
          _In_opt_ PVOID BaseAddress,
          _In_ MEMORY_INFORMATION_CLASS MemoryInformationClass,
          _Out_ PVOID MemoryInformation,
          _In_ SIZE_T MemoryInformationLength,
          _Out_opt_ PSIZE_T ReturnLength
          );

          //MemoryBasicInformation
          typedef struct _MEMORY_BASIC_INFORMATION {
          PVOID BaseAddress;
          PVOID AllocationBase;
          ULONG AllocationProtect;
          USHORT PartitionId;
          SIZE_T RegionSize;
          ULONG State;
          ULONG Protect;
          ULONG Type;
          } MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION;

          Type
          The type of pages in the region. The following types are defined.
          MEM_IMAGE 0x1000000 Indicates that the memory pages within the region are mapped into the view of an image section.
          MEM_MAPPED 0x40000 Indicates that the memory pages within the region are mapped into the view of a section.
          MEM_PRIVATE 0x20000 Indicates that the memory pages within the region are private (that is, not shared by other processes).

          從0地址開始,每次加一個(gè)頁(yè),獲取內(nèi)存信息,如果內(nèi)存的type是MEM_IMAGE或者M(jìn)EM_MAPPED,那么就是文件map,然后獲取虛擬內(nèi)存對(duì)應(yīng)名字,判斷是不是目標(biāo)文件。

          for (;;) {
          Status = ZwQueryVirtualMemory(ProcessHandle, BaseAddress, MemoryBasicInformation,
          &MemoryInfo, sizeof(MemoryInfo), NULL);
          if (MemoryInfo.Type == MEM_IMAGE || //image
          MemoryInfo.Type == MEM_MAPPED) { //data
          Status = ZwQueryVirtualMemory(ProcessHandle, BaseAddress, MemoryMappedFilenameInformation, &Name, sizeof(Name), NULL);
          if (RtlEqualUnicodeString(&Name.u, &TargetName, TRUE)) {
          //找到目標(biāo)文件
          break;
          }
          }
          }
          }

          找到目標(biāo)進(jìn)程后,關(guān)閉進(jìn)程,輕松刪除文件。

          (完)

          如果覺得內(nèi)容還不錯(cuò),請(qǐng)不吝點(diǎn)贊或在看,謝謝。

          歡迎關(guān)注公眾號(hào):Anhkgg日記本

          瀏覽 74
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  操骚屄在线视频 | 操骚逼自拍| 波多野吉衣av无码 | 三级在线播放视频 | 秘 黄 视频免费看 |