HOWTO: Use I_QueryTagInformation

Process Explorer 12 includes a new feature whereby you can view service names associated with threads. To find out how this works, read this article by Alex Ionescu. You won’t be completely satisfied, though. You still don’t know how to use I_QueryTagInformation.

First step: Getting the service tag for a thread
This is simple; use NtQueryInformationThread to get the thread’s TEB address, then read the SubProcessTag from the TEB:

THREAD_BASIC_INFORMATION basicInfo;
PVOID subProcessTag;

NtQueryInformationThread(your_thread_handle, ThreadBasicInformation, &basicInfo, sizeof(basicInfo), NULL);
NtReadVirtualMemory(handle_to_the_process_containing_the_thread, (PVOID)((ULONG_PTR)basicInfo.TebBaseAddress + FIELD_OFFSET(TEB, SubProcessTag)), &subProcessTag, sizeof(PVOID), NULL);

// If you don't have the full TEB definition, here are the offsets (replace the FIELD_OFFSET invocation with these):
// x86: 0xf60
// x64: 0x1720

// You now have the service tag in subProcessTag.

Second step: Using I_QueryTagInformation
I_QueryTagInformation is located in advapi32.dll. Here’s what I’ve reverse-engineered from looking at advapi32.dll and services.exe:

typedef enum _SC_SERVICE_TAG_QUERY_TYPE
{
    ServiceNameFromTagInformation = 1,
    ServiceNamesReferencingModuleInformation,
    ServiceNameTagMappingInformation
} SC_SERVICE_TAG_QUERY_TYPE, *PSC_SERVICE_TAG_QUERY_TYPE;

typedef struct _SC_SERVICE_TAG_QUERY
{
    ULONG ProcessId;
    ULONG ServiceTag;
    ULONG Unknown;
    PVOID Buffer;
} SC_SERVICE_TAG_QUERY, *PSC_SERVICE_TAG_QUERY;

typedef ULONG (NTAPI *_I_QueryTagInformation)(
    __in PVOID Unknown,
    __in SC_SERVICE_TAG_QUERY_TYPE QueryType,
    __inout PSC_SERVICE_TAG_QUERY Query
    );

The usage is fairly obvious: you want the service name for the service tag (ServiceNameFromTagInformation), you fill in the SC_SERVICE_TAG_QUERY structure, and you call I_QueryTagInformation:

_I_QueryTagInformation I_QueryTagInformation;
SC_SERVICE_TAG_QUERY query;

I_QueryTagInformation = GetProcAddress(GetModuleHandle(L"advapi32.dll"), "I_QueryTagInformation");

if (I_QueryTagInformation)
{
    query.ProcessId = (ULONG)your_process_ID;
    query.ServiceTag = (ULONG)subProcessTag;
    query.Unknown = 0;
    query.Buffer = NULL;
    
    I_QueryTagInformation(NULL, ServiceNameFromTagInformation, &query);
    
    wprintf(L"Service name: %s\n", query.Buffer);
    LocalFree(query.Buffer);
}

4 Comments

Leave a Reply