Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

575 lines
13 KiB

  1. /*++
  2. Copyright (c) 1999-2002 Microsoft Corporation
  3. Module Name:
  4. nt4.c
  5. Abstract:
  6. NT 4 specific routines.
  7. The following routine are exported from this file:
  8. o Nt4OpenThread
  9. o Nt4GetProcessInfo
  10. o Nt4EnumProcessModules
  11. o Nt4GetModuleFileNameExW
  12. Author:
  13. Matthew D Hendel (math) 10-Sept-1999
  14. Revision History:
  15. Environment:
  16. NT 4.0 only.
  17. --*/
  18. #include "pch.h"
  19. #include "ntx.h"
  20. #include "nt4.h"
  21. #include "nt4p.h"
  22. #include "impl.h"
  23. BOOL
  24. WINAPI
  25. Nt4EnumProcessModules(
  26. HANDLE hProcess,
  27. HMODULE *lphModule,
  28. DWORD cb,
  29. LPDWORD lpcbNeeded
  30. );
  31. HANDLE
  32. WINAPI
  33. Nt4OpenThread(
  34. DWORD dwDesiredAccess,
  35. BOOL bInheritHandle,
  36. DWORD dwThreadId
  37. )
  38. {
  39. NTSTATUS Status;
  40. NT4_OBJECT_ATTRIBUTES Obja;
  41. HANDLE Handle;
  42. NT4_CLIENT_ID ClientId;
  43. ClientId.UniqueThread = (HANDLE)LongToHandle(dwThreadId);
  44. ClientId.UniqueProcess = (HANDLE)NULL;
  45. Nt4InitializeObjectAttributes(
  46. &Obja,
  47. NULL,
  48. (bInheritHandle ? NT4_OBJ_INHERIT : 0),
  49. NULL,
  50. NULL
  51. );
  52. Status = NtOpenThread(
  53. &Handle,
  54. (ACCESS_MASK)dwDesiredAccess,
  55. (POBJECT_ATTRIBUTES)&Obja,
  56. (PCLIENT_ID)&ClientId
  57. );
  58. if ( NT_SUCCESS(Status) ) {
  59. return Handle;
  60. }
  61. else {
  62. return NULL;
  63. }
  64. }
  65. BOOL
  66. Nt4GetProcessInfo(
  67. IN HANDLE hProcess,
  68. IN ULONG ProcessId,
  69. IN ULONG DumpType,
  70. IN MINIDUMP_CALLBACK_ROUTINE CallbackRoutine,
  71. IN PVOID CallbackParam,
  72. OUT PINTERNAL_PROCESS * ProcessRet
  73. )
  74. {
  75. BOOL Succ;
  76. ULONG i;
  77. NTSTATUS Status;
  78. ULONG BufferSize;
  79. LPVOID Buffer;
  80. PNT4_SYSTEM_PROCESS_INFORMATION ProcessInfo;
  81. PNT4_SYSTEM_THREAD_INFORMATION ThreadInfo;
  82. PINTERNAL_THREAD Thread;
  83. PINTERNAL_MODULE Module;
  84. PINTERNAL_PROCESS Process;
  85. HMODULE Modules [ 512 ];
  86. ULONG ModulesSize;
  87. ULONG NumberOfModules;
  88. ULONG_PTR Next;
  89. BufferSize = 64 * KBYTE;
  90. Buffer = NULL;
  91. do {
  92. if (Buffer) {
  93. FreeMemory (Buffer);
  94. }
  95. Buffer = AllocMemory ( BufferSize );
  96. if ( Buffer == NULL) {
  97. return FALSE;
  98. }
  99. Status = NtQuerySystemInformation (
  100. Nt4SystemProcessInformation,
  101. Buffer,
  102. BufferSize,
  103. NULL
  104. );
  105. if (!NT_SUCCESS (Status) && Status != STATUS_INFO_LENGTH_MISMATCH) {
  106. GenAccumulateStatus(MDSTATUS_CALL_FAILED);
  107. return FALSE;
  108. }
  109. BufferSize += (8 * KBYTE);
  110. } while (Status == STATUS_INFO_LENGTH_MISMATCH);
  111. //
  112. // Find the correct process in the process list.
  113. //
  114. ProcessInfo = (PNT4_SYSTEM_PROCESS_INFORMATION) Buffer;
  115. while (ProcessInfo->NextEntryOffset &&
  116. ProcessInfo->UniqueProcessId != (HANDLE) ProcessId) {
  117. Next = ((ULONG_PTR)ProcessInfo + ProcessInfo->NextEntryOffset);
  118. ProcessInfo = (PNT4_SYSTEM_PROCESS_INFORMATION) Next;
  119. }
  120. //
  121. // Could not find a matching process in the process list.
  122. //
  123. if (ProcessInfo->UniqueProcessId != (HANDLE) ProcessId) {
  124. Succ = FALSE;
  125. GenAccumulateStatus(MDSTATUS_INTERNAL_ERROR);
  126. goto Exit;
  127. }
  128. //
  129. // Create an INTERNAL_PROCESS object and copy the process information
  130. // into it.
  131. //
  132. Process = GenAllocateProcessObject ( hProcess, ProcessId );
  133. if ( Process == NULL ) {
  134. return FALSE;
  135. }
  136. //
  137. // Walk the thread list for this process, copying thread information
  138. // for each thread. Walking the thread list also suspends all the threads
  139. // in the process. This should be done before walking the module list
  140. // to minimize the number of race conditions.
  141. //
  142. ThreadInfo = (PNT4_SYSTEM_THREAD_INFORMATION)(ProcessInfo + 1);
  143. Process->NumberOfThreads = 0;
  144. for (i = 0; i < ProcessInfo->NumberOfThreads; i++) {
  145. ULONG WriteFlags;
  146. if (!GenExecuteIncludeThreadCallback(hProcess,
  147. ProcessId,
  148. DumpType,
  149. (ULONG)ThreadInfo->ClientId.UniqueThread,
  150. CallbackRoutine,
  151. CallbackParam,
  152. &WriteFlags) ||
  153. IsFlagClear(WriteFlags, ThreadWriteThread)) {
  154. ThreadInfo++;
  155. continue;
  156. }
  157. Status = GenAllocateThreadObject (
  158. Process,
  159. hProcess,
  160. (ULONG) ThreadInfo->ClientId.UniqueThread,
  161. DumpType,
  162. WriteFlags,
  163. &Thread
  164. );
  165. if (FAILED(Status)) {
  166. Succ = FALSE;
  167. goto Exit;
  168. }
  169. // If Status is S_FALSE it means that the thread
  170. // couldn't be opened and probably exited before
  171. // we got to it. Just continue on.
  172. if (Status == S_OK) {
  173. InsertTailList (&Process->ThreadList, &Thread->ThreadsLink);
  174. Process->NumberOfThreads++;
  175. }
  176. ThreadInfo++;
  177. }
  178. //
  179. // Get the module information. Use PSAPI since it actually works.
  180. //
  181. ModulesSize = 0;
  182. Succ = Nt4EnumProcessModules (
  183. Process->ProcessHandle,
  184. Modules,
  185. sizeof (Modules),
  186. &ModulesSize
  187. );
  188. if ( !Succ ) {
  189. GenAccumulateStatus(MDSTATUS_CALL_FAILED);
  190. goto Exit;
  191. }
  192. NumberOfModules = ModulesSize / sizeof (HMODULE);
  193. for (i = 0; i < NumberOfModules; i++) {
  194. ULONG WriteFlags;
  195. if (!GenExecuteIncludeModuleCallback(hProcess,
  196. ProcessId,
  197. DumpType,
  198. (LONG_PTR)Modules[i],
  199. CallbackRoutine,
  200. CallbackParam,
  201. &WriteFlags) ||
  202. IsFlagClear(WriteFlags, ModuleWriteModule)) {
  203. continue;
  204. }
  205. Module = NtxAllocateModuleObject (
  206. Process,
  207. Process->ProcessHandle,
  208. (LONG_PTR) Modules [ i ],
  209. DumpType,
  210. WriteFlags,
  211. NULL
  212. );
  213. if ( Module == NULL ) {
  214. Succ = FALSE;
  215. goto Exit;
  216. }
  217. InsertTailList (&Process->ModuleList, &Module->ModulesLink);
  218. }
  219. Process->NumberOfModules = NumberOfModules;
  220. Succ = TRUE;
  221. Exit:
  222. if ( Buffer ) {
  223. FreeMemory ( Buffer );
  224. Buffer = NULL;
  225. }
  226. if ( !Succ && Process != NULL ) {
  227. GenFreeProcessObject ( Process );
  228. Process = NULL;
  229. }
  230. *ProcessRet = Process;
  231. return Succ;
  232. }
  233. //
  234. // From PSAPI
  235. //
  236. BOOL
  237. Nt4FindModule(
  238. IN HANDLE hProcess,
  239. IN HMODULE hModule,
  240. OUT PNT4_LDR_DATA_TABLE_ENTRY LdrEntryData
  241. )
  242. /*++
  243. Routine Description:
  244. This function retrieves the loader table entry for the specified
  245. module. The function copies the entry into the buffer pointed to
  246. by the LdrEntryData parameter.
  247. Arguments:
  248. hProcess - Supplies the target process.
  249. hModule - Identifies the module whose loader entry is being
  250. requested. A value of NULL references the module handle
  251. associated with the image file that was used to create the
  252. process.
  253. LdrEntryData - Returns the requested table entry.
  254. Return Value:
  255. TRUE if a matching entry was found.
  256. --*/
  257. {
  258. NT4_PROCESS_BASIC_INFORMATION BasicInfo;
  259. NTSTATUS Status;
  260. PNT4_PEB Peb;
  261. PNT4_PEB_LDR_DATA Ldr;
  262. PLIST_ENTRY LdrHead;
  263. PLIST_ENTRY LdrNext;
  264. Status = NtQueryInformationProcess(
  265. hProcess,
  266. Nt4ProcessBasicInformation,
  267. &BasicInfo,
  268. sizeof(BasicInfo),
  269. NULL
  270. );
  271. if ( !NT_SUCCESS(Status) ) {
  272. return(FALSE);
  273. }
  274. Peb = BasicInfo.PebBaseAddress;
  275. if ( hModule == NULL ) {
  276. if (!ReadProcessMemory(hProcess, &Peb->ImageBaseAddress, &hModule, sizeof(hModule), NULL)) {
  277. return(FALSE);
  278. }
  279. }
  280. //
  281. // Ldr = Peb->Ldr
  282. //
  283. if (!ReadProcessMemory(hProcess, &Peb->Ldr, &Ldr, sizeof(Ldr), NULL)) {
  284. return (FALSE);
  285. }
  286. if (!Ldr) {
  287. // Ldr might be null (for instance, if the process hasn't started yet).
  288. SetLastError(ERROR_INVALID_HANDLE);
  289. return (FALSE);
  290. }
  291. LdrHead = &Ldr->InMemoryOrderModuleList;
  292. //
  293. // LdrNext = Head->Flink;
  294. //
  295. if (!ReadProcessMemory(hProcess, &LdrHead->Flink, &LdrNext, sizeof(LdrNext), NULL)) {
  296. return(FALSE);
  297. }
  298. while (LdrNext != LdrHead) {
  299. PNT4_LDR_DATA_TABLE_ENTRY LdrEntry;
  300. LdrEntry = CONTAINING_RECORD(
  301. LdrNext,
  302. NT4_LDR_DATA_TABLE_ENTRY,
  303. InMemoryOrderLinks);
  304. if (!ReadProcessMemory(hProcess, LdrEntry, LdrEntryData, sizeof(*LdrEntryData), NULL)) {
  305. return(FALSE);
  306. }
  307. if ((HMODULE) LdrEntryData->DllBase == hModule) {
  308. return(TRUE);
  309. }
  310. LdrNext = LdrEntryData->InMemoryOrderLinks.Flink;
  311. }
  312. SetLastError(ERROR_INVALID_HANDLE);
  313. return(FALSE);
  314. }
  315. BOOL
  316. WINAPI
  317. Nt4EnumProcessModules(
  318. HANDLE hProcess,
  319. HMODULE *lphModule,
  320. DWORD cb,
  321. LPDWORD lpcbNeeded
  322. )
  323. {
  324. NT4_PROCESS_BASIC_INFORMATION BasicInfo;
  325. NTSTATUS Status;
  326. PNT4_PEB Peb;
  327. PNT4_PEB_LDR_DATA Ldr;
  328. PLIST_ENTRY LdrHead;
  329. PLIST_ENTRY LdrNext;
  330. DWORD chMax;
  331. DWORD ch;
  332. Status = NtQueryInformationProcess(
  333. hProcess,
  334. Nt4ProcessBasicInformation,
  335. &BasicInfo,
  336. sizeof(BasicInfo),
  337. NULL
  338. );
  339. if ( !NT_SUCCESS(Status) ) {
  340. return(FALSE);
  341. }
  342. Peb = BasicInfo.PebBaseAddress;
  343. //
  344. // Ldr = Peb->Ldr
  345. //
  346. if (!ReadProcessMemory(hProcess, &Peb->Ldr, &Ldr, sizeof(Ldr), NULL)) {
  347. return(FALSE);
  348. }
  349. LdrHead = &Ldr->InMemoryOrderModuleList;
  350. //
  351. // LdrNext = Head->Flink;
  352. //
  353. if (!ReadProcessMemory(hProcess, &LdrHead->Flink, &LdrNext, sizeof(LdrNext), NULL)) {
  354. return(FALSE);
  355. }
  356. chMax = cb / sizeof(HMODULE);
  357. ch = 0;
  358. while (LdrNext != LdrHead) {
  359. PNT4_LDR_DATA_TABLE_ENTRY LdrEntry;
  360. NT4_LDR_DATA_TABLE_ENTRY LdrEntryData;
  361. LdrEntry = CONTAINING_RECORD(
  362. LdrNext,
  363. NT4_LDR_DATA_TABLE_ENTRY,
  364. InMemoryOrderLinks);
  365. if (!ReadProcessMemory(hProcess, LdrEntry, &LdrEntryData, sizeof(LdrEntryData), NULL)) {
  366. return(FALSE);
  367. }
  368. if (ch < chMax) {
  369. try {
  370. lphModule[ch] = (HMODULE) LdrEntryData.DllBase;
  371. }
  372. except (EXCEPTION_EXECUTE_HANDLER) {
  373. return(FALSE);
  374. }
  375. }
  376. ch++;
  377. LdrNext = LdrEntryData.InMemoryOrderLinks.Flink;
  378. }
  379. try {
  380. *lpcbNeeded = ch * sizeof(HMODULE);
  381. }
  382. except (EXCEPTION_EXECUTE_HANDLER) {
  383. return(FALSE);
  384. }
  385. return(TRUE);
  386. }
  387. DWORD
  388. WINAPI
  389. Nt4GetModuleFileNameExW(
  390. HANDLE hProcess,
  391. HMODULE hModule,
  392. LPWSTR lpFilename,
  393. DWORD nSize
  394. )
  395. /*++
  396. Routine Description:
  397. This function retrieves the full pathname of the executable file
  398. from which the specified module was loaded. The function copies the
  399. null-terminated filename into the buffer pointed to by the
  400. lpFilename parameter.
  401. Routine Description:
  402. hModule - Identifies the module whose executable file name is being
  403. requested. A value of NULL references the module handle
  404. associated with the image file that was used to create the
  405. process.
  406. lpFilename - Points to the buffer that is to receive the filename.
  407. nSize - Specifies the maximum number of characters to copy. If the
  408. filename is longer than the maximum number of characters
  409. specified by the nSize parameter, it is truncated.
  410. Return Value:
  411. The return value specifies the actual length of the string copied to
  412. the buffer. A return value of zero indicates an error and extended
  413. error status is available using the GetLastError function.
  414. Arguments:
  415. --*/
  416. {
  417. NT4_LDR_DATA_TABLE_ENTRY LdrEntryData;
  418. DWORD cb;
  419. if (!Nt4FindModule(hProcess, hModule, &LdrEntryData)) {
  420. return(0);
  421. }
  422. nSize *= sizeof(WCHAR);
  423. cb = LdrEntryData.FullDllName.MaximumLength;
  424. if ( nSize < cb ) {
  425. cb = nSize;
  426. }
  427. if (!ReadProcessMemory(hProcess, LdrEntryData.FullDllName.Buffer, lpFilename, cb, NULL)) {
  428. return(0);
  429. }
  430. if (cb == LdrEntryData.FullDllName.MaximumLength) {
  431. cb -= sizeof(WCHAR);
  432. }
  433. return(cb / sizeof(WCHAR));
  434. }