nt-stuff.h 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  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, const wchar_t *lpstrName);
  48. typedef NTSTATUS (WINAPI *NTOPENFUNC)(PHANDLE phandle, ACCESS_MASK access, POBJECT_ATTRIBUTES objattr);
  49. typedef ULONG (WINAPI *RTLNTSTATUSTODOSERRORFUNC)(NTSTATUS status);
  50. typedef NTSTATUS (WINAPI *NTQUERYSYSTEMINFORMATIONFUNC)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG);
  51. static FARPROC get_nt_func(const char *name)
  52. {
  53. static bool initialized = false;
  54. static HANDLE ntdll = NULL;
  55. if (!initialized) {
  56. ntdll = GetModuleHandleW(L"ntdll");
  57. initialized = true;
  58. }
  59. return GetProcAddress(ntdll, name);
  60. }
  61. static void nt_set_last_error(NTSTATUS status)
  62. {
  63. static bool initialized = false;
  64. static RTLNTSTATUSTODOSERRORFUNC func = NULL;
  65. if (!initialized) {
  66. func = (RTLNTSTATUSTODOSERRORFUNC)get_nt_func(
  67. "RtlNtStatusToDosError");
  68. initialized = true;
  69. }
  70. if (func)
  71. SetLastError(func(status));
  72. }
  73. static void rtl_init_str(UNICODE_STRING *unistr, const wchar_t *str)
  74. {
  75. static bool initialized = false;
  76. static RTLINITUNICODESTRINGFUNC func = NULL;
  77. if (!initialized) {
  78. func = (RTLINITUNICODESTRINGFUNC)get_nt_func(
  79. "RtlInitUnicodeString");
  80. initialized = true;
  81. }
  82. if (func)
  83. func(unistr, str);
  84. }
  85. static NTSTATUS nt_query_information(SYSTEM_INFORMATION_CLASS info_class,
  86. PVOID info, ULONG info_len, PULONG ret_len)
  87. {
  88. static bool initialized = false;
  89. static NTQUERYSYSTEMINFORMATIONFUNC func = NULL;
  90. if (!initialized) {
  91. func = (NTQUERYSYSTEMINFORMATIONFUNC)get_nt_func(
  92. "NtQuerySystemInformation");
  93. initialized = true;
  94. }
  95. if (func)
  96. return func(info_class, info, info_len, ret_len);
  97. return (NTSTATUS)-1;
  98. }
  99. static bool thread_is_suspended(DWORD process_id, DWORD thread_id)
  100. {
  101. ULONG size = 4096;
  102. bool suspended = false;
  103. void *data = malloc(size);
  104. for (;;) {
  105. NTSTATUS stat = nt_query_information(SystemProcessInformation,
  106. data, size, &size);
  107. if (NT_SUCCESS(stat))
  108. break;
  109. if (stat != STATUS_INFO_LENGTH_MISMATCH) {
  110. goto fail;
  111. }
  112. free(data);
  113. size += 1024;
  114. data = malloc(size);
  115. }
  116. OBS_SYSTEM_PROCESS_INFORMATION2 *spi = data;
  117. for (;;) {
  118. if (spi->UniqueProcessId == (HANDLE)(DWORD_PTR)process_id) {
  119. break;
  120. }
  121. ULONG offset = spi->NextEntryOffset;
  122. if (!offset)
  123. goto fail;
  124. spi = (OBS_SYSTEM_PROCESS_INFORMATION2*)((BYTE*)spi + offset);
  125. }
  126. OBS_SYSTEM_THREAD_INFORMATION *sti;
  127. OBS_SYSTEM_THREAD_INFORMATION *info = NULL;
  128. sti = (OBS_SYSTEM_THREAD_INFORMATION*)((BYTE*)spi + sizeof(*spi));
  129. for (ULONG i = 0; i < spi->ThreadCount; i++) {
  130. if (sti[i].UniqueThreadId == (HANDLE)(DWORD_PTR)thread_id) {
  131. info = &sti[i];
  132. break;
  133. }
  134. }
  135. if (info) {
  136. suspended = info->ThreadState == THREAD_STATE_WAITING &&
  137. info->WaitReason == THREAD_WAIT_REASON_SUSPENDED;
  138. }
  139. fail:
  140. free(data);
  141. return suspended;
  142. }
  143. #define MAKE_NT_OPEN_FUNC(func_name, nt_name, access) \
  144. static HANDLE func_name(const wchar_t *name) \
  145. { \
  146. static bool initialized = false; \
  147. static NTOPENFUNC open = NULL; \
  148. HANDLE handle; \
  149. NTSTATUS status; \
  150. UNICODE_STRING unistr; \
  151. OBJECT_ATTRIBUTES attr; \
  152. \
  153. if (!initialized) { \
  154. open = (NTOPENFUNC)get_nt_func(#nt_name); \
  155. initialized = true; \
  156. } \
  157. \
  158. if (!open) \
  159. return NULL; \
  160. \
  161. rtl_init_str(&unistr, name); \
  162. init_named_attribs(&attr, &unistr); \
  163. \
  164. status = open(&handle, access, &attr); \
  165. if (NT_SUCCESS(status)) \
  166. return handle; \
  167. nt_set_last_error(status); \
  168. return NULL; \
  169. }
  170. MAKE_NT_OPEN_FUNC(nt_open_mutex, NtOpenMutant, SYNCHRONIZE)
  171. MAKE_NT_OPEN_FUNC(nt_open_event, NtOpenEvent, EVENT_MODIFY_STATE | SYNCHRONIZE)
  172. MAKE_NT_OPEN_FUNC(nt_open_map, NtOpenSection, FILE_MAP_READ | FILE_MAP_WRITE)