枚舉進程句柄


刪除系統中的文件會提示 有進程已經打開了這個文件會導致不能刪除該文件

在網上找到了在ring3下實現文件碎甲的一篇介紹:在ring3上實現文件碎甲功能

其中首先需要實現的就是需要枚舉出系統中每個進程打開的文件句柄

枚舉進程 枚舉句柄 這些功能都需要用到從Ntdll.dll中導出系統內核函數

比如函數 ZwQuerySystemInformation ZwQueryInformationProcess等

其中有些函數是M$未公開函數 但是大多都可以從網上查到文檔

首先從NtDll.dll中導出函數ZwQuerySystemInformation和函數RtlAdjustPrivilege

ZwQuerySystemInformation原型如下:

typedef NTSTATUS (__stdcall *ZwQuerySystemInformation1)( IN ULONG SysInfoClass, IN OUT PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG RetLen );

RtlAdjustPrivilege函數原型如下:

typedef NTSTATUS (__stdcall *RtlAdjustPrivilege1) (DWORD,BOOL,DWORD,PBOOLEAN);

導出函數:

ZwQueryObject1 ZwQueryObject; ZwQueryObject = (ZwQueryObject1) GetProcAddress(hNtDll,"ZwQueryObject");

RtlAdjustPrivilege函數也是類似

RtlAdjustPrivilege函數用於提高當前進程的權限

RtlAdjustPrivilege(20, TRUE, FALSE, NULL);

20表示賦予當前進程Debug權限 在打開其他進程和復制句柄時會用到

ZwQuerySystemInformation可以用於獲得很多系統信息 第一個參數用於標示需要獲得何種信息

這里使用5作為第一個參數標示獲取當前系統中所有進程的信息

獲得的信息是第二個參數 是一塊內存塊 需要將其轉換為結構體SYSTEM_PROCESS

typedef struct _SYSTEM_PROCESSES { ULONG NextEntryDelta; ULONG ThreadCount; ULONG Reserved1[6]; LARGE_INTEGER CreateTime; LARGE_INTEGER UserTime; LARGE_INTEGER KernelTime; UNICODE_STRING ProcessName; KPRIORITY BasePriority; ULONG ProcessId; ULONG InheritedFromProcessId; ULONG HandleCount; ULONG Reserved2[2]; VM_COUNTERS VmCounters; IO_COUNTERS IoCounters; SYSTEM_THREADS Threads[1]; } SYSTEM_PROCESSES, * PSYSTEM_PROCESSES;

如果給定的內存塊不足以存下所有進程信息則函數返回0xC0000004L

被獲取的進程信息以鏈表的形式存放在給出的內存塊中

並且每個進程由一個SYSTEM_PROCESS結構體表示

在SYSTEM_PROCESS中 NextEntryDelta表示從第一個進程信息結構到下一個結構的偏移

若其為0則表示為最后一個進程

由此我們得到了系統中所有進程的信息

現在就可以遍歷每個進程中的句柄了

由於在遍歷時需要打開進程句柄 所以需要跳過當前進程本身

由於已經得到了進程id所以可以使用ring3下的函數OpenProcess來打開進程句柄

HANDLE hProcess = OpenProcess(PROCESS_SUSPEND_RESUME | PROCESS_QUERY_INFORMATION | PROCESS_DUP_HANDLE, FALSE, Pid);

在打開的時候標示了需要用到的一些權限 如復制句柄等

在打開進程后 需要用函數ZwSuspendProcess將其暫時掛起

但是對於系統進程System(PID:4)不能將其掛起

然后通過函數ZwQueryInformationProcess獲得該進程所擁有的句柄信息

ZwQueryInformationProcess函數原型如下:

typedef NTSTATUS (__stdcall *ZwQueryInformationProcess1)( HANDLE, PROCESSINFOCLASS, LPVOID, DWORD, PDWORD);

其中PROCESSINFOCLASS是一個枚舉類型

這里需要用到的值是ProcessHandleCount(20)用於獲取進程所打開的句柄數

ZwQueryInformationProcess(hProcess, ProcessHandleCount, &hc, sizeof(hc), NULL)

hc就是該進程打開的句柄數

然后就可以通過DuplicateHandle來復制出句柄了

DuplicateHandle(hProcess, (HANDLE)h, GetCurrentProcess(), &ho, 0, FALSE, DUPLICATE_SAME_ACCESS)

這里h就是需要復制的句柄的值 由於並沒有對系統中所有的句柄進行遍歷

所以這里並不知道每個句柄的值

但是我們知道進程中所有句柄的值都是從4開始 然后每4遞增的

就是說每個進程中的句柄值必定為4 8 12 16....等等

但是不一定每個4的倍數都是一個有效的句柄值

如果你把一個無效的句柄值傳入Duplicatehandle 該函數會返回錯誤

這樣就相當於系統幫助我們判斷了句柄是否存在

在遍歷時如果DuplicateHandle成功則表明復制了一個有效句柄

直到復制出hc個有效句柄時 該進程就遍歷完成了

由此我們就遍歷出了 系統中每個進程所打開的句柄

Windows系統中句柄有很多種類型 XP系統下有如下:


1 Type 2 Directory 3 SymbolicLink 4 Token 5 Process 6 Thread 7 Job 8 DebugObject 9 Event 10 EventPair 11 Mutant 12 Callback 13 Semaphore 14 Timer 15 Profile 16 KeyedEvent 17 WindowStation 18 Desktop 19 Section 20 Key 21 Port 22 WaitablePort 23 Adapter 24 Controller 25 Device 26 Driver 27 IoCompletion 28 File 29 WmiGuid 30 FilterConnectionPort 31 FilterCommunicationPort 

對於復制出來的句柄 我們可以通過函數ZwQueryObject來獲取其類型信息

以及名字

但是由於使用ZwQueryObject時有可能引起系統死鎖

所以需要將該操作放入一個單獨的線程中處理 並設置超時

(__stdcall *ZwQueryObject1)( IN HANDLE ObjectHandle, IN OBJECT_INFORMATION_CLASS ObjectInformationClass, OUT PVOID ObjectInformation, IN ULONG Length, OUT PULONG ResultLength );

如果其中ObjectInformationClass參數為ObjectTypeInformation(2)則表示獲取類型信息
存於結構體

typedef struct _OBJECT_TYPE_INFORMATION{ UNICODE_STRING TypeName; ULONG TotalNumberOfHandles; ULONG TotalNumberOfObjects; WCHAR Unused1[8]; ULONG HighWaterNumberOfHandles; ULONG HighWaterNumberOfObjects; WCHAR Unused2[8]; ACCESS_MASK InvalidAttributes; GENERIC_MAPPING GenericMapping; ACCESS_MASK ValidAttributes; BOOLEAN SecurityRequired; BOOLEAN MaintainHandleCount; USHORT MaintainTypeList; POOL_TYPE PoolType; ULONG DefaultPagedPoolCharge; ULONG DefaultNonPagedPoolCharge; BYTE Unknown2[16]; } OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;

如果為ObjectNameInformation(1)則獲取名字信息 存於結構體

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

由此我們就可以獲得系統中所有進程打開的句柄了 也就可以從中得到時哪些進程打開了某個文件

對於掛起的進程一定要使用ZwResumeProcess將其恢復


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM