nt-stuff.h 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. #pragma once
  2. #include <winternl.h>
  3. #define THREAD_STATE_WAITING 5
  4. #define THREAD_WAIT_REASON_SUSPENDED 5
  5. typedef struct _OBS_SYSTEM_PROCESS_INFORMATION2 {
  6. ULONG NextEntryOffset;
  7. ULONG ThreadCount;
  8. BYTE Reserved1[48];
  9. PVOID Reserved2[3];
  10. HANDLE UniqueProcessId;
  11. PVOID Reserved3;
  12. ULONG HandleCount;
  13. BYTE Reserved4[4];
  14. PVOID Reserved5[11];
  15. SIZE_T PeakPagefileUsage;
  16. SIZE_T PrivatePageCount;
  17. LARGE_INTEGER Reserved6[6];
  18. } OBS_SYSTEM_PROCESS_INFORMATION2;
  19. typedef struct _OBS_SYSTEM_THREAD_INFORMATION {
  20. FILETIME KernelTime;
  21. FILETIME UserTime;
  22. FILETIME CreateTime;
  23. DWORD WaitTime;
  24. PVOID Address;
  25. HANDLE UniqueProcessId;
  26. HANDLE UniqueThreadId;
  27. DWORD Priority;
  28. DWORD BasePriority;
  29. DWORD ContextSwitches;
  30. DWORD ThreadState;
  31. DWORD WaitReason;
  32. DWORD Reserved1;
  33. } OBS_SYSTEM_THREAD_INFORMATION;
  34. #ifndef NT_SUCCESS
  35. #define NT_SUCCESS(status) ((NTSTATUS)(status) >= 0)
  36. #endif
  37. #define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
  38. #define init_named_attribs(o, name) \
  39. do { \
  40. (o)->Length = sizeof(*(o)); \
  41. (o)->ObjectName = name; \
  42. (o)->RootDirectory = NULL; \
  43. (o)->Attributes = 0; \
  44. (o)->SecurityDescriptor = NULL; \
  45. (o)->SecurityQualityOfService = NULL; \
  46. } while (false)
  47. typedef void(WINAPI *RTLINITUNICODESTRINGFUNC)(PCUNICODE_STRING pstr,
  48. const wchar_t *lpstrName);
  49. typedef NTSTATUS(WINAPI *NTOPENFUNC)(PHANDLE phandle, ACCESS_MASK access,
  50. POBJECT_ATTRIBUTES objattr);
  51. typedef ULONG(WINAPI *RTLNTSTATUSTODOSERRORFUNC)(NTSTATUS status);
  52. typedef NTSTATUS(WINAPI *NTQUERYSYSTEMINFORMATIONFUNC)(SYSTEM_INFORMATION_CLASS,
  53. PVOID, ULONG, PULONG);
  54. static FARPROC get_nt_func(const char *name)
  55. {
  56. static bool initialized = false;
  57. static HANDLE ntdll = NULL;
  58. if (!initialized) {
  59. ntdll = GetModuleHandleW(L"ntdll");
  60. initialized = true;
  61. }
  62. return GetProcAddress(ntdll, name);
  63. }
  64. static void nt_set_last_error(NTSTATUS status)
  65. {
  66. static bool initialized = false;
  67. static RTLNTSTATUSTODOSERRORFUNC func = NULL;
  68. if (!initialized) {
  69. func = (RTLNTSTATUSTODOSERRORFUNC)get_nt_func(
  70. "RtlNtStatusToDosError");
  71. initialized = true;
  72. }
  73. if (func)
  74. SetLastError(func(status));
  75. }
  76. static void rtl_init_str(UNICODE_STRING *unistr, const wchar_t *str)
  77. {
  78. static bool initialized = false;
  79. static RTLINITUNICODESTRINGFUNC func = NULL;
  80. if (!initialized) {
  81. func = (RTLINITUNICODESTRINGFUNC)get_nt_func(
  82. "RtlInitUnicodeString");
  83. initialized = true;
  84. }
  85. if (func)
  86. func(unistr, str);
  87. }
  88. static NTSTATUS nt_query_information(SYSTEM_INFORMATION_CLASS info_class,
  89. PVOID info, ULONG info_len, PULONG ret_len)
  90. {
  91. static bool initialized = false;
  92. static NTQUERYSYSTEMINFORMATIONFUNC func = NULL;
  93. if (!initialized) {
  94. func = (NTQUERYSYSTEMINFORMATIONFUNC)get_nt_func(
  95. "NtQuerySystemInformation");
  96. initialized = true;
  97. }
  98. if (func)
  99. return func(info_class, info, info_len, ret_len);
  100. return (NTSTATUS)-1;
  101. }
  102. static bool thread_is_suspended(DWORD process_id, DWORD thread_id)
  103. {
  104. ULONG size = 4096;
  105. bool suspended = false;
  106. void *data = malloc(size);
  107. for (;;) {
  108. NTSTATUS stat = nt_query_information(SystemProcessInformation,
  109. data, size, &size);
  110. if (NT_SUCCESS(stat))
  111. break;
  112. if (stat != STATUS_INFO_LENGTH_MISMATCH) {
  113. goto fail;
  114. }
  115. free(data);
  116. size += 1024;
  117. data = malloc(size);
  118. }
  119. OBS_SYSTEM_PROCESS_INFORMATION2 *spi = data;
  120. for (;;) {
  121. if (spi->UniqueProcessId == (HANDLE)(DWORD_PTR)process_id) {
  122. break;
  123. }
  124. ULONG offset = spi->NextEntryOffset;
  125. if (!offset)
  126. goto fail;
  127. spi = (OBS_SYSTEM_PROCESS_INFORMATION2 *)((BYTE *)spi + offset);
  128. }
  129. OBS_SYSTEM_THREAD_INFORMATION *sti;
  130. OBS_SYSTEM_THREAD_INFORMATION *info = NULL;
  131. sti = (OBS_SYSTEM_THREAD_INFORMATION *)((BYTE *)spi + sizeof(*spi));
  132. for (ULONG i = 0; i < spi->ThreadCount; i++) {
  133. if (sti[i].UniqueThreadId == (HANDLE)(DWORD_PTR)thread_id) {
  134. info = &sti[i];
  135. break;
  136. }
  137. }
  138. if (info) {
  139. suspended = info->ThreadState == THREAD_STATE_WAITING &&
  140. info->WaitReason == THREAD_WAIT_REASON_SUSPENDED;
  141. }
  142. fail:
  143. free(data);
  144. return suspended;
  145. }
  146. #define MAKE_NT_OPEN_FUNC(func_name, nt_name, access) \
  147. static HANDLE func_name(const wchar_t *name) \
  148. { \
  149. static bool initialized = false; \
  150. static NTOPENFUNC open = NULL; \
  151. HANDLE handle; \
  152. NTSTATUS status; \
  153. UNICODE_STRING unistr; \
  154. OBJECT_ATTRIBUTES attr; \
  155. \
  156. if (!initialized) { \
  157. open = (NTOPENFUNC)get_nt_func(#nt_name); \
  158. initialized = true; \
  159. } \
  160. \
  161. if (!open) \
  162. return NULL; \
  163. \
  164. rtl_init_str(&unistr, name); \
  165. init_named_attribs(&attr, &unistr); \
  166. \
  167. status = open(&handle, access, &attr); \
  168. if (NT_SUCCESS(status)) \
  169. return handle; \
  170. nt_set_last_error(status); \
  171. return NULL; \
  172. }
  173. MAKE_NT_OPEN_FUNC(nt_open_mutex, NtOpenMutant, SYNCHRONIZE)
  174. MAKE_NT_OPEN_FUNC(nt_open_event, NtOpenEvent, EVENT_MODIFY_STATE | SYNCHRONIZE)
  175. MAKE_NT_OPEN_FUNC(nt_open_map, NtOpenSection, FILE_MAP_READ | FILE_MAP_WRITE)