Overview - Handle Enumeration
|Post Reply||Page <12|
Joined: 10 August 2006
So... You want to know how to get these:
Seeing that this seems to be a hot topic in the Development area of this forum I decided to elaborate on how to enumerate handles of any process:
I did this in VB6, and if it can be done there, it can be done with any language that has access the Windows API.
(Note: The following structues and APIs can be found in winternl.h
Enumerate all handles with NtQuerySystemInformation:
Use 16 for SYSTEM_INFORMATION_CLASS --> which says to it "I want to query handles"
Note: Remember to allocate enough room in your buffer to hold the data. In VB6 I have seen some use a Byte Array, or you can just use VirtualAlloc. (Remember to use VirtualFree when you have your data)
Copy the buffer into SYSTEM_HANDLE (AKA - SYSTEM_HANDLE_ENTRY).
This is found 4 bytes after the buffer's pointer (the first 4 bytes are the number of handles found)
Remember: NTQSI with 16 asks it to give up SYSTEM_HANDLE_INFORMATION, which as you can see in winternl.h, the data follows the 4 bytes.
Walk the list, and manipulate/search it to your liking. It might be useful to store these in an array, depending on your purpose.
The way I did it was:
0-4 = Entries
4-14 = Handle 1
14-24 = Handle 2
24-(size of SH) = Handle x
The best way to store these is to create a loop and increase an offset variable (which starts at 4) and once the handle is stored, the offset is increased by Length of SH.
Then once you have that offset, read it from memory. Ex: CopyMemory (RtlMoveMemory)
Note: All these handles in the buffer are not just your process's handles, it is every handle in the system.
To get the handles for each process, look for the handle's PID from SYSTEM_HANDLE
4. Need more data?
In order to gain the Handle's Type and Name the handle must exist in your process. To do this, you must make a copy of the handle using NtDuplicateHandle (Or just DuplicateHandle) and create a copy of it inside your process.
Once the copy is in your process, use NtQueryObject with the OBJECT_INFORMATION_CLASS of 1 telling it to hand over its Name (In UNICODE_STRING format)
Note: NtQueryObject needs the handle's value. So basically this can convert a handle value into the Handle Name (Or Type).
If you are wondering why earlier I said the handle must exist in your process, this is why: Because NtQueryObject was only made to query a local handle's data. Just like how CloseHandle or NtClose is only for local handles.
So to get the handle name for every process:
The same idea for handle Type is used. The only difference is that OBJECT_TYPE_INFORMATION (2) is used instead of OBJECT_NAME_INFORMATION (1).
Note: Process and Thread handles do not have a name. They can be obtained from:
NtQueryInformationProcess ---> Process_Basic_Information.PID and
NtQueryInformationThread ---> Thread_Basic_Information.CliendID.TID
File path names can be converted from Device Path to Logical Drive path using GetLogicalDriveStrings, and converting them with QueryDosDevice.
Once you know which drive goes with which device, you can convert the \Device\... to X:\
IMPORTANT! If you NtQueryObject with ONI (1) on a special NamedPipe handle, your thread will hang. Infact in my testing, I wasn't even able to kill the process nor shut down my computer.
To avoid these I found a undocumented similarity. Skip the NtQueryObject - ONI call if the Handle's access value is "12019F" (0x0012019F) ---> Dec = 1180063.
EP_X0FF and I talk about this here:
He also suggested spawning another thread for the query, but I don't have that much experience with thread creation, so I luckily found this common factor.
Note: This bug is only for ONI (Name) = 1 and not OTI (Type) = 2.
This avoidance method appears to be foolproof and I have yet to experience a hung thread when avoiding these troublesome File-type NamedPipe handles.
5. Need a CloseHandleEx? (Remote Handle Closing)
As you probably know, NtClose and CloseHandle do not work on remote process handles.
Luckily NtDuplicateObject will do this for us with just one specific flag.
What is this special little flag you ask? --> DUPLICATE_CLOSE_SOURCE (= 1)
Even though NTDO is used to create a copy of the handle into some other process, using that flag will close the source of the handle. You dont even need to bother closing the local handle that is created, because if you just pass it a null for the destination process handle, it cant go anywhere.
In other words, if no target process is specified and the DCS flag is used, the handle is closed remotely without even making another copy.
Note: The documented API that calls NtDuplicateObject is called DuplicateHandle, which will basically explain what NtDuplicateObject does too.
I am sure there are other methods to perform this remote handle close, but this technique seems the easiest to me.
Another other way could include using CRT (CreateRemoteThread) and telling it to execute NtClose or CloseHandle, which would be similar to remote dll unloading with CRT telling the remote process to execute FreeLibrary.
Feel free to add any comments, questions, improvements, examples, or clarifications if you want.
Mods: You might want to pin this if you feel it could help others.
Edited by Matts_User_Name - 01 May 2008 at 10:07am
|Post Reply||Page <12|
|Forum Jump||Forum Permissions
You cannot reply to topics in this forum
You cannot delete your posts in this forum
You cannot edit your posts in this forum
You cannot create polls in this forum
You cannot vote in polls in this forum