R3下用ZwQueryObject/ZwDuplicateObject关闭互斥体和解除文件占用

绕过程序多开限制
本文介绍了一种绕过程序使用Mutex实现的多开限制的方法,包括修改条件跳转和删除Mutex变量两种途径,并提供了详细的代码实现。

    不少程序在运行时会创建/打开全局Mutex,来限制用户多开。百度上搜一圈下来,他们的实现基本是这样:

int main(int argc, char* argv[])
{
	HANDLE hMtx = CreateMutex(NULL,false,"process"); //创建一个有名对象,可以在其他进程中访问 
	if(GetLastError() == ERROR_ALREADY_EXISTS)    //除了创建该对象的进程能进到else分支,其他进程都进入if分支,然后退出
	{
		ExitProcess(0);
	}
	else
	        //do something	
	return 0;
}
    饶过这类限制,我能想到2种方法:

    1).修改跳转发生时的条件,不管什么情况都进入else分支

     2).删除全局Mutex变量
先简单说下方式1)

	if(GetLastError() == ERROR_ALREADY_EXISTS)
00DC13D9  mov         esi,esp  
00DC13DB  call        dword ptr [__imp__GetLastError@0 (0DC81F0h)]  
00DC13E1  cmp         esi,esp  
00DC13E3  call        @ILT+295(__RTC_CheckEsp) (0DC112Ch)  
00DC13E8  cmp         eax,0B7h  //比较-判断发生在这,只要修改eax的值或者EFlags的值即可
00DC13ED  jne         main+7Dh (0DC141Dh) 
再看下方式2),a.主要思路是查找目标进程,b.找到后枚举进程所有打开的句柄,c.用ZwDuplicateObject复制句柄,能复制成功的基本是可用的句柄,d.先关闭上次调用ZwDuplicateObject时复制的句柄,然后已DUPLICATE_CLOSE_SOURCE的方式(复制后关闭原句柄)再次复制/关闭句柄。以此关闭限制多开的Mutex。

    罗列代码前,先看下这种方式是否具有可行性。首先不杀Mutex句柄,运行同一个进程两次的结果如下


用xuetr关闭进程中的mutex句柄,再次打开:




由上面几张图可知,杀掉全局Mutext后,可以实现进程多开。有了理论的支持,下面开始实际编码。

1.准备工作。代码进行枚举并打开进程,打开进程需要提权,使进程本身具有SE_PRIVILEGE_ENABLED权限。然后导出一堆Zw*函数用于枚举系统和进程的UnDocument API。读者可能知道进程EPROCESS结构中有进程句柄表,记录了进程打开的句柄信息,但是有了SE_PRIVILEGE_ENABLED权限和UnDocument API就能获得目标进程的句柄表了么?貌似也不是~那这不就无解了?在R3下的确很直白的方法,但是,有个很重要的事:进程句柄从4开始计数,每次往上加4,这个可以通过ARK工具查看验证。知道这个事就好办了,大不了在循环中慢慢找过去呗~虽然挨个找过去是一个办法,但是未必每个值为4N的整数就是进程内有效句柄啊~因此,需要用另一个UnDocument API----ZwDuplicateObject加以验证,如果调用这个函数成功就是一个可用的句柄,然后对这个句柄经行下一步处理。

2.摸排信息。光有进程句柄,同时知道这是一个有效的句柄作用不大。想想GUI进程一堆窗口,每个窗口一个句柄,不可能直接一棍打死吧?所以得摸清楚这个句柄的背景信息,通过调用ZwQueryObject可以获得该句柄的类型名和句柄名。通过字符串比较(wcsstr)找到Mutext对应的句柄。

3.暗杀。以DUPLICATE_CLOSE_SOURCE方式调用DuplicateHandle,意思很直白了,复制的时候把源句柄关闭。谁是源句柄?当然是创建Mutext的进程中的Mutext句柄。读者可以在调试时单步运行到DuplicateHandle,然后观察xuetr中句柄占用情况:调用前,创建这个Mutext的进程对这个句柄的引用数>0,调用成功后引用数=0,因此在创建进程中再也找不到这个句柄的信息了。最后在代码中调用CloseHandle,关闭复制到本进程中的Mutext句柄。当系统发现这个句柄的引用数==0,于是会删除对应的内核对象。当下次运行同一个进程并创建互斥体时,发现系统中并没有这个互斥体,于是顺利的通过if语句往下执行。

#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <winternl.h>

#define STATUS_SUCCESS 0x00UL
#define STATUS_INFO_LENGTH_MISMATCH 0xC0000004

#define SystemHandleInformation 16
#define SE_DEBUG_PRIVILEGE 0x14

typedef enum _OBJECT_INFORMATION_CLASSEX {
    ObjBasicInformation = 0,
	ObjNameInformation,
    ObjTypeInformation,
} OBJECT_INFORMATION_CLASSEX;

typedef enum _PROCESSINFOCLASSEX
{
	ProcessHandleInformation=20,
}PROCESSINFOCLASSEX;

typedef struct _SYSTEM_HANDLE
{
	ULONG ProcessId;
	BYTE ObjectTypeNumber;
	BYTE Flags;
	USHORT Handle;
	PVOID Object;
	ACCESS_MASK GrantAccess;
}SYSTEM_HANDLE;

typedef struct _SYSTEM_HANDLE_INFORMATION
{
	DWORD HandleCount;
	SYSTEM_HANDLE Handles[1];
}SYSTEM_HANDLE_INFORMATION;

typedef struct _OBJECT_NAME_INFORMATION
{
	UNICODE_STRING ObjectName;
}OBJECT_NAME_INFORMATION;

typedef NTSTATUS (WINAPI *ZwQueryInformationProcessProc)(HANDLE,PROCESSINFOCLASSEX,LPVOID,DWORD,PDWORD);
ZwQueryInformationProcessProc ZwQueryInformationProcess;

typedef NTSTATUS (WINAPI *ZwQuerySystemInformationProc)(DWORD,PVOID,DWORD,DWORD*);
ZwQuerySystemInformationProc ZwQuerySystemInformation;

typedef NTSTATUS (WINAPI *ZwQueryObjectProc)(HANDLE,OBJECT_INFORMATION_CLASSEX,PVOID,ULONG,PULONG);
ZwQueryObjectProc ZwQueryObject;

typedef NTSTATUS (WINAPI *RtlAdjustPrivilegeProc)(DWORD,BOOL,BOOL,PDWORD);
RtlAdjustPrivilegeProc RtlAdjustPrivilege;

typedef DWORD (WINAPI *ZwSuspendProcessProc)(HANDLE);
ZwSuspendProcessProc ZwSuspendProcess;

typedef DWORD (WINAPI *ZwResumeProcessProc)(HANDLE);
ZwResumeProcessProc ZwResumeProcess;
//进程提权
BOOL ElevatePrivileges()
{
	HANDLE hToken;
	TOKEN_PRIVILEGES tkp;
	tkp.PrivilegeCount = 1;
	if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken))
		return FALSE;
	LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&tkp.Privileges[0].Luid);
	tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
	if(!AdjustTokenPrivileges(hToken,FALSE,&tkp,sizeof(TOKEN_PRIVILEGES),NULL,NULL))
	{
		return FALSE;
	}

	return TRUE;
}
//获得未导出api的地址
BOOL GetUnDocumentAPI()
{
	ZwSuspendProcess = (ZwSuspendProcessProc)
							GetProcAddress(GetModuleHandle(L"ntdll.dll"),"ZwSuspendProcess");

	ZwQuerySystemInformation = (ZwQuerySystemInformationProc)
							GetProcAddress(GetModuleHandle(L"ntdll.dll"),"ZwQuerySystemInformation");

	ZwQueryObject = (ZwQueryObjectProc)
							GetProcAddress(GetModuleHandle(L"ntdll.dll"),"ZwQueryObject");

	ZwResumeProcess = (ZwResumeProcessProc)
		GetProcAddress(GetModuleHandle(L"ntdll.dll"),"ZwResumeProcess");

	ZwQueryInformationProcess = (ZwQueryInformationProcessProc)
							GetProcAddress(GetModuleHandle(L"ntdll.dll"),"ZwQueryInformationProcess");

	if((ZwSuspendProcess==NULL)||\
		(ZwQuerySystemInformation==NULL)||\
		(ZwQueryObject==NULL)||\
		(ZwResumeProcess==NULL)||\
		(ZwQueryInformationProcess==NULL))
		return FALSE;
	
	return TRUE;
}

int main(int argc, char* argv[])
{
	HANDLE duplicateHnd;
	HANDLE sourceHnd;
	DWORD procHndNum;
	ULONG pid;
	FILE* fp = fopen("./pid.txt","r+");
	fscanf(fp,"%d",&pid);
	fclose(fp);
	SYSTEM_HANDLE* currnetHnd;
	DWORD buffLen = 0x1000;
	NTSTATUS status;
	SYSTEM_HANDLE_INFORMATION* buff = (SYSTEM_HANDLE_INFORMATION*)malloc(buffLen);
	
	if((ElevatePrivileges()==FALSE)||(GetUnDocumentAPI()==FALSE))
		ExitProcess(0);

	do
	{
                //初次运行时,不知道缓存区要多大,就试探性的调用该函数。函数返回<span style="font-family: Arial, Helvetica, sans-serif;">STATUS_INFO_LENGTH_MISMATCH</span>
<span style="font-family:Arial, Helvetica, sans-serif;">                                //意为缓存区不够大,然后在下次循环前扩大缓存空间再次调用函数
</span>		status = ZwQuerySystemInformation(SystemHandleInformation,buff,buffLen,&buffLen);
		if(status == STATUS_INFO_LENGTH_MISMATCH)
		{
			free(buff);
			buff = (SYSTEM_HANDLE_INFORMATION*)malloc(buffLen);
		}
		else
			break;

	}while(1);

	OBJECT_NAME_INFORMATION* objNameInfo = (OBJECT_NAME_INFORMATION*)malloc(0x1000);
	OBJECT_NAME_INFORMATION* objTypeInfo = (OBJECT_NAME_INFORMATION*)malloc(0x1000);
	
	for(int idx=0;idx<buff->HandleCount;idx++)
	{
		currnetHnd = &(buff->Handles[idx]);

		if(currnetHnd->ProcessId == pid)
		{
			sourceHnd = OpenProcess(PROCESS_ALL_ACCESS|PROCESS_DUP_HANDLE|PROCESS_SUSPEND_RESUME,FALSE,pid);
			(ZwSuspendProcess)(sourceHnd);
			(ZwQueryInformationProcess)(sourceHnd,ProcessHandleInformation,&procHndNum,sizeof(DWORD),NULL);
			//进程有效句柄从4开始,每次以4递增
			unsigned short hndNum=4;
			for(int idx=0;idx<procHndNum;hndNum+=4)
			{
				//判断是否为有效句柄,返回TRUE,就是有效句柄
				if(!DuplicateHandle(sourceHnd,
									(HANDLE)hndNum,
									GetCurrentProcess(),
									&duplicateHnd,0,FALSE,DUPLICATE_SAME_ACCESS))
				{
					continue;
				}
				else
				{
					memset(objNameInfo,0,0x1000);
					memset(objTypeInfo,0,0x1000);
                                        //查询句柄类型名和句柄名
					ZwQueryObject((HANDLE)duplicateHnd,ObjNameInformation,objNameInfo,0x1000,NULL);
					ZwQueryObject((HANDLE)duplicateHnd,ObjTypeInformation,objTypeInfo,0x1000,NULL);

					//找到互斥体 比较名字
					if(wcsicmp(objTypeInfo->ObjectName.Buffer,L"mutant") == 0)
					{
						if(wcsstr(objNameInfo->ObjectName.Buffer,L"process") != 0)
						{
							CloseHandle(duplicateHnd);
							/*
							DUPLICATE_CLOSE_SOURCE
							Closes the source handle. This occurs regardless of any error status returned.
							DUPLICATE_SAME_ACCESS
							Ignores the dwDesiredAccess parameter. The duplicate handle has the same access as the source handle.

							也就是说当我们选择DUPLICATE_CLOSE_SOURCE时,源句柄就会自动关闭了
							*/
							if(DuplicateHandle(sourceHnd,
									(HANDLE)hndNum,
									GetCurrentProcess(),
									&duplicateHnd,0,FALSE,DUPLICATE_CLOSE_SOURCE))
							{
								CloseHandle(duplicateHnd);
								ExitProcess(0);
							}
						}
					}

					wprintf(L"idx:%03x\nType:%ls\nName:%ls\n",
						(idx+1)*4,
						objTypeInfo->ObjectName.Buffer,
						objNameInfo->ObjectName.Buffer);

					wprintf(L"\n\n");
					CloseHandle(duplicateHnd);
					idx++;
				}
			}
			

			
		}
	}

	(ZwResumeProcess)(sourceHnd);
	return 0;
}


这段代码做个变体,可以查找进程打开的文件句柄,然后关闭同时删除文件,unlocker的作者大熊猫候佩就是在R3下这么实现结束进程对文件的占用。具体可以搜索他的博客,我就简单罗列一下按他的思路实现的代码

#include <stdio.h>
#include <string.h>
#include <windows.h>
//#include <winternl.h>

#define STATUS_SUCCESS 0x00UL
#define STATUS_INFO_LENGTH_MISMATCH 0xC0000004
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)

#define SystemHandleInformation 16
#define SE_DEBUG_PRIVILEGE 0x14

typedef struct _IO_STATUS_BLOCK
{
	union
	{
		NTSTATUS Status;
		PVOID    Pointer;
	};
	ULONG_PTR Information;
}IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;

typedef enum _FILE_INFORMATION_CLASS
{
	FileDirectoryInformation=1,
	FileFullDirectoryInformation,   // 2
	FileBothDirectoryInformation,   // 3
	FileBasicInformation,           // 4  wdm
	FileStandardInformation,        // 5  wdm
	FileInternalInformation,        // 6
	FileEaInformation,              // 7
	FileAccessInformation,          // 8
	FileNameInformation,            // 9
	FileRenameInformation,          // 10
	FileLinkInformation,            // 11
	FileNamesInformation,           // 12
	FileDispositionInformation,     // 13
	FilePositionInformation,        // 14 wdm
	FileFullEaInformation,          // 15
	FileModeInformation,            // 16
	FileAlignmentInformation,       // 17
	FileAllInformation,             // 18
	FileAllocationInformation,      // 19
	FileEndOfFileInformation,       // 20 wdm
	FileAlternateNameInformation,   // 21
	FileStreamInformation,          // 22
	FilePipeInformation,            // 23
	FilePipeLocalInformation,       // 24
	FilePipeRemoteInformation,      // 25
	FileMailslotQueryInformation,   // 26
	FileMailslotSetInformation,     // 27
	FileCompressionInformation,     // 28
	FileObjectIdInformation,        // 29
	FileCompletionInformation,      // 30
	FileMoveClusterInformation,     // 31
	FileQuotaInformation,           // 32
	FileReparsePointInformation,    // 33
	FileNetworkOpenInformation,     // 34
	FileAttributeTagInformation,    // 35
	FileTrackingInformation,        // 36
	FileIdBothDirectoryInformation, // 37
	FileIdFullDirectoryInformation, // 38
	FileValidDataLengthInformation, // 39
	FileShortNameInformation,       // 40
	FileMaximumInformation,
}FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;

typedef struct _UNICODE_STRING
{
	USHORT Length;
	USHORT MaximumLength;
	PWSTR  Buffer;
}UNICODE_STRING, *PUNICODE_STRING;

typedef struct _OBJECT_NAME_INFORMATION
{
	UNICODE_STRING Name;
}OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;

typedef enum _OBJECT_INFORMATION_CLASSEX {
    ObjBasicInformation = 0,
	ObjNameInformation,
    ObjTypeInformation,
} OBJECT_INFORMATION_CLASSEX;

typedef enum _PROCESSINFOCLASSEX
{
	ProcessHandleInformation=20,
}PROCESSINFOCLASSEX;

typedef struct _SYSTEM_HANDLE
{
	ULONG ProcessId;
	BYTE ObjectTypeNumber;
	BYTE Flags;
	USHORT Handle;
	PVOID Object;
	ACCESS_MASK GrantAccess;
}SYSTEM_HANDLE;

typedef struct _SYSTEM_HANDLE_INFORMATION
{
	DWORD HandleCount;
	SYSTEM_HANDLE Handles[1];
}SYSTEM_HANDLE_INFORMATION;

typedef NTSTATUS (NTAPI *ZwQueryInformationFileProc)(HANDLE,PIO_STATUS_BLOCK,PVOID,DWORD,FILE_INFORMATION_CLASS);
ZwQueryInformationFileProc ZwQueryInformationFile;

typedef NTSTATUS (WINAPI *ZwQueryInformationProcessProc)(HANDLE,PROCESSINFOCLASSEX,LPVOID,DWORD,PDWORD);
ZwQueryInformationProcessProc ZwQueryInformationProcess;

typedef NTSTATUS (WINAPI *ZwQuerySystemInformationProc)(DWORD,PVOID,DWORD,DWORD*);
ZwQuerySystemInformationProc ZwQuerySystemInformation;

typedef NTSTATUS (WINAPI *ZwQueryObjectProc)(HANDLE,OBJECT_INFORMATION_CLASSEX,PVOID,ULONG,PULONG);
ZwQueryObjectProc ZwQueryObject;

typedef NTSTATUS (WINAPI *RtlAdjustPrivilegeProc)(DWORD,BOOL,BOOL,PDWORD);
RtlAdjustPrivilegeProc RtlAdjustPrivilege;

typedef DWORD (WINAPI *ZwSuspendProcessProc)(HANDLE);
ZwSuspendProcessProc ZwSuspendProcess;

typedef DWORD (WINAPI *ZwResumeProcessProc)(HANDLE);
ZwResumeProcessProc ZwResumeProcess;

BOOL ElevatePrivileges()
{
	HANDLE hToken;
	TOKEN_PRIVILEGES tkp;
	tkp.PrivilegeCount = 1;
	if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken))
		return FALSE;
	LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&tkp.Privileges[0].Luid);
	tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
	if(!AdjustTokenPrivileges(hToken,FALSE,&tkp,sizeof(TOKEN_PRIVILEGES),NULL,NULL))
	{
		return FALSE;
	}

	return TRUE;
}

BOOL GetUnDocumentAPI()
{
	ZwSuspendProcess = (ZwSuspendProcessProc)
							GetProcAddress(GetModuleHandle(L"ntdll.dll"),"ZwSuspendProcess");

	ZwQueryInformationFile = (ZwQueryInformationFileProc)
							GetProcAddress(GetModuleHandle(L"ntdll.dll"),"ZwQueryInformationFile");
	
	ZwQuerySystemInformation = (ZwQuerySystemInformationProc)
							GetProcAddress(GetModuleHandle(L"ntdll.dll"),"ZwQuerySystemInformation");

	ZwQueryObject = (ZwQueryObjectProc)
							GetProcAddress(GetModuleHandle(L"ntdll.dll"),"ZwQueryObject");

	ZwResumeProcess = (ZwResumeProcessProc)
		GetProcAddress(GetModuleHandle(L"ntdll.dll"),"ZwResumeProcess");

	ZwQueryInformationProcess = (ZwQueryInformationProcessProc)
							GetProcAddress(GetModuleHandle(L"ntdll.dll"),"ZwQueryInformationProcess");

	if((ZwSuspendProcess==NULL)||\
		(ZwQuerySystemInformation==NULL)||\
		(ZwQueryObject==NULL)||\
		(ZwResumeProcess==NULL)||\
		(ZwQueryInformationProcess==NULL))
		return FALSE;
	
	return TRUE;
}

int _tmain(int argc, _TCHAR* argv[])
{
	_tsetlocale(0, _T("chs"));
	HANDLE duplicateHnd;
	HANDLE sourceHnd;
	DWORD procHndNum;
	ULONG pid;
	FILE* fp = _wfopen(L"./pid.txt",L"r+");
	fwscanf(fp,L"%d",&pid);
	fclose(fp);
	SYSTEM_HANDLE* currnetHnd;
	DWORD buffLen = 0x1000;
	NTSTATUS status;
	SYSTEM_HANDLE_INFORMATION* buff = (SYSTEM_HANDLE_INFORMATION*)malloc(buffLen);
	
	IO_STATUS_BLOCK IoStatus ={0};
	POBJECT_NAME_INFORMATION objName = NULL;
	DWORD allocSize = (DWORD)(sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH*sizeof(WCHAR));
	objName = (POBJECT_NAME_INFORMATION)malloc(allocSize);
	memset(objName,0,allocSize);

	if((ElevatePrivileges()==FALSE)||(GetUnDocumentAPI()==FALSE))
		ExitProcess(0);

	do
	{
		status = ZwQuerySystemInformation(SystemHandleInformation,buff,buffLen,&buffLen);
		if(status == STATUS_INFO_LENGTH_MISMATCH)
		{
			free(buff);
			buff = (SYSTEM_HANDLE_INFORMATION*)malloc(buffLen);
		}
		else
			break;

	}while(1);

	OBJECT_NAME_INFORMATION* objNameInfo = (OBJECT_NAME_INFORMATION*)malloc(0x1000);
	OBJECT_NAME_INFORMATION* objTypeInfo = (OBJECT_NAME_INFORMATION*)malloc(0x1000);
	
	for(int idx=0;idx<buff->HandleCount;idx++)
	{
		currnetHnd = &(buff->Handles[idx]);

		if(currnetHnd->ProcessId == pid)
		{
			sourceHnd = OpenProcess(PROCESS_ALL_ACCESS|PROCESS_DUP_HANDLE|PROCESS_SUSPEND_RESUME,FALSE,pid);
			//(ZwSuspendProcess)(sourceHnd);
			(ZwQueryInformationProcess)(sourceHnd,ProcessHandleInformation,&procHndNum,sizeof(DWORD),NULL);
			//进程有效句柄从4开始,每次以4递增
			unsigned short hndNum=4;
			for(int idx=0;idx<procHndNum;hndNum+=4)
			{
				//判断是否为有效句柄,返回TRUE,就是有效句柄
				if(!DuplicateHandle(sourceHnd,
									(HANDLE)hndNum,
									GetCurrentProcess(),
									&duplicateHnd,0,FALSE,DUPLICATE_SAME_ACCESS))
				{
					continue;
				}
				else
				{

					memset(objNameInfo,0,0x1000);
					memset(objTypeInfo,0,0x1000);

					ZwQueryObject((HANDLE)duplicateHnd,ObjNameInformation,objNameInfo,0x1000,NULL);
					ZwQueryObject((HANDLE)duplicateHnd,ObjTypeInformation,objTypeInfo,0x1000,NULL);

					//找到互斥体 比较名字
					if(wcsicmp(objTypeInfo->Name.Buffer,L"file") == 0)
					{
						NTSTATUS status =-1;
						memset(objName,0,allocSize);
						status = ZwQueryInformationFile((HANDLE)duplicateHnd,&IoStatus,objName,allocSize,FileNameInformation);
						if(NT_SUCCESS(status))
						{
							if(wcsstr((wchar_t*)&(objName->Name.Buffer), L"unlock")!=0)
							{
								if(DuplicateHandle(sourceHnd,
										(HANDLE)hndNum,
										GetCurrentProcess(),
										&duplicateHnd,0,FALSE,DUPLICATE_CLOSE_SOURCE))
								{
									CloseHandle(duplicateHnd);
									//DeleteFile();
									ExitProcess(0);
								}
							}
							wprintf(L"%ls\n",&(objName->Name.Buffer));
						}
					}

					idx++;
				}
			}
		}
	}
	//(ZwResumeProcess)(sourceHnd);
	return 0;
}

参考的文档打包连接

前言 上一次发布过的程序:【首发】检测文件占用,具有学习商业价值(By超级用户),可以使用,仿电脑管家 正文 对于怎么枚举文件句柄 ,上一帖子对此有介绍,核心代码大概如下:如果 (ZwQueryObject (handle, #ObjectTypeInformation, unicode, 0, size) ≠ #STATUS_INVALID_HANDLE )&#39; 只要不是无效的,为什么,详细看下面的注释 &#39; 参数 &#39; Handle &#39; 对象的一个句柄来获取信息。 &#39; ObjectInformationClass &#39; 指定一个OBJECT_INFORMATION_CLASS返回值的类型决定了信息在ObjectInformation缓冲区。 &#39; ObjectInformation &#39; 一个指向caller-allocated缓冲接收请求的信息。 &#39; ObjectInformationLength &#39; 指定的大小,以字节为单位,ObjectInformation缓冲区。 &#39; ReturnLength &#39; 一个指向变量的指针,接收的大小,以字节为单位,请求的关键信息。如果NtQueryObject STATUS_SUCCESS返回,返回的变量包含的数据量。如果NtQueryObject返回STATUS_BUFFER_OVERFLOW或STATUS_BUFFER_TOO_SMALL,您可以使用变量的值来确定所需的缓冲区大小。 &#39; 返回值 &#39; NtQueryObject返回STATUS_SUCCESS或适当的错误状态。可能的错误状态码包括以下: &#39; 返回代码 描述 &#39; STATUS_ACCESS_DENIED &#39; 有足够的权限来执行该cha询。 &#39; STATUS_INVALID_HANDLE &#39; 提供对象句柄无效。 &#39; STATUS_INFO_LENGTH_MISMATCH &#39; 信息长度不足以容纳数据。 unicode = 取空白字节集 (size) ZwQueryObject (handle, #ObjectTypeInformation, unicode, size, 0)&#39; 读取信息的unicode文本 RtlUnicodeStringToAnsiString (ansi, unicode, 真)&#39; 编码转换 &#39; RtlUnicodeStringToAnsiString例程将给定Unicode字符串转换成一个ANSI字符串。 str = 指针到文本 (ansi.Buffer) &#39; RtlFreeAnsiString常规版本存储由RtlUnicodeStringToAnsiString分配。 &#39; 参数 &#39; AnsiString &#39; 指针ANSI字符串缓冲区由RtlUnicodeStringToAnsiString以前分配的。 RtlFreeAnsiString (ansi) str = “无法获取”&#39; 无效的怎么获取…… 返回 (str) 这一次呢更新了一个RemoteCloseHandle ,大概的原理是什么呢? 同时也采用了一些比较骚的方法,这种方法的限制较多,但是对于32位进程就很有效果。 NtClose在MSDN的大概介绍 1. NtClose is a generic routine that operates on any type of object. 2. Closing an open object handle causes that handle to become invalid. The system also decrements the handle count for the object and checks whether the object can be deleted. The system does not actually delete the object until all of the object&#39;s handles are closed and no referenced pointers remain. 3. A driver must close every handle that it opens as soon as the handle is no longer required. Kernel handles, which are those that are opened by a system thread or by specifying the OBJ_KERNEL_HANDLE flag, can be closed only when the previous processor mo
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值