Problems getting the main handle of a process

Hi all, could anyone help me please, I’m trying to get the main handle ID of a process via NtQuerySystemInformation ( CreateToolhelp32Snapshot + Thread32First/Thread32Next uses that function ) but without success… my code:

// get process list
if(NtQuerySystemInformation(SystemProcessInformation,BufferAllocated,GetSizeBuffer,&RetSizeBuffer) == 0)
{

lpProcInfo = (SYSTEM_PROCESS_INFORMATION*)BufferAllocated;

// looking for process name
while(lpProcInfo->NextEntryOffset )
{

// check pointer valid
if(lpProcInfo->ImageName.Buffer)
{
// string compare
if(wcsncmp((PWCHAR)lpProcInfo->ImageName.Buffer,Processname,lpProcInfo->ImageName.Length) == 0)
{
// this will be the Tthread ID, right?
return (HANDLE)lpProcInfo->Threads.ClientId.UniqueThread;
}
}

lpProcInfo = (SYSTEM_PROCESS_INFORMATION*) ((ULONG_PTR)lpProcInfo + lpProcInfo->NextEntryOffset);
}
}

but the return is zero ( the UniqueThread field from ClientId ) and I don’t why… I want to use this function because I would like to use it in user mode too. I have this trouble two days ago, please help. thanks

> Hi all, could anyone help me please, I’m trying to get the main handle ID

of a process via NtQuerySystemInformation ( CreateToolhelp32Snapshot +
Thread32First/Thread32Next uses that function ) but without success… my
code:

I think you need to be a little clearer about what you are asking. A
process has both a handle and an ID, and they are completely different.
You also seem to think there is a “main” something, implying there is a
“secondary” something. Note that a process has a handle whose value is
potentially different for every process that queries for it, so it cannot
possibly be “unique” system-wide. And " unique ID" applies only to the
current process set; once a process terminates, the system is free to
reassign that ID to a newly-created process.

There is no “main thread” as far as the system is concerned. While as a
programmer, I might speak of “the Main GUI Thread” and “secondary
threads”, that is an idea only in my head, and allows me to describe
certain desired behaviors (“You must make certain all your secondary
threads have terminated before terminating the main GUI thread”), the
kernel does not care about what the threads mean to me; they’re just
threads.

The usual question applies: what are you trying to do, and why do you
think this information is going to help you?
joe

// get process list
if(NtQuerySystemInformation(SystemProcessInformation,BufferAllocated,GetSizeBuffer,&RetSizeBuffer)
== 0)
{

lpProcInfo = (SYSTEM_PROCESS_INFORMATION*)BufferAllocated;

// looking for process name
while(lpProcInfo->NextEntryOffset )
{

// check pointer valid
if(lpProcInfo->ImageName.Buffer)
{
// string compare
if(wcsncmp((PWCHAR)lpProcInfo->ImageName.Buffer,Processname,lpProcInfo->ImageName.Length)
== 0)
{
// this will be the Tthread ID, right?
return
(HANDLE)lpProcInfo->Threads.ClientId.UniqueThread;
}
}

lpProcInfo = (SYSTEM_PROCESS_INFORMATION*)
((ULONG_PTR)lpProcInfo + lpProcInfo->NextEntryOffset);
}
}

but the return is zero ( the UniqueThread field from ClientId ) and I
don’t why… I want to use this function because I would like to use it in
user mode too. I have this trouble two days ago, please help. thanks


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

In thinking about this, I realized that you should be doing all of this in
user space. Use a CBT hook to detect process creation. As you pointed
out, you need to assign a unique ID of your own to each process session,
since there is no other way to uniquely identify the process. The handle
value is local to your process space, and as already observed, the process
ID is not unique. Hooks will not work across sessions, so a service
cannot hook process creation, and if you are using snapshots to inspect
the global system state, between any two calls the process ID cpuld have
been freed and reassigned.
joe

> Hi all, could anyone help me please, I’m trying to get the main handle
> ID
> of a process via NtQuerySystemInformation ( CreateToolhelp32Snapshot +
> Thread32First/Thread32Next uses that function ) but without success…
> my
> code:

I think you need to be a little clearer about what you are asking. A
process has both a handle and an ID, and they are completely different.
You also seem to think there is a “main” something, implying there is a
“secondary” something. Note that a process has a handle whose value is
potentially different for every process that queries for it, so it cannot
possibly be “unique” system-wide. And " unique ID" applies only to the
current process set; once a process terminates, the system is free to
reassign that ID to a newly-created process.

There is no “main thread” as far as the system is concerned. While as a
programmer, I might speak of “the Main GUI Thread” and “secondary
threads”, that is an idea only in my head, and allows me to describe
certain desired behaviors (“You must make certain all your secondary
threads have terminated before terminating the main GUI thread”), the
kernel does not care about what the threads mean to me; they’re just
threads.

The usual question applies: what are you trying to do, and why do you
think this information is going to help you?
joe
>
> // get process list
> if(NtQuerySystemInformation(SystemProcessInformation,BufferAllocated,GetSizeBuffer,&RetSizeBuffer)
> == 0)
> {
>
> lpProcInfo = (SYSTEM_PROCESS_INFORMATION*)BufferAllocated;
>
> // looking for process name
> while(lpProcInfo->NextEntryOffset )
> {
>
> // check pointer valid
> if(lpProcInfo->ImageName.Buffer)
> {
> // string compare
> if(wcsncmp((PWCHAR)lpProcInfo->ImageName.Buffer,Processname,lpProcInfo->ImageName.Length)
> == 0)
> {
> // this will be the Tthread ID, right?
> return
> (HANDLE)lpProcInfo->Threads.ClientId.UniqueThread;
> }
> }
>
> lpProcInfo = (SYSTEM_PROCESS_INFORMATION*)
> ((ULONG_PTR)lpProcInfo + lpProcInfo->NextEntryOffset);
> }
> }
>
>
> but the return is zero ( the UniqueThread field from ClientId ) and I
> don’t why… I want to use this function because I would like to use it
> in
> user mode too. I have this trouble two days ago, please help. thanks
>
> —
> NTDEV is sponsored by OSR
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

Process ids cannot be reassigned while a handle is open to the process, even if a process is terminated. The kernel reclaims the id when the reference count on the process goes to zero, i.e. after all handles and other references are gone.

CBT hooks will not get involved for non GUI processes.

  • S (Msft)

From: xxxxx@flounder.commailto:xxxxx
Sent: ?11/?21/?2012 20:34
To: Windows System Software Devs Interest Listmailto:xxxxx
Subject: Re: [ntdev] Problems getting the main handle of a process

In thinking about this, I realized that you should be doing all of this in
user space. Use a CBT hook to detect process creation. As you pointed
out, you need to assign a unique ID of your own to each process session,
since there is no other way to uniquely identify the process. The handle
value is local to your process space, and as already observed, the process
ID is not unique. Hooks will not work across sessions, so a service
cannot hook process creation, and if you are using snapshots to inspect
the global system state, between any two calls the process ID cpuld have
been freed and reassigned.
joe

>> Hi all, could anyone help me please, I’m trying to get the main handle
>> ID
>> of a process via NtQuerySystemInformation ( CreateToolhelp32Snapshot +
>> Thread32First/Thread32Next uses that function ) but without success…
>> my
>> code:
>
> I think you need to be a little clearer about what you are asking. A
> process has both a handle and an ID, and they are completely different.
> You also seem to think there is a “main” something, implying there is a
> “secondary” something. Note that a process has a handle whose value is
> potentially different for every process that queries for it, so it cannot
> possibly be “unique” system-wide. And " unique ID" applies only to the
> current process set; once a process terminates, the system is free to
> reassign that ID to a newly-created process.
>
> There is no “main thread” as far as the system is concerned. While as a
> programmer, I might speak of “the Main GUI Thread” and “secondary
> threads”, that is an idea only in my head, and allows me to describe
> certain desired behaviors (“You must make certain all your secondary
> threads have terminated before terminating the main GUI thread”), the
> kernel does not care about what the threads mean to me; they’re just
> threads.
>
> The usual question applies: what are you trying to do, and why do you
> think this information is going to help you?
> joe
>>
>> // get process list
>> if(NtQuerySystemInformation(SystemProcessInformation,BufferAllocated,GetSizeBuffer,&RetSizeBuffer)
>> == 0)
>> {
>>
>> lpProcInfo = (SYSTEM_PROCESS_INFORMATION*)BufferAllocated;
>>
>> // looking for process name
>> while(lpProcInfo->NextEntryOffset )
>> {
>>
>> // check pointer valid
>> if(lpProcInfo->ImageName.Buffer)
>> {
>> // string compare
>> if(wcsncmp((PWCHAR)lpProcInfo->ImageName.Buffer,Processname,lpProcInfo->ImageName.Length)
>> == 0)
>> {
>> // this will be the Tthread ID, right?
>> return
>> (HANDLE)lpProcInfo->Threads.ClientId.UniqueThread;
>> }
>> }
>>
>> lpProcInfo = (SYSTEM_PROCESS_INFORMATION*)
>> ((ULONG_PTR)lpProcInfo + lpProcInfo->NextEntryOffset);
>> }
>> }
>>
>>
>> but the return is zero ( the UniqueThread field from ClientId ) and I
>> don’t why… I want to use this function because I would like to use it
>> in
>> user mode too. I have this trouble two days ago, please help. thanks
>>
>> —
>> NTDEV is sponsored by OSR
>>
>> For our schedule of WDF, WDM, debugging and other seminars visit:
>> http://www.osr.com/seminars
>>
>> To unsubscribe, visit the List Server section of OSR Online at
>> http://www.osronline.com/page.cfm?name=ListServer
>>
>
>
>
> —
> NTDEV is sponsored by OSR
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer</mailto:xxxxx></mailto:xxxxx>

Yes, I’m sorry because my title says “handle” and I’m trying to get the thread ID.
Well, so summarizing my question is: how can I get the Thread ID of a process, in user mode is obtained via CreateToolhelp32Snapshot + Thread32First/Thread32Next ( the th32ThreadID member of the THREADENTRY32 structure ). so I’m trying get that information via NtquerySystemInformation because these functions use it, but without success.

> Yes, I’m sorry because my title says “handle” and I’m trying to get the

thread ID.
Well, so summarizing my question is: how can I get the Thread ID of a
process, in user mode is obtained via CreateToolhelp32Snapshot +
Thread32First/Thread32Next ( the th32ThreadID member of the THREADENTRY32
structure ). so I’m trying get that information via
NtquerySystemInformation because these functions use it, but without
success.

But all threads are effectively equal; any concept of “main” thread is a
programmer-generated concept. There is no way to tell what the initial
thread might have been, and there is no reason to even presume that it
still exists. And thread IDs are recycled fairly quickly, so if you
record something as happening on thread N, and later record something as
happening on thread N, there is no way to know that it is the same thread.

I learned years ago to put into all my trace logs a discernable “thread
start” event and a similar “thread end” event so my trace analysis tool
can “clean up” its internal tables about the existence of thread N so it
can treat the recurring value as a new thread. Key here is to understand
that the thread ID is largely useless as anthing other than a transient
artifact, and has no long-term meaning, and there is, in the OS, not one
whit of concern about which of the many threads in a process is the
original thread it was started with, and that thread may, in fact, no
longer exist, and the OS has absolutely no concern about this. So you are
trying to do something that has little or no relevance, and you have to
work with the assumptions that thread IDs and process IDs are recycled and
consequently have no meaning over the long-term state of the OS. At any
given instant there is a set of unique IDs for threads and processes, and
a second snapshot will also contain a list of unique IDs, but there is no
reliable way to tell if the processes and threads of the second snapshot
have anything whatsoever to do with the processes and threads of the first
snapshot, other than some of the IDs of the second snapshot have the same
numeric value as some of the IDs in the first snapshot. But they could
reprsent totally different processes or threads. That’s the reality.
joe


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

> Yes, I’m sorry because my title says “handle” and I’m trying to get the

thread ID.
Well, so summarizing my question is: how can I get the Thread ID of a
process, in user mode is obtained via CreateToolhelp32Snapshot +
Thread32First/Thread32Next ( the th32ThreadID member of the THREADENTRY32
structure ). so I’m trying get that information via
NtquerySystemInformation because these functions use it, but without
success.

In re-reading your question, there is a deep and fundamental failure. You
can’t get THE thead ID of a process because each process can have MANY
threads, and it is very important to understand that NONE of the threads
currently listed in the process might be the “original” thread whose
handle was returned from the CreateProcess call, although there might be a
thread with that same ID in the process, or a thread of that ID might now
exist in a completely different process. The only guarantee you have
about a thread ID is that at any instant of time it is a value distinct
from all other simultaneously-existing threads. And note that thread
termination will free up that value to be recycled ONLY when the
underlying kernel thread object is deleted. The object is not deleted
until its reference count goes to zero, which requires that (a) the thread
has terminated and (note “and”) (b) all outstanding handles to the thread
have been closed.

Ditto for process IDs.

So if you record an event for a given pair, you have absolutely
NO IDEA how that correlates with any past or future pair that
have the same numeric values. Bottom line: the OS does not and cannot
provide you with unique representations within a boot session,
and given <pid tid2 …> there is no way to dtermine what the
“main” thread really is, or even if it is in the tid set.

Note that for GUI apps, there is a high probability (but not a guarantee)
that the thread that owns the root window is the “main thread”, maybe,
just possibly, perhaps, but I have seen some instances where a secondary
thread holds all the visible graphical objects. It’s rare, because there
are certain risks to this approach, but you can’t rule it out. Besides,
why should you care which thread is the “main” thread? The concept is
quite meaningless to the OS, which is why there is no good way to discover
it.

Also, note that adding the executable path name does not change this:

<270, B2, msword.exe> may not be the same instance that was previously
described by <270, B2, msword.exe> because the previous instance of Word
may have been exited, and six hours later, when it was again launched, by
the merest coincidence the pid 270 had come around for recycling, and it
also just happened that the thread ID 0xB2 was also recycled. But in the
first instance, 0xB2 was the thread ID of the main thread, and in the
second case it was the background thread of the spellchecker (or something
like that). So what can you tell from a pair in your event log?
Answer: that at the time the event was logged, it was generated by a
given pid and from a specific thread within that process that had the
given tid number. The meaning of these numbers, however, gives you no
correlation between the two entries. There is nothing in the OS that
guarantees uniqueness in any way, such that you can make a meaningful
statement about the relationship of the two entries to each other. You
would have to track the creation and destruction of all processes and
threads to sort this mess out. Your event log would have to have entries
recording the pid and tid for all process and thread creations and
destructions to provide the context for interpretation.

Now, you might say, “Hey, I can inject a DLL and process the four events
there, for thread attach/detach and process attach/detatch.” This won’t
work. Read the fine print. I usually spend about ten minutes in my
Advanced Windows System Programming course explaining why this won’t work,
and I don’t feel like typing it all in tonight. But it won’t allow you to
do what you think it should allow you to do.

joe
> —
> NTDEV is sponsored by OSR
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>

> Process ids cannot be reassigned while a handle is open to the process,

even if a process is terminated. The kernel reclaims the id when the
reference count on the process goes to zero, i.e. after all handles and
other references are gone.

Yes, I thought I had said that, but it is true. Which is why I tell my
students that they must explicitly close all the handles they get back
from CreateProcess. Otherwise, the kernel gets glutted up with a lot of
useless thread handles, which won’t be cleaned up until the process
terminates, and a lot of useless process handles, that will not be
cleaned up until the process that calls CreateProcess terminates. In a
world of 24/7 availability, the process that creates threads or other
processes may not terminate, ever (until the system is rebooted; I reboot
my servers two or three times a year)

CBT hooks will not get involved for non GUI processes.

Since I only work with GUI processes, I had forgotten this fact, because
it always works for my processes. But you are right; it won’t catch
events in non-GUI processes.

joe

  • S (Msft)

From: xxxxx@flounder.commailto:xxxxx
> Sent: ý11/ý21/ý2012 20:34
> To: Windows System Software Devs Interest Listmailto:xxxxx
> Subject: Re: [ntdev] Problems getting the main handle of a process
>
> In thinking about this, I realized that you should be doing all of this in
> user space. Use a CBT hook to detect process creation. As you pointed
> out, you need to assign a unique ID of your own to each process session,
> since there is no other way to uniquely identify the process. The handle
> value is local to your process space, and as already observed, the process
> ID is not unique. Hooks will not work across sessions, so a service
> cannot hook process creation, and if you are using snapshots to inspect
> the global system state, between any two calls the process ID cpuld have
> been freed and reassigned.
> joe
>
>>> Hi all, could anyone help me please, I’m trying to get the main handle
>>> ID
>>> of a process via NtQuerySystemInformation ( CreateToolhelp32Snapshot +
>>> Thread32First/Thread32Next uses that function ) but without success…
>>> my
>>> code:
>>
>> I think you need to be a little clearer about what you are asking. A
>> process has both a handle and an ID, and they are completely different.
>> You also seem to think there is a “main” something, implying there is a
>> “secondary” something. Note that a process has a handle whose value is
>> potentially different for every process that queries for it, so it
>> cannot
>> possibly be “unique” system-wide. And " unique ID" applies only to the
>> current process set; once a process terminates, the system is free to
>> reassign that ID to a newly-created process.
>>
>> There is no “main thread” as far as the system is concerned. While as a
>> programmer, I might speak of “the Main GUI Thread” and “secondary
>> threads”, that is an idea only in my head, and allows me to describe
>> certain desired behaviors (“You must make certain all your secondary
>> threads have terminated before terminating the main GUI thread”), the
>> kernel does not care about what the threads mean to me; they’re just
>> threads.
>>
>> The usual question applies: what are you trying to do, and why do you
>> think this information is going to help you?
>> joe
>>>
>>> // get process list
>>> if(NtQuerySystemInformation(SystemProcessInformation,BufferAllocated,GetSizeBuffer,&RetSizeBuffer)
>>> == 0)
>>> {
>>>
>>> lpProcInfo = (SYSTEM_PROCESS_INFORMATION*)BufferAllocated;
>>>
>>> // looking for process name
>>> while(lpProcInfo->NextEntryOffset )
>>> {
>>>
>>> // check pointer valid
>>> if(lpProcInfo->ImageName.Buffer)
>>> {
>>> // string compare
>>> if(wcsncmp((PWCHAR)lpProcInfo->ImageName.Buffer,Processname,lpProcInfo->ImageName.Length)
>>> == 0)
>>> {
>>> // this will be the Tthread ID, right?
>>> return
>>> (HANDLE)lpProcInfo->Threads.ClientId.UniqueThread;
>>> }
>>> }
>>>
>>> lpProcInfo = (SYSTEM_PROCESS_INFORMATION*)
>>> ((ULONG_PTR)lpProcInfo + lpProcInfo->NextEntryOffset);
>>> }
>>> }
>>>
>>>
>>> but the return is zero ( the UniqueThread field from ClientId ) and I
>>> don’t why… I want to use this function because I would like to use it
>>> in
>>> user mode too. I have this trouble two days ago, please help. thanks
>>>
>>> —
>>> NTDEV is sponsored by OSR
>>>
>>> For our schedule of WDF, WDM, debugging and other seminars visit:
>>> http://www.osr.com/seminars
>>>
>>> To unsubscribe, visit the List Server section of OSR Online at
>>> http://www.osronline.com/page.cfm?name=ListServer
>>>
>>
>>
>>
>> —
>> NTDEV is sponsored by OSR
>>
>> For our schedule of WDF, WDM, debugging and other seminars visit:
>> http://www.osr.com/seminars
>>
>> To unsubscribe, visit the List Server section of OSR Online at
>> http://www.osronline.com/page.cfm?name=ListServer
>>
>
>
>
> —
> NTDEV is sponsored by OSR
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>
> —
> NTDEV is sponsored by OSR
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer</mailto:xxxxx></mailto:xxxxx>