Discussion:
NtQueryInformationThread, Handle Duplication - Oh My!
(too old to reply)
Max Bolingbroke
2004-07-20 22:08:01 UTC
Permalink
Hi

I'm trying to get the process ID that owns a given thread handle using
Delphi. After much digging, it turns out I can use
NtQueryInformationThread in ntdll to get this information, and I've done
this successfully. The problem is now that the handle being passed in
may not have the THREAD_QUERY_INFORMATION access right. After more
digging, I found that I could use DuplicateHandle to get a handle with
more rights. Done and done, but although the handle it returns looks
valid, NtQUeryInformation rejects my request with ERROR_ACCESS_DENIED :(

Thanks in advance for any help!

Max Bolingbroke

-----

function GetProcessIDOfThread(threadHandle: dword) : dword;
var
basicInformation : THREAD_BASIC_INFORMATION; // This is defined
OK - I know because a C program i wrote to do this with a fully
privileged thread handle works fine with the an equivalent definition
returnCode : dword;
error : dword;

temporaryHandle : dword;
begin
temporaryHandle := 0;

DuplicateHandle(GetCurrentProcess(), threadHandle,
GetCurrentProcess(), @temporaryHandle, THREAD_QUERY_INFORMATION, TRUE,
0); // temporaryHandle is shown as != 0 in the MessageBox, so I *assume*
this works

returnCode := ntQueryInformationThreadEP(temporaryHandle, 0,
@basicInformation, 28, nil);
MessageBox(0, PChar(IntToStr(temporaryHandle) + ' ' +
IntToStr(basicInformation.uniqueProcess) + ' ' + IntToStr(returnCode) +
' ' + IntToStr(GetLastError())), 'Debug: Temp + PID + Return Code +
GLE', 0); // this debugging messagebox tells me that I have a valid temp
handle, a nonsense uniqueProcess, a return code of ERROR_ACCESS_DENIED
and GLE = 0 (I don't think it works for Ntdll.dll functions called
directly anyway, but I thought it better to be safe..)

CloseHandle(temporaryHandle);

result := basicInformation.uniqueProcess;
end;
Max Bolingbroke
2004-07-21 09:29:39 UTC
Permalink
Post by Max Bolingbroke
Hi
I'm trying to get the process ID that owns a given thread handle using
Delphi. After much digging, it turns out I can use
NtQueryInformationThread in ntdll to get this information, and I've done
this successfully. The problem is now that the handle being passed in
may not have the THREAD_QUERY_INFORMATION access right. After more
digging, I found that I could use DuplicateHandle to get a handle with
more rights. Done and done, but although the handle it returns looks
valid, NtQUeryInformation rejects my request with ERROR_ACCESS_DENIED :(
Thanks in advance for any help!
Max Bolingbroke
<snip delphi code>
Hi

No progress so far on this issue, but I've managed to get a sample in
C++ working fine. This just baffles me further - why dosent the Delphi
solution work?

In the sample I used a DWORD array instead of a struct - this is
simply because I'm at work now and don't have access to the structure
I put together at home. In effect, the two definitions are equivalent.
In addition, I've had to use GetProcAddress to access both OpenThread
and NtQueryInformationThread because the headers I'm working with
don't provide these functions.

Again, thanks in advance for any insight.

Max Bolingbroke

----

#include <windows.h>
#include <stdlib.h>
#include <stdio.h>

typedef HANDLE (*tOpenThread)(DWORD, BOOL, DWORD);
typedef DWORD (*tNtQueryInformationThread)(HANDLE, DWORD, PVOID,
DWORD, PDWORD);

int main(int argc, char ** argv)
{
// Check for argument validity
DWORD threadID = 0;
if (argc < 2)
{
printf("You must specify a thread ID\n");
return 1;
}
else
{
threadID = strtol(argv[1], NULL, 10);
printf("Testing operation with Thread ID = %d\n", threadID);
}

// Variable to hold return code
int returnCode = 0;

// Get kernel32 entry points
HMODULE kernel32Handle = GetModuleHandle("kernel32.dll");
tOpenThread openThreadEP =
(tOpenThread)GetProcAddress(kernel32Handle, "OpenThread");

// Get ntdll entry points
HMODULE ntDLLHandle = LoadLibrary("ntdll.dll");
tNtQueryInformationThread ntQueryInformationThreadEP =
(tNtQueryInformationThread)GetProcAddress(ntDLLHandle,
"NtQueryInformationThread");

// Open thread with wrong access rights
HANDLE handle = openThreadEP(THREAD_SUSPEND_RESUME, FALSE,
threadID);

if (handle != 0)
{
// Duplicate handle to get correct access rights
HANDLE temporaryHandle = 0;
DWORD duplicateHandleResult =
DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(),
&temporaryHandle, THREAD_QUERY_INFORMATION, FALSE, 0);
printf("DuplicateHandle returned %d\n",
duplicateHandleResult);
if (duplicateHandleResult != 0)
{
// Create buffer to recieve thread info
DWORD threadInfo[7] = {0,0,0,0,0,0,0};

// Obtain and show thread info
DWORD ntQueryInformationThreadResult =
ntQueryInformationThreadEP(temporaryHandle, 0, threadInfo, 28,
(PDWORD)NULL);
printf("NtQueryInformationThread returned %d\n",
ntQueryInformationThreadResult);
if (ntQueryInformationThreadResult == 0)
{
printf("Process ID: %d\n", threadInfo[2]);
printf("Thread ID: %d\n", threadInfo[3]);
}
else
{
printf("Cannot query the thread information\n");
returnCode = 1;
}

// Cleanup
CloseHandle(temporaryHandle);
}
else
{
printf("Cannot duplicate the thread handle to
THREAD_QUERY_INFORMATION rights\n");
returnCode = 1;
}

// Cleanup
CloseHandle(handle);
}
else
{
printf("Cannot open the thread with THREAD_SUSPEND_RESUME
rights\n");
returnCode = 1;
}

// Cleanup DLL
FreeLibrary(ntDLLHandle);

// Wait for user input
getchar();

return returnCode;
}

Loading...