nt-stuff.c 6.4 KB

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