C#获取外部进程的线程起始地址
Get Thread's Start Address for External Process in C#
我已经设置了一个简单的 C# 程序。
我从 kernel32.dll
OpenProcess
, ReadProcessMemory
and WriteProcessMemory
.
导入
我已将外部进程获取到 Process
class。
如何获得 StartAddress
for Thread #0 for that specific ProcessThread
?
Process process = Process.GetProcessesByName("Calculator")[0];
if (process == null) {
Console.WriteLine("Process not found");
return;
}
foreach (ProcessThread thread in process.Threads) {
Console.WriteLine(thread.StartAddress);
}
上面代码的结果是:
-157479632
-157479632
-157479632
-157479632
0
-157479632
-157479632
-157479632
-157479632
-157479632
-157479632
-157479632
为什么有的是0,其余的都是一样的,都是负数?
在线程对象 (struct _ETHREAD
) 中存在 2 个不同的起始地址 - StartAddress
- 这是通过 LdrInitializeThunk
遍历 DLL 后线程开始执行的地址。还存在第二个地址 - Win32StartAddress
。这个地址的意义 - 当我们通过 win32 函数 Create[Remothe]Thread
(或者它 shell)创建线程时 - win32 level set common thread StartAddress
to ntdll.RtlThreadThreadStart
(这个函数的名字取决于来自 windows 版本,例如 xp - 另一个名称)和实际 lpStartAddress 作为参数传递给 Create[Remothe]Thread
。 RtlThreadThreadStart
已经调用了实际的 lpStartAddress。 lpStartAddress 并存储在 Win32StartAddress
中。
因为大多数线程都是通过 win32 创建的 Create[Remothe]Thread
- 它们都具有相同的 StartAddress
(对于另一个 StartAddress
我们需要直接调用低级 api 像 RtlCreateUserThread
。同样在 System 进程中 - StartAddress
是内核中的实际线程起始地址)
当您使用代码时
foreach (ProcessThread thread in process.Threads) {
Console.WriteLine(thread.StartAddress);
}
你得到了 StartAddress
- 绝对正常,你在大多数情况下给出了相同的地址。在某些情况下,您可能会得到 0 或另一个不正确的值 - 因为在某些版本中 windows StartAddress
与另一个成员联合保存并且可以被覆盖。
要获得 Win32StartAddress
,您必须使用 THREAD_QUERY_LIMITED_INFORMATION
或 THREAD_QUERY_INFORMATION
打开线程句柄,并使用 ThreadQuerySetWin32StartAddress
调用 ZwQueryInformationThread
PVOID pv;
ZwQueryInformationThread(hThread, ThreadQuerySetWin32StartAddress, &pv, sizeof(pv), 0);
大约 all negative?
因为你错误地打印了线程地址 - 指针。您将其打印为有符号整数。但您必须以 %p
格式
将其打印为十六进制指针
我已经设置了一个简单的 C# 程序。
我从 kernel32.dll
OpenProcess
, ReadProcessMemory
and WriteProcessMemory
.
我已将外部进程获取到 Process
class。
如何获得 StartAddress
for Thread #0 for that specific ProcessThread
?
Process process = Process.GetProcessesByName("Calculator")[0];
if (process == null) {
Console.WriteLine("Process not found");
return;
}
foreach (ProcessThread thread in process.Threads) {
Console.WriteLine(thread.StartAddress);
}
上面代码的结果是:
-157479632
-157479632
-157479632
-157479632
0
-157479632
-157479632
-157479632
-157479632
-157479632
-157479632
-157479632
为什么有的是0,其余的都是一样的,都是负数?
在线程对象 (struct _ETHREAD
) 中存在 2 个不同的起始地址 - StartAddress
- 这是通过 LdrInitializeThunk
遍历 DLL 后线程开始执行的地址。还存在第二个地址 - Win32StartAddress
。这个地址的意义 - 当我们通过 win32 函数 Create[Remothe]Thread
(或者它 shell)创建线程时 - win32 level set common thread StartAddress
to ntdll.RtlThreadThreadStart
(这个函数的名字取决于来自 windows 版本,例如 xp - 另一个名称)和实际 lpStartAddress 作为参数传递给 Create[Remothe]Thread
。 RtlThreadThreadStart
已经调用了实际的 lpStartAddress。 lpStartAddress 并存储在 Win32StartAddress
中。
因为大多数线程都是通过 win32 创建的 Create[Remothe]Thread
- 它们都具有相同的 StartAddress
(对于另一个 StartAddress
我们需要直接调用低级 api 像 RtlCreateUserThread
。同样在 System 进程中 - StartAddress
是内核中的实际线程起始地址)
当您使用代码时
foreach (ProcessThread thread in process.Threads) {
Console.WriteLine(thread.StartAddress);
}
你得到了 StartAddress
- 绝对正常,你在大多数情况下给出了相同的地址。在某些情况下,您可能会得到 0 或另一个不正确的值 - 因为在某些版本中 windows StartAddress
与另一个成员联合保存并且可以被覆盖。
要获得 Win32StartAddress
,您必须使用 THREAD_QUERY_LIMITED_INFORMATION
或 THREAD_QUERY_INFORMATION
打开线程句柄,并使用 ThreadQuerySetWin32StartAddress
ZwQueryInformationThread
PVOID pv;
ZwQueryInformationThread(hThread, ThreadQuerySetWin32StartAddress, &pv, sizeof(pv), 0);
大约 all negative?
因为你错误地打印了线程地址 - 指针。您将其打印为有符号整数。但您必须以 %p
格式