nt-stuff.h 6.4 KB

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