Proper way to get the main thread ID in the non Ex process creation callback?

Hello everyone

I want to get the thread ID inside my PCREATE_PROCESS_NOTIFY_ROUTINE callback, since unlike the EX version there is no PPS_CREATE_NOTIFY_INFO in the third argument, what is the proper way of doing this?

I don’t want to parse EPROCESS structure of the corresponding PID since its undocumented, i want a stable way of getting the thread ID that works in all windows versions.
I thought of using PsGetCurrentThreadId, but does PsGetCurrentThreadId always return the thread ID of the created process?

I also tried to use ZwQuerySystemInformation to find the corresponding PID then find its TID that way, but it seems like when i use this inside the create process callback, the process is still not fully created and i cannot find the PID using ZwQuerySystemInformation.

You might want and try to use PsSetCreateThreadNotifyRoutine for this.

@ThatsBerkan said:
You might want and try to use PsSetCreateThreadNotifyRoutine for this.

Thank you for the suggestion, but i want to use only the create process callback for efficiency, i want to block certain processes from getting created and using thread creation callback is not really good. there has to be a way that i can get the thread ID considering i already have the PID and the EPROCESS, but i don’t want to use unstable methods to do so.

The “older” callbacks would not let you prevent process creation, IIRC, so
how does main thread help?

@Dejan_Maksimovic said:
The “older” callbacks would not let you prevent process creation, IIRC, so
how does main thread help?

Yes you can, i have already implemented it using ZwTerminateProcess, but what is the most efficient and documented way of getting the thread ID?

Also i did manage to get the thread ID using ZwQuerySystemInformation, turns out there was a bug in the structs that i defined. but the problem with using ZwQuerySystemInformation is that it needs undocumented structs, and i really want to step away from using undocumented structs as much as i can, my company really discourages us from using undocumented stuff, unless we have valid reasons that its the only way of doing it, so any help is appreciated.

First of all, what is the “main thread” in this context??? Please note that the very concept of the “main thread” is a 100% Win32 thing, which is simply meaningless in the kernel, because the kernel does not make any distinction between the “main” thread and all other ones. As far as there is at least one thread in some state other than ‘terminated’ one, the process is considered alive and kicking by the kernel…

what is the most efficient and documented way of getting the thread ID?

Well, you already got the answer to this question (i.e to use thread creation callbacks), but you claim that this approach is not good for you…

Anton Bassov

You cannot do this without the PsSetCreateThreadNotifyRoutine. In older versions of Windows (I never tried it beyond Win7) depending on the type of process create there is no thread at the time of the callback. Windows allows people to create a process in a number of ways (for example emulate a fork) each of these is different. I had clients who tried what you are proposing to do, only to find they were killing the process that was specified to be inherited from.

@anton_bassov said:
First of all, what is the “main thread” in this context??? Please note that the very concept of the “main thread” is a 100% Win32 thing, which is simply meaningless in the kernel, because the kernel does not make any distinction between the “main” thread and all other ones. As far as there is at least one thread in some state other than ‘terminated’ one, the process is considered alive and kicking by the kernel…

what is the most efficient and documented way of getting the thread ID?

Well, you already got the answer to this question (i.e to use thread creation callbacks), but you claim that this approach is not good for you…

Anton Bassov

By main thread i mean the only thread that exists when the create process callback gets called.
Trying to use thread callback just so i can get the main thread ID doesn’t make any sense, i already have the process ID and its structure in the process creation callback… and yes i tested it with 10-12 windows versions and all of them do have a thread ID when process callback gets called.

And i already solved this problem using the undocumented way of using ZwQuerySystemInformation, but was wondering if theres any better way.
I need the thread ID before killing the process for logging purposes, long story. (supervisor says log thread ID, i can’t say no…)

@Don_Burn said:
You cannot do this without the PsSetCreateThreadNotifyRoutine. In older versions of Windows (I never tried it beyond Win7) depending on the type of process create there is no thread at the time of the callback. Windows allows people to create a process in a number of ways (for example emulate a fork) each of these is different. I had clients who tried what you are proposing to do, only to find they were killing the process that was specified to be inherited from.

But i already did!! I literally tested it with 10-12 windows versions. i got the thread ID using ZwQuerySystemInformation, but i was wondering if there’s any documented and easier way of doing this, because right now i need to enumerate all the processes… and yes there is a thread a the time of callback, you can easily check it yourself if you don’t believe me.

I no longer have access to the source, but at one time there were at least four major code paths through process create. Over the years I found that developers tested one of the paths, and the other three they just assumed that it was the same. It isn’t the versions of Windows as much as the subtle variations in code paths for variations on the creation of a process.

> By main thread i mean the only thread that exists when the create process callback gets called. 

Again, you seem to be thinking in terms of Win32…

In actuality, process and thread creation are, from the kernel’s perspective, two separate system calls. When a new process gets created it does not yet have any threads associated with it

and yes i tested it with 10-12 windows versions and all of them do have a thread ID when process callback gets called.

This is nothing more than just an observed behavior. Once your callback gets invoked in context of a system thread, you were, up to this point, just (un?)lucky enough to have had both syscalls executed by the time your callback got invoked. However, things are not guaranteed to work this way in 100% cases

And i already solved this problem using the undocumented way of using ZwQuerySystemInformation

This"solution" belongs to “works fine most of the time” class, i.e. is just a classical example of a “Heisenbug” that reveals itself once in a VERY while

Anton Bassov

It is possible to create a process in the kernel without any threads. I’ve done this to have a user space address space to manage memory. What is your approach going to do with a process like that?

Don,

It is possible to create a process in the kernel without any threads.I’ve done this to have a user space address space to manage memory.

Could you please expand it a bit.

IIRC, there is simply no way to create a process without a userland representation of any description. Although a newly-created process, indeed, does not have any threads in it, it still needs the address space, and, hence its image section. Depending on your objectives, it can be either the one of the process that you want to inherit the address space from, or the one of the target executable file, but it has to be mapped to its address space (along with ntdll.dll,of course - IIRC, there is simply no way to avoid this part).

Anton Bassov

Anton,

 Sorry if I wasn't clear.  This was done when NonPagedPool was limited and a client had a system that needed a lot of memory.  I created a process to have the address space.  Then I allocated memory in that address space with ZwAllocateVirtualMemory and mapped it to the kernel.  

Don Burn

@anton_bassov said:
> By main thread i mean the only thread that exists when the create process callback gets called.

Again, you seem to be thinking in terms of Win32…

In actuality, process and thread creation are, from the kernel’s perspective, two separate system calls. When a new process gets created it does not yet have any threads associated with it

That makes sense, thank you for the response.

Where???

IIRC the reason that these callbacks were changed was because of horrible race conditions with doing exactly that. that was back in the server 2003 days i think though

@anton_bassov said:
In actuality, process and thread creation are, from the kernel’s perspective, two separate system calls. When a new process gets created it does not yet have any threads associated with it
This is nothing more than just an observed behavior. Once your callback gets invoked in context of a system thread, you were, up to this point, just (un?)lucky enough to have had both syscalls executed by the time your callback got invoked. However, things are not guaranteed to work this way in 100% cases

Thank you for the answer, But how come the new create process callbacks (Ex and Ex2) do provide the creating thread ID in the PS_CREATE_NOTIFY_INFO struct? if thread ID being available is just the matter of luck, why would microsoft provide it in the PS_CREATE_NOTIFY_INFO structure?

how come the new create process callbacks (Ex and Ex2) do provide the creating thread ID

Well, simply because the creating thread is known to have been alive and kicking at the time it has called ZwCreateProcess(,) don’t you think. Therefore, there is no particular problem with identifying it. However, the same thing cannot be said about the main thread of the newly-created process - it does not yet exist at the moment…

Anton Bassov