![]() |
Overview - Handle Enumeration |
Post Reply
|
Page 12> |
| Author | |||
Matts_User_Name
Senior Member
Joined: 10 August 2006 Location: USA Status: Offline Points: 692 |
Post Options
Thanks(0)
Quote Reply
Topic: Overview - Handle EnumerationPosted: 01 May 2008 at 6:54am |
||
|
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 http://source.winehq.org/source/include/winternl.h ) 1. Enumerate 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) 2. Query 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. 3. Manipulate 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: http://forum.sysinternals.com/forum_posts.asp?TID=14435&PN=1 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. http://msdn.microsoft.com/en-us/library/ms724251(VS.85).aspx Example code:
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 |
|||
![]() |
|||
SamCPP
Newbie
Joined: 24 June 2008 Location: Australia Status: Offline Points: 9 |
Post Options
Thanks(0)
Quote Reply
Posted: 01 July 2008 at 9:31pm |
||
|
Regarding step 4, how can I find the name information for USB/COM port device file handles? OBJECT_INFORMATION_CLASS of 1 returns an NTSTATUS error of 0xc00000bb (STATUS_NOT_SUPPORTED), whereas all other file handles for hyperterminal are returned fine.
Attached is what process explorer displays (and is exactly what I am trying to get programmatically). uploads/20080701_212826_device_usbser00.zip Cheers, Sam |
|||
![]() |
|||
Matts_User_Name
Senior Member
Joined: 10 August 2006 Location: USA Status: Offline Points: 692 |
Post Options
Thanks(0)
Quote Reply
Posted: 01 July 2008 at 11:20pm |
||
|
Hey there.
Hmm that is interesting. I have noticed PE adds "artificial" names to many objects (like threads, processes, ect, by using functions like NtQueryInformation[ObjectType] Infact I had a similar question but with access tokens: http://forum.sysinternals.com/forum_posts.asp?TID=15261&PN=1 I am not really sure how to get that, although it is a handle to a File object. So basically NtQueryObject with ONI is returning "STATUS_NOT_SUPPORTED" ONLY on this specific file, and nothing else? Did you try using the alternative approach of NtQueryInformationFile with FILE_NAME_INFORMATION structure? Perhaps it is one of those handles which NtQueryObject will not work with even if it is a "File" object. Might be similar to the behavior of a NamedPipe, except instead of freezing, NTQO reports that it doesn't support the retrieval of that kind of File object's name. Obviously PE uses a driver so perhaps that is why it is able to get its name. After all, PE is able to get the name of NamedPipes which will cause a freeze for us. Most likely it uses the aid of its driver for that, so indeed this could be a similar case. I wish I could help more but my knowledge of Windows pretty much ends at usermode :P. |
|||
![]() |
|||
SamCPP
Newbie
Joined: 24 June 2008 Location: Australia Status: Offline Points: 9 |
Post Options
Thanks(0)
Quote Reply
Posted: 02 July 2008 at 12:07am |
||
Yes, all files in hyperterminal with the COM port opened work except for the COM port handle. I thought I was soooo close to having what I wanted till that moment!
I'll give that a go now.
That's what I think... PE must be doing something sneakier. Well that's a good start at least. I'll try to hack something together and post my results when it is going. I want to get the object type lookup working properly too (i.e. no hard coded tables like I have atm). Cheers, Sam Edited by SamCPP - 02 July 2008 at 12:09am |
|||
![]() |
|||
molotov
Moderator Group
Joined: 04 October 2006 Status: Offline Points: 17531 |
Post Options
Thanks(0)
Quote Reply
Posted: 02 July 2008 at 3:45am |
||
If you don't run PE as an admin, PE will still run but will not load the driver. So, if the information that's available differs between when you load PE as admin and as standard user...
Note: when PE is first launched as admin (and the driver loads), and is subsequently launched as a standard user - the driver will remain loaded, but I'm not sure if the instance of PE launched as a standard user will use it.
|
|||
|
Daily affirmation:
net helpmsg 4006 |
|||
![]() |
|||
SamCPP
Newbie
Joined: 24 June 2008 Location: Australia Status: Offline Points: 9 |
Post Options
Thanks(0)
Quote Reply
Posted: 02 July 2008 at 5:52pm |
||
Seems to give the same status error. I'll poke around with the other enums and see what I can actually get access to. |
|||
![]() |
|||
digger666
Newbie
Joined: 19 December 2008 Status: Offline Points: 4 |
Post Options
Thanks(0)
Quote Reply
Posted: 19 December 2008 at 1:55am |
||
|
The NtQueryInformationFile(FileNameInformation) returns name that begins with \. How to get drive letter? Additionally, it returns directories too , like
"\Program\Microsoft Visual Studio\vc98\Include".
How to distinguish directory?
What is SYSTEM_HANDLE_INFORMATION->Flags?
|
|||
![]() |
|||
molotov
Moderator Group
Joined: 04 October 2006 Status: Offline Points: 17531 |
Post Options
Thanks(0)
Quote Reply
Posted: 19 December 2008 at 3:10am |
||
|
Daily affirmation:
net helpmsg 4006 |
|||
![]() |
|||
YuraQ
Newbie
Joined: 19 December 2008 Status: Offline Points: 1 |
Post Options
Thanks(0)
Quote Reply
Posted: 19 December 2008 at 4:38pm |
||
|
I read many posts about "Enumerating file handle".
And all of them contain Ring3-code.
I have a question. I can (and want) get filename from handle at Ring0.
Can it simplify this algorithm?
PS
But I can't access to undocumented internal structures Edited by YuraQ - 19 December 2008 at 4:42pm |
|||
![]() |
|||
digger666
Newbie
Joined: 19 December 2008 Status: Offline Points: 4 |
Post Options
Thanks(0)
Quote Reply
Posted: 19 December 2008 at 9:04pm |
||
|
Works !
But I think I have problem with buffer resizing. If I put size big enough initially, everything is OK.
I call , as in sample codes:
dwSize = sizeof(OBJECT_NAME_INFORMATION);
pObjectInfo = (POBJECT_NAME_INFORMATION)(malloc(dwSize)); ntReturn = pNtQueryObject(hLocal, ObjectNameInformation, pObjectInfo, dwSize, &dwSize); and get INFO_LENGTH_MISMATCH with return dwSize = 0.I expect STATUS_BUFFER_OVERFLOW and required size in dwSize. What should be correct dwSize in 1st call? Should be pObjectInfo->Name (struct UNICODE_STRING) initialized?
For names , I can consider QueryDosDevice for A:..Z: , and then memcmp.
Does anyone have source code that follows code of QueryDosDevice in kernel32.dll (to avoid "missing function")? Edited by digger666 - 19 December 2008 at 10:12pm |
|||
![]() |
|||
Post Reply
|
Page 12> |
|
Tweet
|
| Forum Jump | Forum Permissions ![]() You cannot post new topics in this forum 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 |