• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆-60  評論-262  文章-1  trackbacks-0
            ====================================================================
            以下為轉帖

            操作被占用的文件-unlocker機理分析
            *[標題]: 操作被占用的文件-unlocker機理分析
            *[作者]: gz1X [gz1x(at)tom(dot)com]
                        EagleNet [hklt594(at)163(dot)com]
            *[來自]: 中國黑客聯盟 [CHU]
            *[原始鏈接]: http://blog.china-pub.com/more.asp?name=zzs0405&id=41832

            [前言]
            ——————————————————————
            之前給原作者發過郵件, 不過沒能得到unlocker的源代碼, 所以自己逆向了一份;
            逆向的很匆忙, 因為近來事情太多, 而且unlocker本身也是版權所有, 所以不好做的太露骨;
            本人也還有不少地方不是很明白, 有機會和我聯系, 一起探討 :-)
            感謝EagleNet的討論.


            [關于unlocker]
            ——————————————————————
            Unlocker是一個免費的工具, 原作者的網站是: http://ccollomb.free.fr/unlocker
            當使用者發現有某個文件或目錄無法刪除時, 只要按下鼠標右鍵中的"Unlocker",
            程序會顯示出是哪一些程序占用了該目錄或文件, 接著只要按下"Unlock"就能夠為你的文件解鎖.


            ==============================Here we start=================================

            [大致流程]
            ——————————————————————
            主程序Unlocker.exe通過ZwQuerySystemInformation查詢當前系統的所有句柄信息, 然后調用OpenProcess獲取目標進程句柄,
            遍歷當前所有進程, 根據進程ID, 得到此進程打開的所有句柄信息, 接下來用DuplicateHandle復制Handle到本地進程,
            然后把文件句柄發給驅動UnlockerDriver5.sys進行名字的查詢, sys將返回文件句柄對應的內核文件對象的完整名字.
            確定文件名后, 如果要刪除文件, 則調用OpenProcess與DuplicateHandle關閉句柄, 然后ZwDeleteFile刪除文件.


            [UnlockerAssistant.exe]
            [UnlockerHook.dll]
            ——————————————————————
            UnlockerAssistant.exe主要是實現系統托盤等輔助功能, 同時安裝鉤子:
            .text:00403AC9           public start
            .text:00403AC9 start:
            //...
            .text:00403AD5           call   sub_40391E
            跟進, 能看到主要的實現代碼:
            .text:00403925           call   sub_402E83
            //...
            .text:00403944           push   offset LibFileName ; "UnlockerHook.dll"
            .text:00403949           call   ds:LoadLibraryA
            //...
            .text:0040398A           push   offset ProcName ; "HookInstall"
            .text:00403994           call   edi ; GetProcAddress
            注冊窗口消息, 初始化控件, 安裝鉤子;

            .text:00403A1A           call   ds:Shell_NotifyIconA
            .text:00403A20           call   sub_40359E   ;RegOpenKeyExA...
            設置托盤圖標, 寫入注冊表啟動項;

            .text:00403A69           push   offset s_Hookuninstall ; "HookUninstall"
            卸載鉤子.

            當然也有綠化版本只寫入右鍵, 這些大家自己看反匯編的代碼, 詳細的鉤子過程反匯編UnlockerHook.dll, 也不再做糾纏.
            我們只看UnlockerHook.dll里一處:
            .text:10001102 sub_10001102   proc near           ;
            //...
            .text:10001181           call   ds:GetModuleFileNameW
            .text:1000118E           call   ds:PathRemoveFileSpecW
            //...
            .text:100011A7           push   offset s_SUnlocker_exe ; "\"%s\\Unlocker.exe\""
            //...
            .text:100011E0           call   ds:ShellExecuteExW
            呼出主程序, 進行文件處理.


            [UnlockerDriver5.sys分析]
            ——————————————————————
            反匯編驅動文件, 跳到入口點:
            INIT:00402000 ; int __stdcall start(PDRIVER_OBJECT DriverObject,int)
            INIT:00402000           public start
            INIT:00402000 start       proc near
            //...
            INIT:0040203D           call   ds:IoCreateDevice
            //...
            INIT:004020E3           call   ds:IoCreateSymbolicLink
            //...
            上面就是DriverEntry了. 注意這一段:
            INIT:004020AB           mov   dword ptr [ecx], offset loc_401000
            INIT:004020B1           mov   dword ptr [esi+40h], offset loc_401000
            INIT:004020B8           mov   dword ptr [esi+44h], offset sub_401090
            INIT:004020BF           mov   dword ptr [esi+48h], offset loc_401020
            INIT:004020C6           mov   dword ptr [esi+34h], offset sub_401240
            經典的, 處理MajorFunction[IRP_MJ_DEVICE_CONTROL*(sizeof PVOID)]等等.

            我們跟蹤這兩個函數, 先跟sub_401240, 如下:
            PAGE:0040124D           call   ds:RtlInitUnicodeString
            //...
            PAGE:00401257           call   ds:IoDeleteSymbolicLink
            //...
            PAGE:00401265           call   ds:IoDeleteDevice
            很明顯的DriverUnload函數;

            接著跟sub_401090, 這個函數就是類似于DispatchControl(IRP_MJ_DEVICE_CONTROL)了;
            我們挑關鍵的看, RtlInitUnicodeString函數填充UNICODE_STRING結構就不多做糾纏:
            PAGE:004010FA           call   ds:ObReferenceObjectByHandle
            獲取由句柄描述的對象的指針, 也就是獲取FILE_OBJECT對象;
            這里, 想想內核級文件的Read和Write, 通過HANDLE執行就要先用ObReferenceObjectByHandle函數來獲得Handle對應的FileObject,
            然后我們再給FileObject發送IRP進行實質操作.

            略過分配內存, 接著往下走:
            PAGE:00401158           call   ds:ObQueryNameString
            這個函數將獲取設備名, 然后和FILE_OBJECT的FileName構成完整的名字返回(應用層在注冊表中保存設備名+目錄名);

            PAGE:00401214           call   ds:ObfDereferenceObject
            再一次調用ObfDereferenceObject, 將對象的引用計數器恢復到先前的值, 防止泄漏;

            PAGE:0040122D           call   ds:IofCompleteRequest
            MajorFunction[IRP_MJ_CLOSE*(sizeof PVOID)], 完成操作.

            回頭看看這個驅動, 實際上是很經典也很簡單的驅動程序, 實現的功能也很簡單:
            返回文件句柄對應的內核文件對象的完整名字, 傳給主程序進行文件"刪除""移動"等操作.


            [Unlocker.exe分析]
            ——————————————————————
            直接跳到入口點:
            .text:004135FB           public start
            .text:004135FB start       proc near
            //...
            .text:00413607           call   sub_412EDC
            跟進去, 挑重點:

            .text:00412EEF           call   sub_40D1FF     ; 命令行用法說明
            .text:00412EFC           call   sub_40D78C     ; 查詢注冊表
            .text:00412F0C           push   offset Caption ; "Unlocker 1.8.5"
            .text:00412F11           call   sub_413DEF     ; 創建線程, 網絡升級, 在線輔助
            //...
            .text:00412F1C           mov   ecx, eax
            .text:00412F1E           call   sub_40FA79     ; 這里開始!

            =============================================================================
            我把sub_40FA79列出來(有省略), 如下:
            .text:0040FA79 sub_40FA79     proc near           ; CODE XREF: sub_412EDC+42 p
            .text:0040FA79           push   ebx
            .text:0040FA7A           push   esi
            .text:0040FA7B           push   offset LibFileName ; "ntdll.dll"
            .text:0040FA82           call   ds:LoadLibraryA
            //...
            .text:0040FA8E           push   edi
            .text:0040FA8F           mov   edi, ds:GetProcAddress
            .text:0040FA95           push   offset ProcName ; "ZwQuerySystemInformation"
            .text:0040FA9D           push   offset s_Zwqueryobject ; "ZwQueryObject"
            .text:0040FAA7           push   offset s_Zwdeletefile ; "ZwDeleteFile"
            .text:0040FAB2           push   offset s_Rtlinitunicod ; "RtlInitUnicodeString"
            .text:0040FABD           push   offset s_Rtladjustpriv ; "RtlAdjustPrivilege"
            .text:0040FAC8           push   offset s_Ntloaddriver ; "NtLoadDriver"
            .text:0040FAD3           push   offset s_Ntunloaddrive ; "NtUnloadDriver"
            .text:0040FAD8           push   ebx         ; hModule
            .text:0040FAD9           mov   [esi+14h], eax
            .text:0040FADC           call   edi ; GetProcAddress

            這一段的代碼是unlocker的重點部分, 獲取ntdll.dll地址后, 調用其中的函數:
            1)ZwQuerySystemInformation函數獲得系統當前所以進程的所建立的句柄及其相關信息;
            2)ZwQueryObject獲取句柄所代表對象信息, 查出目標文件(設備名+目錄名);
            3)ZwDeleteFile刪除目標文件;
            4)NtLoadDriver加載驅動, 當然還需要后面的注冊表修改;
            ===========================================================================

            再往下:
            .text:00412F9E           call   ds:PathRemoveFileSpecW
            .text:00412FAB           push   offset s_SUnlocker_cfg ; "%s\\Unlocker.cfg"
            .text:00412FB5           call   ds:wsprintfW
            //...
            .text:00412FC2           call   sub_40D3F4
            跟進sub_40D3F4函數, 發現作用是將驅動信息寫入注冊表;

            .text:00413008           push   dword ptr [eax+8] ; lpFileName
            .text:0041300B           call   sub_410E28
            //...
            .text:004133E8           call   ds:QueryDosDeviceA
            //...
            .text:004134B7           push   offset s_DeviceLanmanr ; "\\Device\\LanmanRedirector"
            .text:004134BC           push   eax         ; LPWSTR
            .text:004134BD           mov   [ebp+lpSrch], eax
            .text:004134C0           call   ds:wsprintfW
            遍歷查詢DOS設備, 進行重定向;

            .text:00413504           mov   esi, ds:DialogBoxParamA     
            .text:0041350A           mov   edi, ds:GetModuleHandleA
            //...
            .text:00413529           call   sub_411A59   //--->getfullname
            創建一個對話框窗口, 顯示所有枚舉出的相關進程;
            sub_411A59函數將獲取對象文件的完整名, 并返回, 我們跟進去:

            .text:00411F63           push   dword ptr [esi] ; dwProcessId
            .text:00411F65           mov   edi, ds:OpenProcess
            .text:00411F6B           push   ebx         ; bInheritHandle
            .text:00411F6C           push   450h         ; dwDesiredAccess
            .text:00411F71           call   edi ; OpenProcess
            之前是進程和模塊遍歷, 找到相關聯的所有進程和模塊, OpenProcess打開需要操作的文件;

            .text:00411F93           call   ds:GetCurrentProcess
            //...
            .text:00411FA2           call   ds:DuplicateHandle
            獲取本地進程, 將對象進程的句柄復制到本地進程(句柄進程相關);

            .text:00411FBB           push   offset s_?Unlockerdriv ; "\\\\?\\UnlockerDriver5"
            .text:00411FC0           call   ds:CreateFileW
            //...
            將句柄發送給驅動程序, 驅動將返回文件句柄對應的內核文件對象的完整名字;


            [文件操作選擇]
            ——————————————————————
            現在退出sub_411A59函數返回主線, 我們走到這里:
            .text:00413536           cmp   byte ptr [eax+3], 0
            .text:0041353A           jz     short loc_41357B
            .text:0041353A
            .text:0041353C           mov   eax, cInitial
            .text:00413541           test   eax, eax
            .text:00413543           jz     short loc_413571   ; "移動"或者"重命名"操作;
            .text:00413543
            .text:00413545           xor   ebx, ebx
            .text:00413547           test   eax, eax
            .text:00413549           jbe   short loc_41355F   ; "刪除"操作
            這里將進行文件處理的選擇, 是無動作? 刪除? 還是移動? 重命名?

            .text:0041353A           jz     short loc_41357B
            //...
            .text:0041357B           xor   ebx, ebx
            .text:0041357D           cmp   cInitial, ebx
            .text:00413583           jz     short loc_4135AE
            cInitial存放的值代表當前的窗口是否為初始窗口;

            a)
            我們先看是派生窗口時的處理, loc_4135AE:
            .text:004135B5           push   offset sub_412D62 ; lpDialogFunc
            //...
            .text:00412DA4           push   [esp+800h+hDlg] ; hDlg
            .text:00412DAB           call   sub_412371   //-->toMoveFile
            生成一個瀏覽對話框供選擇路徑保存文件:
            .text:004123AB           call   sub_410064
            //--->
            .text:00410082           call   ds:CoInitialize
            .text:004100D6           call   ds:SHBrowseForFolderW
            .text:004100E4           call   ds:SHGetPathFromIDListW
            .text:004100F4           call   ds:CoUninitialize
            //<---
            .text:004123DE           call   ds:PathIsDirectoryW
            .text:0041242C           call   ds:GetSaveFileNameW
            .text:00412451           call   sub_4115AE     //-->inject

            實際上查看sub_412371這個函數的交叉引用(實際上你不用看引用也很容易就會發現), 會發現:
            .text:00412478 sub_412478     proc near     //-->GuiControlDeal
            這里是一個對話框, 也就是我們右鍵unlocker時產生的界面, 它將生成unlocker的主界面,
            也將處理各種用戶操作的消息, 發給各個子程序去處理;

            回到:
            .text:004135C7           call   esi ; DialogBoxParamA
            .text:004135CF           call   sub_410F86   //-->MoveFile
            由于cInitial值為0, 所以此時必定是用戶選擇了"移動"或"重命名";

            =========================================================================
            跟進sub_410F86, 看到:
            .text:00410F96           jnz   loc_4110C2     ; 重命名
            //...
            .text:00411145           call   esi ; wsprintfW
            //...
            .text:00411173           call   edi ; SHFileOperationW
            //...
            .text:00411166           mov   [ebp+FileOp.wFunc], 4   ;ReName
            text:00411217             call   edi ; SHFileOperationW
            調用wsprintfW格式化路徑后, 填充SHFILEOPSTRUCT結構, 由SHFileOperationW來重命名, 完成后調用MessageBoxA通知完成;

            否則就是"移動"操作:
            .text:00411048           call   sub_410BB2   //-->getdirfile
            //--->
            .text:00410C20           call   ds:FindFirstFileW
            .text:00410C95           call   ds:FindNextFileW
            //<---
            .text:00411064           call   ds:MoveFileExW
            .text:00411076           jnz   short loc_41105F ; 循環移動目錄下的所有文件
            .text:00411093           jb     loc_410FBF     //-->deleteDir
            //...
            .text:004113E4           push   eax         ; int
            .text:004113E5           mov   eax, lpSrch
            .text:004113EA           push   [ebp+var_8]   ; int
            .text:004113ED           add   eax, esi
            .text:004113EF           push   eax         ; lpExistingFileName
            .text:004113F0           call   sub_410462   //-->movefile
            到這里就完成了這兩項功能, 不過注意函數里壓棧時的參數:

            .text:00411281           call   getdirfile
            //...
            .text:00411302           push   4           ; MOVEFILE_DELAY_UNTIL_REBOOT
            .text:00411304           lea   eax, [ebp+NewFileName]
            .text:0041130A           push   eax         ; lpNewFileName
            .text:0041130B           push   dword ptr [edi] ; lpExistingFileName
            .text:0041130D           call   ds:MoveFileExW
            這段代碼的意思是, 如果暫時處理不了用戶請求的文件操作, 那就在系統重新啟動時實行操作;
            ========================================================================

            接著:
            .text:004135DE           cmp   [ebp+var_9], 0
            .text:004135E2           jnz   loc_413514
            返回, 重新獲取文件的完整名, 重繪主窗口;

            .text:004135E8           call   sub_40D51D
            .text:004135ED           call   sub_413B8F
            ds:GlobalFree釋放內存后, 調用了sub_40D51D, 它刪除了注冊表里的sys服務, 然后sub_413B8F休眠, 繼續等待操作觸發;

            b)
            現在我們回到a)處, 考慮另一種情況, cInitial==1:

            .text:00413586           push   offset GuiControlDeal ; lpDialogFunc
            .text:00413596           call   esi ; DialogBoxParamA
            //...
            .text:00413568           push   [ebp+hMem]
            .text:0041356B           call   sub_41178F   //--->CloseFileHandle
            此時的文件操作是"刪除"(或者"無動作");

            sub_41178F函數的作用就是實現刪除文件, 我們看:

            .text:004117FB           call   ds:OpenProcess
            //...
            .text:0041180D           call   ds:TerminateProcess
            //...
            .text:00411819           cmp   eax, 0FFFFFFFFh
            .text:0041181C           jnz   loc_4119F8
            判斷目標文件是哪種類型文件, exe還是dll? 是exe則跳到loc_4119F8處;

            .text:0041182E           call   ds:OpenProcess
            //...
            .text:00411868           call   GetModuleFileNameExW
            //...
            .text:00411873           push   offset s__dll   ; ".DLL"
            .text:00411878           push   eax         ; pszPath
            .text:00411879           call   sub_40FC27
            文件是dll類型, 獲取其路徑;

            .text:0041189F           push   offset s_SUS   ; "/s /u \"%s\""
            //...
            .text:004118B3           mov   [ebp+ExecInfo.lpVerb], offset s_Open ; "open"
            .text:004118BA           mov   [ebp+ExecInfo.lpFile], offset s_Regsvr32_exe ; "regsvr32.exe"
            //...
            .text:004118DA           call   ds:ShellExecuteExW
            先將模塊注銷掉, 使用regsvr32.exe /s /u實現;

            .text:00411944           push   offset s_Freelibrary ; "FreeLibrary"
            //...
            .text:00411966           push   offset s_Closehandle ; "CloseHandle"
            然后通過FreeLibrary來釋放, 調用GetModuleHandleW查詢句柄后, 用CloseHandle將其關閉;

            注意這一段代碼:
            .text:00411888           push   0Eh
            .text:0041188A           pop   ecx
            也就是說循環將進行0EH(14)次, FreeLibrary也將執行14次直到dll被釋放;

            .text:00411921           call   esi ; WriteProcessMemory
            .text:00411933           call   edi ; VirtualAllocEx
            .text:004119A8           call   esi ; WriteProcessMemory
            .text:004119B5           call   ds:CreateRemoteThread
            想必您已經注意到了這些代碼, 對, 思路就是用線程注入到目標進程去調用FreeLibrary來釋放dll;

            現在我們來到loc_4119F8處, 也就是上文提到的如果文件是exe文件時的處理方法:
            .text:00411A07           call   ds:OpenProcess
            .text:00411A1B           call   ds:GetCurrentProcess
            .text:00411A28           call   ds:DuplicateHandle
            .text:00411A3C           call   ds:CloseHandle
            還是先打開文件, 然后調用DuplicateHandle, 但是這里傳遞的參數是DUPLICATE_CLOSE_SOURCE標志, 將強制關閉句柄;

            ===========================EOF===But to be modified========================


            [后語]
            ——————————————————————
            突然發現沒結尾, 被老大姐罵了, 補充一個吧.
            unlocker最主要的功能實現都在unlocker.exe和一個.sys驅動里, 值得關注的是它怎么實現的關閉句柄和刪除文件.
            關鍵的函數 (部分也是未公開的API) , 比如:
            ZwQuerySystemInformation、 ZwQueryObject、ZwDeleteFile、ObReferenceObjectByHandle、ObQueryNameString、 SHFileOperationW、MoveFileExW、DuplicateHandle.
            這里尤其是DuplicateHandle和MoveFileExW比較有意思.
            詳細的界面構造沒有去研究, 就是這句:
            .text:00412478 sub_412478     proc near     //-->GuiControlDeal
            跟進去分析就是界面的相關操作了, 太煩, 本人時間有限, 如果有人愿意繼續, 記得把結果分享一份給我, 謝謝.



            *[參考資料]:
            ——————————————————————
            1. Windows平臺內核級文件訪問   baiyuanfan
            2. unlocker1.8.5       http://ccollomb.free.fr/unlocker
            3. Kmd教程-全功能的驅動程序分析   羅云彬

            4. http://forum.sysinternals.com/forum_posts.asp?TID=7974

            ==========================================================================

            另一篇: http://windknown.spaces.live.com/blog/cns!627D8DB6EC5BD4A7!435.entry

            April 07
            UnLocker帶來的思考
                這幾個禮拜已經是忙得焦頭爛額了, 這2天還偏偏和unlocker這個軟件耗上了, 我的睡眠時間啊~~
                UnLocker是一款可以用來刪除已被占用文件的軟件, http://ccollomb.free.fr/unlocker/
                通常的刪除文件是通過調用win32 api的DeleteFile來執行的, 該函數會檢查是否有引用該文件的句柄, 因此若有進程打開了該文件是無法刪除的. 另外說一下該api的執行過程, 打開文件-〉設置為刪除-〉關閉文件, 此時系統會自動刪除該文件. 設置是通過主控制號為IRP_MJ_SET_INFORMATION的IRP進行的, IO 棧的Parameters.SetFile.FileInformationClass值為 FileDispositionInformation, AssociatedIrp.SystemBuffer指向結構 FILE_DISPOSITION_INFORMATION, 其成員DeleteFile設置為TRUE. 于是乎, 如果在自己的文件過濾驅動里過濾該 IRP, 只需要改為FASLE就可以防止文件被刪除了.
                說一下另一種刪除文件的方法, 也就是unlocker使用的, ntdll導出的ZwDeleteFile, 該函數的原理沒有細究, 但是同樣也是會檢查句柄的.
                因此, 要刪除文件的關鍵是需要關閉打開的文件句柄, 而句柄是與進程相關的. 今天仔細逆向了一下unlocker, 包括主程序和一個sys文件.
                sys文件的作用是返回文件句柄對應的內核文件對象的完整名字, 例如: \Device\HarddiskVolum1\mytest.doc,  \Device\HarddiskVolum1就是C:這個卷的設備名. 大致流程就是調用ObReferenceObjectByHandle通過對象獲取FILE_OBJECT對象, 然后通過ObQuerNameString查詢FILE_OBJECT中的DeviceObject指針獲取設備名, 再與 FILE_OBJECT的FileName構成完整的名字返回.
                主程序是通過 ZwQuerySystemInformation 查詢 handle 信息, 類型為 SystemHandleInformation, 然后調用 OpenProcess 獲取目標進程句柄, 再用 DuplicateHandle 復制 Handle 為本進程, 再通過驅動查詢名字, 確定文件名. 一定記住句柄是進程相關的, MSDN里描述, 例如在DriverEntry中打開的句柄是在system進程下, 因此在驅動DispatchFunction中不可用, 因為DispatchFunction的進程上下文為與驅動通信的進程. 當要刪除文件時, 對于打開的文件, unlocker仍然是通過OpenProcess與DuplicateHandle, 只是指定了 DUPLICATE_CLOSE_SOURCE標志, 真是大開眼界阿, 如此便關閉了句柄, 高. 而對于dll就沒有那么方便了, unlocker會用線程注入到目標進程去調用FreeLibrary來釋放dll, 因此可能不夠穩定, 而且逆向時發現注入的代碼只嘗試0x10次Free, 呵呵我load20次自己就可以搞定撈.
                然后看MSDN過程中發現了另一個nb函數, SetHandleInformation, 設置這個標志 HANDLE_FLAG_PROTECT_FROM_CLOSE , 那么 unlocker 調用 DuplicateHandle 也關不掉你的句柄了, 試驗了一下, 果然說刪不了撈, hoho
                整這些鳥東西弄了我一天時間, 唉, 許久不逆向, 生疏了不少~~而且因為在虛擬機里調試, 老破機器這個卡啊~~睡覺去!
                順便一提, 今天發現國內搞安全的兄弟們共享精神不如國外阿, 唉, 環境使然, 人嗎首先還是要自己生存的. 想想自己也快畢業了, 有點迷惘, 畢業了干啥工作去捏……生存阿生存


            ============================================================================
            第三篇: http://blog.vckbase.com/windowssky/archive/2007/04/18/25565.html

            小議文件保護和鎖定技術

              近1年來互連網上的木馬越來越多, 有的還刪除不掉, 要切換到dos才可行, 如: CNNC, 3721等, 實現技術也五花八門, 但就文件不可刪除的實現技術可分三類:

              1 Attach file system; 這種技術和Filemon/sfilter查不多, 就是掛一個 filter 驅動到 fs 上, 其他函數都是 passthru 下去, 只處理 IRP_MJ_SET_INFORMATION, 當發現有刪除需保護文件的 IRP, 就
            Irp->IoStatus.Status = STATUS_SUCCESS;            
            Irp->IoStatus.Information = 0;            
            IoCompleteRequest(Irp, IO_NO_INCREMENT);
            根本不讓 Fs 去處理, 從而達到文件不可刪除的作用!

            有什么方法可以刪除呢? 自己寫個驅動自己填充 irp 包 (見 OSR 文檔 Rolling Your Own) , 直接發送 IRP 到 File System Device 上去就 ok 啦!


              2 修改 file system 的 dispatch 函數表; 首先得到 Fs 的 DriverObject (根據驅動名得到驅動設備對象 (ObReferenceObjectByName(IoDriverObjectType))), pDriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = MySetInformation, 然后在 MySetInformation 中再調用原來的調度函數, 類似于 HookApi; 發現有刪除需保護文件的 IRP, 就直接 IoCompleteRequest, 根本不讓原來的 FsSetInformation 處理!

            有什么方法可以刪除呢? 自己寫個驅動來修復 Fs 的 dispatch 函數表, 讀 Fs 的原始文件, 根據 PE 文件得到 Fs 的 Entrypoint, dispatch 函數表的填充都在 EntryPoint 后面, 我們可以根據 Opcode 查找, XX XX XX XX 就是我們要找的 dispatch 的原始地址; 找到后 pDriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = XX XX XX XX, 然后就能刪除文件啦!

            FunOpc=MajorFunction*4+0x38
            C7 46 FunOpc[<80]  XX XX XX XX  mov     dword ptr [esi+50h], offset _NtfsFsdSetInformation
            C7 86 FunOpc[>=80] XX XX XX XX
            C7 43 FunOpc[<80]  XX XX XX XX  mov     dword ptr [ebx+50h], offset _NtfsFsdSetInformation
            C7 83 FunOpc[>=80] XX XX XX XX


              3 通過 ZwCreateFile 把文件鎖定; 刪除時報告 "文件正在使用, 禁止刪除", 具體原理自己摸索吧, 反正是通過 ZwCreateFile 實現的!

            有什么方法可以刪除呢?
              step1: 通過 QuerySystemInformation(SystemHandleInformation) 得到當前系統的所有句柄信息
              step2: 遍歷當前所有進程, 根據進程 ID, 得到此進程打開的所有句柄信息
              Step3: 把句柄發送給我們的驅動程序, 驅動程序根據 ObQueryNameString 得到句柄的路徑信息, 然后再傳給我們的應用程序
              Step4: 如果是我們要刪除文件的路徑, 應用程序調用 DuplicateHandle(DUPLICATE_CLOSE_SOURCE), 句柄被關閉了, 現在可以刪除文件了!
              注: QuerySystemInformation 的使用說明見 The Undocumented Functions, 或者 http://undocumented.ntinternals.net, 第三種解除文件鎖定的方法是我反匯編 Unlocker 軟件學習到的


              最后感謝 7cat 的幫助!

            ====================================================================
            以下為原創

            free2000fly 按:
            unlocker 軟件真是搞的百轉千回, 還用到了驅動, 其實不必要, 在ring3是可以通過文件句柄得到文件名的, 以下是刪除已被鎖定文件的代碼:
            BOOL DeleteLockedFile(DWORD dwProcessID, HANDLE hFile)
            {
                TCHAR szTargetName[MAX_PATH] 
            = { 0 };
                HANDLE hTargeFile 
            = INVALID_HANDLE_VALUE;
                HANDLE hProcess 
            = NULL;
                BOOL bResult 
            = FALSE;
                
                
            do 
                {
                    hProcess 
            = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessID);
                    
            if (NULL == hProcess) {
                        
            break;
                    }
                    
                    
            if (FALSE == DuplicateHandle(hProcess, hFile, 
                        GetCurrentProcess(), 
            &hTargeFile, 
                        
            0, FALSE, DUPLICATE_SAME_ACCESS)) 
                    {
                        
            break;
                    }
                    
                    
            if (INVALID_HANDLE_VALUE==hTargeFile || NULL==hTargeFile) {
                        
            break;
                    }

                    
            if (FALSE == GetFilePathFromHandle(hTargeFile, 
                        szTargetName, _countof(szTargetName))) 
                    {
                        
            break;
                    }

                    CloseHandle(hTargeFile);
                    hTargeFile 
            = INVALID_HANDLE_VALUE;
                    
                    
            if (0 == lstrlen(szTargetName)) {
                        
            break;
                    }
                    
                    
            if (FALSE == DuplicateHandle(hProcess, hFile, 
                        GetCurrentProcess(), 
            &hTargeFile, 
                        
            0, FALSE, 
                        DUPLICATE_SAME_ACCESS
            |DUPLICATE_CLOSE_SOURCE))  // 關鍵標志
                    {
                        
            break;
                    }

                    
            if (INVALID_HANDLE_VALUE==hTargeFile || NULL==hTargeFile) {
                        
            break;
                    }
                    
                    CloseHandle(hTargeFile);
                    hTargeFile 
            = INVALID_HANDLE_VALUE;

                    bResult 
            = DeleteFile(szTargetName);
                } 
            while (FALSE);

                
            if (INVALID_HANDLE_VALUE != hTargeFile && NULL != hTargeFile) {
                    CloseHandle(hTargeFile);
                }
                
                
            if (hProcess) {
                    CloseHandle(hProcess);
                }
                
            return bResult;
            }
            其中函數 GetFilePathFromHandle 的實現請看我的 另一篇博文 " 從文件句柄得到文件路徑的函數 "

            PS. 最近幾天試圖實現枚舉已打開所有文件的功能, 我卻一而再,再而三的在函數 NtQueryObject 和 ZwQueryInformationFile 上遭遇掛起的現象, 這兩個函數在被調用后有可能不再返回, 軟件失去響應, 這是相當要命的事, 后來的解決方法是, 用一個獨立的線程來調用這兩個函數, 如果超時則立即返回, 但在需要講求效率的場合這個解決方法行不通. 查遍網絡才發現這可能算是 Windows 系列操作系統的一個 BUG.  因此, 最后, 還是回到了必須使用驅動的老路上去了.  2009.12.05

            參考:
            http://www.codeproject.com/KB/shell/OpenedFileFinder.aspx
            http://www.codeproject.com/Articles/35202/GetFinalPathNameByHandle-API-Hangs.aspx
            http://www.codeguru.com/forum/showthread.php?t=359606
            http://bbs.pediy.com/showthread.php?t=60190

            posted on 2009-07-14 02:45 free2000fly 閱讀(6644) 評論(2)  編輯 收藏 引用

            評論:
            # re: 操作被占用的文件-unlocker機理分析 2009-12-22 14:05 | marihees
            大哥您好,小弟有一點不明白 DeleteLockedFile(DWORD dwProcessID, HANDLE hFile) dwProcessID這個鎖定文件的進程ID如何獲得? hFile傳入的是?我想改成DeleteLockedFile(CString strFilePath) 該如何做呢?  回復  更多評論
              
            # re: 操作被占用的文件-unlocker機理分析 2012-05-07 11:33 | 斷了的貓
            強大 謝謝分享   回復  更多評論
              
            久久精品国产WWW456C0M| 久久av无码专区亚洲av桃花岛| 韩国免费A级毛片久久| 国产国产成人精品久久| 国产精品99久久久久久猫咪| 亚洲人成电影网站久久| 国产产无码乱码精品久久鸭 | 国产成人精品久久免费动漫| 久久综合视频网站| 国产精品无码久久综合| 一本久久精品一区二区| 日本精品久久久中文字幕 | 久久综合狠狠综合久久97色| 久久99国产精品久久99小说| 久久精品草草草| 亚洲av日韩精品久久久久久a| 国内精品久久久久国产盗摄| 伊人久久大香线焦AV综合影院 | 久久久久99精品成人片牛牛影视| 久久精品国产亚洲av麻豆蜜芽| 亚洲国产精品热久久| 人人狠狠综合久久88成人| 要久久爱在线免费观看| 99热精品久久只有精品| 69久久夜色精品国产69| 亚洲精品国产美女久久久| 久久综合亚洲色一区二区三区| 精品久久久无码中文字幕天天| 久久99国产精品99久久| 久久福利青草精品资源站| 久久久婷婷五月亚洲97号色| 天天爽天天狠久久久综合麻豆| 久久综合久久美利坚合众国| 热99RE久久精品这里都是精品免费 | 99久久精品国产一区二区三区| 久久精品国产99国产精品澳门| av无码久久久久久不卡网站| av无码久久久久不卡免费网站| 久久99精品久久久久久久不卡| 亚洲中文字幕无码一久久区| 久久亚洲熟女cc98cm|