[原创]关于Ring3解锁文件句柄的一些总结吧……
在看Windows内核原理与实现的时候,看到进程句柄表这小节,突然想起,很久本打算弄个Ring3解锁文件的东西,后来不了了之。既然想起来,那就翻出来把它做完……
书中对于进程句柄的描述:当一个进程利用名称创建或者打开一个对象(Object)时,将获得一个句柄,该句柄所指向所创建或者打开的对象。对象管理器中的对象或者执行体对象,位于系统空间中,所以在进程空间中不能通过地址来引用(对象地址值都大于0x80000000)。在windows中,句柄仅在进程范围内有效。一个进程中的句柄传递给另一个进程后,句柄值不再有效。
在windows中每一个用户进程都有一个自己的句柄表,句柄表结构为:HANDLE_TABLE,每一个句柄项结构为:HANDLE_TABLE_ENTRY(具体结构定义,请参见相关书本)。
除了用户进程的句柄表外,还有一个内核句柄表,即:系统空间中的全局句柄表。在WRK中即变量:ObpKernelHandleTable,也是System进程的句柄表(用XT看了一下,里面也有进程对象和线程对象)。
说到进程,其实进程惟一ID的分配也是通过句柄表实现的,在一个全局句柄表PspCidTable中穿件的句柄索引值,也称为CID句柄表,该表中每一个句柄项都包含了进程或线程的对象地址(以上提及进程或线程对象地址的地方应该可以用来检测隐藏进程
)。
全局句柄表和用户进程的句柄表通过对象引用计数实现对象引用的一致性。当用户进程引用某个对象时,全局句柄表对应的该对象的引用计数加一,当用户进程不使用该对象时即使解除引用,即全局引用计数减一( 在内核代码中,我们经常看到ObReferenceObjectByHandle 和 ObDereferenceObject成对出现)。当引用计数为0时,当前对象从全局句柄表和局部句柄表中移除,相关资源释放。
转入正题:Ring3解锁文件引用过程:提升进程权限,获取系统句柄表,拷贝,每一个进程中相同访问权限的文件对象(FileObject),解析文件对象名,查找需要解锁的文件,执行解锁操作。
(1)提升进程权限(古老的东西)
//打开进程权限令牌
result=::OpenProcessToken(::GetCurrentProcess(),TOKEN_QUERY|TOKEN_ADJUST_PRIVILEGES,&hTokenHandle);
if(result){
result=::LookupPrivilegeValueW(NULL,SE_DEBUG_NAME,&TokenPrivileges.Privileges[0].Luid);
if(result){
TokenPrivileges.PrivilegeCount = 1;
TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
//提升进程权限
result=::AdjustTokenPrivileges(hTokenHandle,FALSE,&TokenPrivileges,0,NULL,0);
}
}(2)获取系统句柄表
pInfo = (ULONG)HeapAlloc(hHeap,HEAP_GENERATE_EXCEPTIONS,0x1000);
//第一次调用获取所需空间大小
status = NtQuerySystemInformation(InfoClass,(PVOID)pInfo,0x1000,&ReturnBytes);
if(STATUS_INFO_LENGTH_MISMATCH == status)
{
HeapFree(hHeap,HEAP_GENERATE_EXCEPTIONS,(PVOID)pInfo);
while(status != STATUS_SUCCESS)//多次调用
{
pInfo = (ULONG)HeapAlloc(hHeap,HEAP_GENERATE_EXCEPTIONS,ReturnBytes);
//继续调用看当前提交空间是否足够(可能是系统句柄表大小会变)
status = NtQuerySystemInformation(InfoClass,(PVOID)pInfo,ReturnBytes,&ReturnBytes);
if(status == STATUS_INFO_LENGTH_MISMATCH)
{
HeapFree(hHeap,HEAP_GENERATE_EXCEPTIONS,(PVOID)pInfo);
}
}
}(3)拷贝进程句柄
if(pInfo->Handle[i].ObjectType == OB_TYPE_FILE){
hProcess = OpenProcess(PROCESS_DUP_HANDLE,NULL,pInfo->Handle[i].uIdProcess);
if(hProcess){
//拷贝文件句柄
if(DuplicateHandle(hProcess,(HANDLE)pInfo->Handle[i].Handle,GetCurrentProcess(),&hFile,0,FALSE,DUPLICATE_SAME_ACCESS)){
DupFileSuccess = TRUE;
}
CloseHandle(hProcess);
}
}(4)解析文件对象名
//查询文件名线程函数
DWORD WINAPI QueryObjectNameInfoThread(LPVOID lpParam)
{
PINTHREAD_PARAM pInParam = (PINTHREAD_PARAM)lpParam;
ULONG Length = 0;
NTSTATUS status;
OBJECT_NAME_INFORMATION ObNameInfo,*pObNameInfo = NULL;
//NtQueryObject函数也需要两次调用,第一次获取空间大小,第二次才返回结果
if( STATUS_BUFFER_OVERFLOW== NtQueryObject(pInParam->hFile,OB_TYPE_TYPE,&ObNameInfo,sizeof(OBJECT_NAME_INFORMATION),&Length)){
pObNameInfo = (POBJECT_NAME_INFORMATION)HeapAlloc(pInParam->hHeap,HEAP_GENERATE_EXCEPTIONS,Length);
pInParam->pObNameInfo = pObNameInfo;
status = NtQueryObject(pInParam->hFile,OB_TYPE_TYPE,pInParam->pObNameInfo,Length,&Length);
}
return 0;
}
//解析文件对象名(解析文件对象名所使用的句柄值是执行拷贝文件句柄函数后得到的新的句柄值,而不是系统句柄表中得到的原句柄值)
VOID CEnumSysHandleTableToolsDlg::GetFileName(HANDLE hFile,PINTHREAD_PARAM pInParam)
{
HANDLE hThread;
if(hHeap){
pInParam->hFile = hFile;
pInParam->hHeap = hHeap;
pInParam->pObNameInfo = NULL;
//使用线程是为了防止函数执行过程中卡死
hThread = CreateThread(NULL,0,QueryObjectNameInfoThread,pInParam,0,NULL);
if(WaitForSingleObject(hThread,INFINITE) == WAIT_TIMEOUT){
TerminateThread(hThread,0);
}
CloseHandle(hThread);
}
}(5)解锁文件句柄(解锁远程进程的文件句柄时,使用的句柄值是从系统句柄表中得到的,而不是执行拷贝句柄函数后得到的新句柄值)
hTargetProcess = OpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_VM_WRITE|PROCESS_VM_READ,FALSE,CurProcessId);
hKernel32Module = LoadLibrary(_T("kernel32.dll"));
if(hTargetProcess && hKernel32Module){
//和谐的CreateRemoteThread
hRemoteThread = CreateRemoteThread(hTargetProcess,0,0,(LPTHREAD_START_ROUTINE)GetProcAddress(hKernel32Module,"CloseHandle"),hRemoteHandle,0,NULL);
if(hRemoteThread == NULL){
result = FALSE;
goto Error;
}
if(WaitForSingleObject(hRemoteThread,2000) == WAIT_OBJECT_0){
result = TRUE;
}else{
result = FALSE;
}
}Ring3下解锁文件句柄比较中规中矩,使用系统接口,如果接口被HOOK了,相关文件信息被XX了,那就搞不定了。装NT驱动外壳进到系统空间,直接操作进程句柄表或者全局句柄表,效果好,不过稳定性得多加注意
……打完收工。图片:

SRC:
EnumSysHandleTableTools.rar
