2009年2月17日 星期二

Unlocker .NET

下載 Unlocker.NET.dll

軟體名稱:Unlocker.NET.dll
版本:v 1.0
軟體作者:cuteofdragon
軟體授權:學術使用免費軟體
軟體類型:Library
軟體開發:Visual Studio .NET 2005 C#
發佈時間:2009/02/18

簡介
Unlocker .NET 是一個純粹採用 .NET C# 撰寫的 dll,目的為處理在 Windows 檔案系統下強制關閉正在被其它程序使用的檔案 Handle,使目前正在處理的程序可以對該檔案進行讀取或刪除等動作。

原理說明
Unlocker .NET 主要使用到 Microsoft 未公開文件的 ntdll.dll 裡面的函式,透過 .NET Interop 技術呼叫原生 Win32 函式,並揭露如何將 C-Style 函式指標轉換成 .NET C# delegate 型式。以下說明相關技術實作。

所使用到的 ntdll.dll 函式指標原型宣告如下:
typedef DWORD (WINAPI *PNtQueryObject)( HANDLE, DWORD, VOID*, DWORD, VOID* );
typedef DWORD (WINAPI *PNtQuerySystemInformation)( DWORD, VOID*, DWORD, ULONG* );
typedef DWORD (WINAPI *PNtQueryInformationFile)(HANDLE, PVOID, PVOID, DWORD, DWORD );

載入函式指標方法:
PNtQueryObject NtQueryObject;
PNtQuerySystemInformation NtQuerySystemInformation;
PNtQueryInformationFile NtQueryInformationFile;

NtQueryObject = (PNtQueryObject) GetProcAddress( GetModuleHandle( _T( "ntdll.dll" ) ), _T("NtQueryObject") );
NtQuerySystemInformation = (PNtQuerySystemInformation) GetProcAddress( GetModuleHandle( _T( "ntdll.dll" ) ), _T("NtQuerySystemInformation") );
NtQueryInformationFile = (PNtQueryInformationFile) GetProcAddress( GetModuleHandle( _T( "ntdll.dll" ) ), _T("NtQueryInformationFile") );

轉換後的 C# delegate 原型宣告如下:
delegate uint NtQueryObjectDelegate(IntPtr hHandle, uint dw1, [MarshalAs(UnmanagedType.LPArray)] byte[] buffer, uint bufferLength, ref uint needLength);
delegate uint NtQuerySystemInformationDelegate(uint dw1, IntPtr systemHandleInformation, uint bufferSize, ref uint needLength);
delegate uint NtQueryInformationFileDelegate(IntPtr hHandle, uint[] iob, IntPtr buffer, uint bufferSize, uint dw2);

delegate 取得 C-Style 函式指標方法:
IntPtr ntQueryObjectPtr = IntPtr.Zero;
IntPtr ntQuerySystemInformationPtr = IntPtr.Zero;
IntPtr ntQueryInformationFilePtr = IntPtr.Zero;

NtQueryObjectDelegate ntQueryObjectDelegate = null;
NtQuerySystemInformationDelegate ntQuerySystemInformationDelegate = null;
NtQueryInformationFileDelegate ntQueryInformationFileDelegate = null;

ntQueryObjectPtr = NativeMethod.GetProcAddress(NativeMethod.GetModuleHandle("ntdll.dll"), "NtQueryObject");
ntQuerySystemInformationPtr = NativeMethod.GetProcAddress(NativeMethod.GetModuleHandle("ntdll.dll"), "NtQuerySystemInformation");
ntQueryInformationFilePtr = NativeMethod.GetProcAddress(NativeMethod.GetModuleHandle("ntdll.dll"), "NtQueryInformationFile");

ntQueryObjectDelegate = (NtQueryObjectDelegate)Marshal.GetDelegateForFunctionPointer(ntQueryObjectPtr, typeof(NtQueryObjectDelegate));
ntQuerySystemInformationDelegate = (NtQuerySystemInformationDelegate)Marshal.GetDelegateForFunctionPointer(ntQuerySystemInformationPtr, typeof(NtQuerySystemInformationDelegate));
ntQueryInformationFileDelegate = (NtQueryInformationFileDelegate)Marshal.GetDelegateForFunctionPointer(ntQueryInformationFilePtr, typeof(NtQueryInformationFileDelegate));

以 .NET C# 方法進行呼叫 delegate
public uint NtQueryObject(IntPtr hHandle, uint dw1, byte[] buffer, uint bufferSize, ref uint needLength)
{
return ntQueryObjectDelegate.Invoke(hHandle, dw1, buffer, bufferSize, ref needLength);
}

public uint NtQuerySystemInformation(uint dw1, IntPtr systemHandleInformation, uint bufferSize, ref uint needLength)
{
return ntQuerySystemInformationDelegate.Invoke(dw1, systemHandleInformation, bufferSize, ref needLength);
}

public uint NtQueryInformationFile(IntPtr hHandle, uint[] iob, IntPtr buffer, uint bufferSize, uint dw2)
{
return ntQueryInformationFileDelegate.Invoke(hHandle, iob, buffer, bufferSize, dw2);
}

Unlocker .NET 如何取得鎖住檔案的程序 Handle
1. 透過 NtQuerySystemInformation 方法取得所有系統中使用的 Handle
2. 透過 NtQueryObject 方法可獲得系統的 Handle 是屬於那一類型,包括 Process、Thread、File 等
3. 透過 NtQueryObject 方法可取得任一 File Handle 被那一個程序使用中

Unlocker .NET 強制關閉 File Handle 原理
1. 首先要 Enable DEBUG privilege
2. 透過 OpenProcess Win32 API 取得鎖住檔案的程序 Handle
3. 透過 CreateRemoteThread Win32 API 呼叫 CloseHandle Win32 API

如何使用 Unlocker.NET.dll
下載並加入 Unlocker.NET.dll 參考

using Unlocker.NET;
class Program
{
static void Main(string[] args)
{
// C:\01.bmp 為被鎖住的檔案名稱
if (Unlocker.CloseFileHandle(@"C:\01.bmp"))
{
Console.WriteLine("成功關閉檔案");
}
else
{
Console.WriteLine("關閉檔案失敗");
}
Console.ReadLine();
}
}

參考網址:http://www.codeguru.com/Cpp/W-P/files/fileio/article.php/c1287/

沒有留言: