Ключ должен вызвать функцию NtQueryInformationThread
. Это не полностью «официальная» функция (возможно, недокументированная в прошлом?), Но в документации нет альтернативы для получения начального адреса потока.
Я завернул его в .NET. -другой вызов, который принимает идентификатор потока и возвращает начальный адрес как IntPtr
. Этот код был протестирован в режиме x86 и x64, а в последнем он был протестирован как на 32-битном, так и на 64-битном целевом процессе.
Одна вещь, которую я не тестировал, выполняла это с низким привилегии; Я бы ожидал, что этот код требует, чтобы вызывающий абонент имел SeDebugPrivilege
.
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
class Program
{
static void Main(string[] args)
{
PrintProcessThreads(Process.GetCurrentProcess().Id);
PrintProcessThreads(4156); // some other random process on my system
Console.WriteLine("Press Enter to exit.");
Console.ReadLine();
}
static void PrintProcessThreads(int processId)
{
Console.WriteLine(string.Format("Process Id: {0:X4}", processId));
var threads = Process.GetProcessById(processId).Threads.OfType();
foreach (var pt in threads)
Console.WriteLine(" Thread Id: {0:X4}, Start Address: {1:X16}",
pt.Id, (ulong) GetThreadStartAddress(pt.Id));
}
static IntPtr GetThreadStartAddress(int threadId)
{
var hThread = OpenThread(ThreadAccess.QueryInformation, false, threadId);
if (hThread == IntPtr.Zero)
throw new Win32Exception();
var buf = Marshal.AllocHGlobal(IntPtr.Size);
try
{
var result = NtQueryInformationThread(hThread,
ThreadInfoClass.ThreadQuerySetWin32StartAddress,
buf, IntPtr.Size, IntPtr.Zero);
if (result != 0)
throw new Win32Exception(string.Format("NtQueryInformationThread failed; NTSTATUS = {0:X8}", result));
return Marshal.ReadIntPtr(buf);
}
finally
{
CloseHandle(hThread);
Marshal.FreeHGlobal(buf);
}
}
[DllImport("ntdll.dll", SetLastError = true)]
static extern int NtQueryInformationThread(
IntPtr threadHandle,
ThreadInfoClass threadInformationClass,
IntPtr threadInformation,
int threadInformationLength,
IntPtr returnLengthPtr);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, int dwThreadId);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool CloseHandle(IntPtr hObject);
[Flags]
public enum ThreadAccess : int
{
Terminate = 0x0001,
SuspendResume = 0x0002,
GetContext = 0x0008,
SetContext = 0x0010,
SetInformation = 0x0020,
QueryInformation = 0x0040,
SetThreadToken = 0x0080,
Impersonate = 0x0100,
DirectImpersonation = 0x0200
}
public enum ThreadInfoClass : int
{
ThreadQuerySetWin32StartAddress = 9
}
}
Вывод в моей системе:
Process Id: 2168 (this is a 64-bit process)
Thread Id: 1C80, Start Address: 0000000001090000
Thread Id: 210C, Start Address: 000007FEEE8806D4
Thread Id: 24BC, Start Address: 000007FEEE80A74C
Thread Id: 12F4, Start Address: 0000000076D2AEC0
Process Id: 103C (this is a 32-bit process)
Thread Id: 2510, Start Address: 0000000000FEA253
Thread Id: 0A0C, Start Address: 0000000076F341F3
Thread Id: 2438, Start Address: 0000000076F36679
Thread Id: 2514, Start Address: 0000000000F96CFD
Thread Id: 2694, Start Address: 00000000025CCCE6
, кроме материала в круглых скобках, поскольку это требует
Что касается ошибки SymFromAddress
«модуль не найден», я просто хотел упомянуть, что нужно называть SymInitialize
с fInvadeProcess = true
ИЛИ загружать модуль вручную, , как описано в MSDN .
Я знаю, что вы говорите, что это не так в вашей ситуации, но я оставлю это в интересах любого, кто находит этот вопрос через те ключевые слова.