Unlocker的编程”探险”及工作原理
关键字:文件对象,NT用户态,内核态 Unlocker是偶写的一个文件解锁小工具,原来GUI用的是C# 2005编写,功能逻辑用的 是纯汇编加少量的C语言编写。现在为了不依赖于.Net Framework 平台,CUI用VB6.0 重写,而功能逻辑全部用C语言改写。 VB6对于GUI的快速开发以及”便携绿色化”还是比较优秀的一款工具,虽然他对漂亮 的XP皮肤支持有限(比如一些控件无法XP Skin化),甚至有些人会认为她是一款早已 过时的IDE,但目前来说,她还是可以很好的满足偶的需求,既然可以满足那么足以。 [PART0 : 关于文件解锁方法的浅谈] NT下的文件解锁,我知道的主要有3种方法,我分别写了3个函数对应: extern WINAPI int CloseHandleByDH(DWORD pid,HANDLE hfile); extern WINAPI int CloseHandleByRT(DWORD pid,HANDLE hfile); extern WINAPI int CloseHandleByCore(DWORD pid,HANDLE handle); 这些都是NT下编程中较基本的知识点,相信大多数Coder们看到这心中已经明白了。 下面我逐一作简单说明: 1. CloseHandleByDH 使用DuplicateHandle的DUPLICATE_CLOSE_SOURCE 选项,该选项的作用是不但将源进 程中的对象句柄“拷贝”到目标进程(其实是将句柄指向Object的连接添加到目标进程 的对象表中。),而且同时关闭源进程中的对象句柄。 这种方法效果还是很好的,可以unlock大多数文件句柄,只要取得SE_DEBUG特权, 甚至连System进程中一些句柄都可以关闭。很多文件解锁工具用的都是这种方法。 2. CloseHandleByRT 这种方法的原理是向源进程中插入RemoteThread,同时将远线程的入口设置为 CloseHandle,并将源进程中要关闭的句柄传递给它。以前在汇编中我是写了一个 所谓的naked函数,还要在源进程中分配地址空间,然后将naked函数copy过去, 最后在该函数中调用CloseHandle。其实没这么复杂,对于只有一个参数的 ”知名” API, 完全可以用一个CreateRemoteThread搞定。但这种RemoteThread方法效果不是很好, 如果源进程不允许在用户态插入远线程(比如System,smss等),则这种方法就会失效。 RemoteThread效果大大不如第一种方法。 3. CloseHandleByCore 前两种方法对于有些内核对象来说没有效果-------原汤化原食,这时还得从内核 里想办法。所以有了CloseHandleByCore 方法。对于某些内核对象可以简单的在 Ring0中用ZwClose 关闭,然而另一些内核对象称之为PERMANENT对象,这种对象 要先使用ZwMakeTemporaryObject将其“转性”然后再将其关闭(但据偶观察还未见 到File类型的永久对象。)。然而在内核中做动作仍需小心,否则”必蓝”。这个问题 在后面还要提及。 以上列出了关闭句柄的几种方法,还没说如何获得活动文件对象的句柄表。偶用的 还是比较“正统”的NtQuerySystemInformation 方法,该函数返回系统中全部活动对 象的信息表,其中每一项结构定义如下: typedef struct _SYSTEM_HANDLE_INFORMATION { ULONG ProcessId; UCHAR ObjectTypeNumber; UCHAR Flags; USHORT Handle; PVOID Object; ACCESS_MASK GrantedAccess; }SYSTEM_HANDLE_INFORMATION,*PSYSTEM_HANDLE_INFORMATION; 为了便于VB与C的信息传递,偶定义了相关的OpenFile结构: typedef struct _OPENED_FILE_INFO { char ProcessName[MAX_PATH]; //进程名全称 char FileName[MAX_PATH]; //文件全名称 HANDLE hFile; //文件句柄 DWORD PID; //进程ID DWORD Flags; //句柄标志 DWORD GrantedAccess; //句柄访问授权 PVOID Object; //对象体指针 int CurrentIndex; //当前句柄项在句柄表中的索引 }OPENED_FILE_INFO,*POPENED_FILE_INFO; VB6中与其定义的结构是: Type OPENED_FILE_INFO ProcessName As String * MAX_PATH FileName As String * MAX_PATH hfile As Long pid As Long Flags As Long GrantedAccess As Long Object As Long CurrentIndex As Long End Type [PART1 : 一个内核态中的严重漏洞!] 在用户模式(UserMode)中,使用不到Object对象指针,但在内核中往往需要传递Object 去完成某些操作。这本来也无可厚非,但有一个严重的漏洞存在: 在内核中使用该Object时不能确保它是否还处在有效状态! 前面用NtQuerySystemInformation 取得系统句柄表,只是系统在某个时间段里的“快照”, 谁也没有保证这些句柄和对象在后面仍然有效!如果我们在Ring3级中引用一个失效 的句柄,那顶多也就返回无效句柄之类的错误。但在Ring0级则情况大有不同,在内 核态(KernelMode)中引用任何无效的内存都有可能引发“严重问题”。 |
|