nt-stuff.c 6.4 KB

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