0

In my C# application I have a PID and threadID of a Windows service. How can I find which service it is (note: e.g., a single instance of svchost.exe can host multiple services)? Either directly in C# or calling some other utility is fine with me.

Process Hacker can show the service name (properties of process -> tab threads -> column service).

So far I have found the process and also the thread:

var p = Process.GetProcessById(pid);
var t = p.Threads.Cast<ProcessThread>().SingleOrDefault(t => t.Id == threadId);

How to go on? Alternatives?

Jack Miller
  • 6,843
  • 3
  • 48
  • 66
  • Have a look at this [related post](http://stackoverflow.com/questions/1574019/how-to-determine-windows-diagnostics-process-from-servicecontroller). It shows how to enumerate the services and determine the process ID per service. – Axel Kemper Nov 22 '15 at 20:11
  • That does not help. There a processes (for example svchost.exe) which hosts multiple services in a single process. That is why the thread ID comes into play. The linked post does not consider threads. – Jack Miller Nov 22 '15 at 20:17
  • Does the thread name go along with any data retrieved from `Win32_Service` class or `ServiceController` class? Maybe match on name rather than ThreadID? – toddmo Nov 22 '15 at 21:03
  • You could parse and evaluate the output of "svc.exe -ld" to find which process is responsible for your service. However, this also does not mention threads. Next step could be to [walk through the thread list](https://msdn.microsoft.com/en-us/library/windows/desktop/ms686852%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396). – Axel Kemper Nov 23 '15 at 08:03

2 Answers2

1

I had a look into the source code of Process Hacker. There is no heuristic as suggested by Harry Johnston. What is does instead:

1) Lookup the base address of the thread using NtQueryInformationThread. Check Get StartAddress of win32 thread from another process to see how to call from C#.

2) The process handle is obtained via NtQueryInformationThread and NtOpenProcess.

3) NtReadVirtualMemory is used to read from thread's memory in opened process at position FIELD_OFFSET(TEB, SubProcessTag) (not sure how to translate to C#). This is the so called ServiceTag.

4) Get service name from ServiceTag using I_QueryTagInformation from advapi32.dll.

So there is no trickery nor magic, but it seems a little work to get it working for C#.

Community
  • 1
  • 1
Jack Miller
  • 6,843
  • 3
  • 48
  • 66
  • That would be the "undocumented method" I mentioned in my answer. (And if reading from an undocumented structure isn't trickery, I don't know what is!) I suspect it will only work if the thread you're inspecting was the same one that called ServiceMain; it obviously won't work for threads that are shared between multiple services. If it meets your needs then that's fine, just be aware that since it reads from an undocumented structure it might stop working in a future release of Windows. – Harry Johnston Nov 23 '15 at 18:28
0

In general, you can't. There is no 1:1 relationship between threads and services. A single thread can be running multiple services, and a single service can (and typically does) have multiple threads.

Process Hacker is likely using some sort of heuristic, for example, tracing the call stack for the thread and identifying the DLL that svchost.exe is running. Or perhaps it assumes that the thread is the same one that called ServiceMain(); there might be an undocumented method of identifying that one.

Harry Johnston
  • 35,639
  • 6
  • 68
  • 158