Leaked source code of windows server 2003
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.

1053 lines
26 KiB

  1. /*++
  2. Copyright (c) 1994-1998 Microsoft Corporation
  3. Module Name:
  4. tlist.c
  5. Abstract:
  6. This module implements a task list application.
  7. Author:
  8. Wesley Witt (wesw) 20-May-1994
  9. Mike Sartain (mikesart) 28-Oct-1994 Added detailed task information
  10. Julian Jiggins (julianj) 19-Mar-1998 Added list processes using specific module feature
  11. Shaun Cox (shaunco) 9-Jul-1998 Display services running in processes
  12. Environment:
  13. User Mode
  14. --*/
  15. #include "pch.h"
  16. #pragma hdrstop
  17. #include <dbghelp.h>
  18. #include "psapi.h"
  19. #include <tchar.h>
  20. #define BAD_PID ((DWORD)-1)
  21. DWORD numTasks;
  22. TASK_LIST tlist[MAX_TASKS];
  23. BOOL fShowServices;
  24. BOOL fShowMtsPackages;
  25. BOOL fShowSessionIds;
  26. BOOL fShowCommandLines;
  27. const char *Blanks = " ";
  28. VOID Usage(VOID);
  29. VOID PrintThreadInfo(PTASK_LIST pTaskList);
  30. BOOL FMatchTaskName(LPTSTR szPN, LPTSTR szWindowTitle, LPTSTR szProcessName);
  31. VOID GetFirstPidWithName(LPTSTR szTask);
  32. VOID
  33. PrintTask(
  34. DWORD i
  35. )
  36. {
  37. BOOL NameShown = FALSE;
  38. if (fShowSessionIds) {
  39. printf("%2d ", tlist[i].SessionId);
  40. }
  41. printf( "%4d %-15s ", tlist[i].dwProcessId, tlist[i].ProcessName );
  42. if (fShowServices && tlist[i].ServiceNames[0]) {
  43. printf( "Svcs: %s", tlist[i].ServiceNames);
  44. NameShown = TRUE;
  45. }
  46. if (fShowMtsPackages && tlist[i].MtsPackageNames[0]) {
  47. printf( "%sMts: %s", NameShown ? " " : "",
  48. tlist[i].MtsPackageNames);
  49. NameShown = TRUE;
  50. }
  51. if (!NameShown && tlist[i].hwnd) {
  52. if (fShowServices || fShowMtsPackages) {
  53. printf( "Title: %s", tlist[i].WindowTitle );
  54. }
  55. else {
  56. printf( " %s", tlist[i].WindowTitle );
  57. }
  58. }
  59. printf( "\n" );
  60. if (fShowCommandLines) {
  61. printf(" Command Line: %s\n", tlist[i].CommandLine);
  62. }
  63. }
  64. VOID
  65. PrintTaskTree(
  66. DWORD level,
  67. DWORD id
  68. )
  69. {
  70. DWORD i;
  71. DetectOrphans( tlist, numTasks );
  72. for (i=0; i<numTasks; i++) {
  73. if (tlist[i].flags) {
  74. continue;
  75. }
  76. // NOTE: The format of the output below should stay fixed forever. There are tools
  77. // at MS that depend on it.
  78. if (level == 0 || tlist[i].dwInheritedFromProcessId == id) {
  79. printf( "%.*s", level*2, Blanks );
  80. printf( "%s (%d)", tlist[i].ProcessName, tlist[i].dwProcessId );
  81. if (tlist[i].hwnd) {
  82. printf( " %s", tlist[i].WindowTitle );
  83. }
  84. printf( "\n" );
  85. tlist[i].flags = TRUE;
  86. if (tlist[i].dwProcessId != 0) {
  87. PrintTaskTree( level+1, tlist[i].dwProcessId );
  88. }
  89. }
  90. }
  91. }
  92. int __cdecl
  93. main(
  94. int argc,
  95. char *argv[]
  96. )
  97. /*++
  98. Routine Description:
  99. Main entrypoint for the TLIST application. This app prints
  100. a task list to stdout. The task list include the process id,
  101. task name, ant the window title.
  102. Arguments:
  103. argc - argument count
  104. argv - array of pointers to arguments
  105. Return Value:
  106. 0 - success
  107. --*/
  108. {
  109. DWORD i;
  110. TASK_LIST_ENUM te;
  111. BOOL fTree;
  112. BOOL fFindTasksUsingModule;
  113. BOOL fPidOnly = FALSE;
  114. DWORD cchPN = 0;
  115. LPSTR szPN = NULL;
  116. DWORD dwPID = BAD_PID;
  117. DWORD dwNumServices = 0;
  118. LPENUM_SERVICE_STATUS_PROCESS pServiceInfo = NULL;
  119. if (argc > 1 && (argv[1][0] == '-' || argv[1][0] == '/') && argv[1][1] == '?') {
  120. Usage();
  121. }
  122. fTree = FALSE;
  123. fFindTasksUsingModule = FALSE;
  124. if (argc > 1) {
  125. if ((argv[1][0] == '-' || argv[1][0] == '/') &&
  126. (argv[1][1] == 't' || argv[1][1] == 'T')) {
  127. fTree = TRUE;
  128. } else if ((argv[1][0] == '-' || argv[1][0] == '/') &&
  129. (argv[1][1] == 's' || argv[1][1] == 'S')) {
  130. fShowServices = TRUE;
  131. } else if ((argv[1][0] == '-' || argv[1][0] == '/') &&
  132. (argv[1][1] == 'k' || argv[1][1] == 'K')) {
  133. fShowMtsPackages = TRUE;
  134. } else if ((argv[1][0] == '-' || argv[1][0] == '/') &&
  135. (argv[1][1] == 'e' || argv[1][1] == 'E')) {
  136. fShowSessionIds = TRUE;
  137. } else if ((argv[1][0] == '-' || argv[1][0] == '/') &&
  138. (argv[1][1] == 'c' || argv[1][1] == 'C')) {
  139. fShowCommandLines = TRUE;
  140. } else if ((argv[1][0] == '-' || argv[1][0] == '/') &&
  141. (argv[1][1] == 'v' || argv[1][1] == 'V')) {
  142. fShowServices = TRUE;
  143. fShowMtsPackages = TRUE;
  144. fShowSessionIds = TRUE;
  145. fShowCommandLines = TRUE;
  146. } else if ((argv[1][0] == '-' || argv[1][0] == '/') &&
  147. (argv[1][1] == 'p' || argv[1][1] == 'P') && argc == 3) {
  148. _strlwr(argv[2]);
  149. if (!strcmp(argv[2], "system process")) {
  150. printf("0\n");
  151. return 0;
  152. }
  153. fPidOnly = TRUE;
  154. } else if ((argv[1][0] == '-' || argv[1][0] == '/') &&
  155. (argv[1][1] == 'p' || argv[1][1] == 'P') && argc == 4) {
  156. _strlwr(argv[2]);
  157. if (!strcmp(argv[2], "system")) {
  158. _strlwr(argv[3]);
  159. if (!strcmp(argv[3], "process")) {
  160. printf("0\n");
  161. return 0;
  162. }
  163. }
  164. Usage();
  165. } else if ((argv[1][0] == '-' || argv[1][0] == '/') &&
  166. (argv[1][1] == 'm' || argv[1][1] == 'M') && argc == 3) {
  167. fFindTasksUsingModule = TRUE;
  168. } else {
  169. szPN = argv[1];
  170. if (!(dwPID = atol(szPN)) && szPN[0] != '0' && szPN[1] != 0) {
  171. dwPID = BAD_PID;
  172. cchPN = strlen(szPN);
  173. _strupr(szPN);
  174. }
  175. }
  176. }
  177. //
  178. // lets be god
  179. //
  180. EnableDebugPriv();
  181. //
  182. // Include 32bit modules in enumeration
  183. //
  184. {
  185. DWORD SymOpt = SymGetOptions();
  186. SymOpt |= SYMOPT_INCLUDE_32BIT_MODULES;
  187. SymSetOptions(SYMOPT_INCLUDE_32BIT_MODULES);
  188. }
  189. //
  190. // get the task list for the system
  191. //
  192. //
  193. // Get the process information for all active Win32 services.
  194. // This allows us to print the service names next to the processes
  195. // that host them.
  196. //
  197. dwNumServices = GetServiceProcessInfo( &pServiceInfo );
  198. numTasks = GetTaskListEx(
  199. tlist,
  200. MAX_TASKS,
  201. cchPN || (dwPID != BAD_PID),
  202. dwNumServices,
  203. pServiceInfo);
  204. free( pServiceInfo );
  205. if (fShowMtsPackages) {
  206. AddMtsPackageNames(tlist, numTasks);
  207. }
  208. if (fShowCommandLines) {
  209. AddCommandLines(tlist, numTasks);
  210. }
  211. //
  212. // enumerate all windows and try to get the window
  213. // titles for each task
  214. //
  215. te.tlist = tlist;
  216. te.numtasks = numTasks;
  217. GetWindowTitles( &te );
  218. //
  219. // print the task list
  220. //
  221. if (fTree) {
  222. PrintTaskTree( 0, 0 );
  223. } else if (fFindTasksUsingModule) {
  224. PrintTasksUsingModule(argv[2]);
  225. } else if (fPidOnly) {
  226. GetFirstPidWithName(argv[2]);
  227. } else {
  228. for (i=0; i<numTasks; i++) {
  229. if ((dwPID == BAD_PID) && (!cchPN)) {
  230. PrintTask( i );
  231. }
  232. else
  233. if ((dwPID == tlist[i].dwProcessId) ||
  234. (cchPN && FMatchTaskName(szPN, tlist[i].WindowTitle, tlist[i].ProcessName))) {
  235. PrintTask( i );
  236. PrintThreadInfo(tlist + i);
  237. }
  238. if (tlist[i].pThreadInfo) {
  239. free(tlist[i].pThreadInfo);
  240. }
  241. }
  242. }
  243. //
  244. // end of program
  245. //
  246. return 0;
  247. }
  248. VOID
  249. GetFirstPidWithName(
  250. LPTSTR szTask
  251. )
  252. /*++
  253. Routine Description:
  254. Returns the PID of the first task with a Name matching the specified
  255. Name. IF no task is found -1 is returned
  256. Arguments:
  257. szTask - module name to search for
  258. --*/
  259. {
  260. DWORD i;
  261. TCHAR szPName[PROCESS_SIZE + 1];
  262. TCHAR szNameWExe[PROCESS_SIZE + 1] = {0};
  263. _tcsncat(szNameWExe, szTask, (sizeof(szNameWExe)/sizeof(szNameWExe[0]))-1);
  264. _tcsncat(szNameWExe, ".exe", (sizeof(szNameWExe)/sizeof(szNameWExe[0]))-_tcslen(szNameWExe)-1);
  265. for (i=0; i<numTasks; i++) {
  266. ZeroMemory(szPName, sizeof(szPName));
  267. _tcsncat(szPName, tlist[i].ProcessName, (sizeof(szPName)/sizeof(szPName[0]))-1);
  268. _tcslwr(szPName);
  269. if ((!_tcscmp(szPName, szTask))||(!_tcscmp(szPName, szNameWExe))) {
  270. if (tlist[i].dwProcessId != 0) {
  271. printf("%d\n", tlist[i].dwProcessId);
  272. return;
  273. }
  274. }
  275. }
  276. printf("-1\n");
  277. }
  278. VOID
  279. Usage(
  280. VOID
  281. )
  282. /*++
  283. Routine Description:
  284. Prints usage text for this tool.
  285. Arguments:
  286. None.
  287. Return Value:
  288. None.
  289. --*/
  290. {
  291. fprintf( stderr,
  292. "Microsoft (R) Windows NT (TM) Version 5.1 TLIST\n"
  293. VER_LEGALCOPYRIGHT_STR
  294. "\n\n"
  295. "usage: TLIST"
  296. " <<-m <pattern>> | <-t> | <pid> | <pattern> | <-p <processname>>> | <-k> | <-s>\n"
  297. " [options]:\n"
  298. " -t\n"
  299. " Print Task Tree\n\n"
  300. " <pid>\n"
  301. " List module information for this task.\n\n"
  302. " <pattern>\n"
  303. " The pattern can be a complete task\n"
  304. " name or a regular expression pattern\n"
  305. " to use as a match. Tlist matches the\n"
  306. " supplied pattern against the task names\n"
  307. " and the window titles.\n\n"
  308. " -c\n"
  309. " Show command lines for each process\n\n"
  310. " -e\n"
  311. " Show session IDs for each process\n\n"
  312. " -k\n"
  313. " Show MTS packages active in each process.\n\n"
  314. " -m <pattern>\n"
  315. " Lists all tasks that have DLL modules loaded\n"
  316. " in them that match the given pattern name\n\n"
  317. " -s\n"
  318. " Show services active in each process.\n\n"
  319. " -p <processname>\n"
  320. " Returns the PID of the process specified or -1\n"
  321. " if the specified process doesn't exist. If there\n"
  322. " are multiple instances of the process running only\n"
  323. " the instance with the first PID value is returned.\n\n"
  324. " -v\n"
  325. " Show all process information\n\n"
  326. );
  327. ExitProcess(0);
  328. }
  329. //
  330. // Routines used to list all processes that have a specific module in use
  331. //
  332. BOOL
  333. FindSpecificModuleCallback(
  334. LPSTR Name,
  335. DWORD_PTR Base,
  336. DWORD Size,
  337. PVOID Context
  338. )
  339. /*++
  340. Routine Description:
  341. Callback function for module enumeration to find a specific module
  342. Arguments:
  343. Name - Module name
  344. Base - Base address
  345. Size - Size of image
  346. Context - User context pointer
  347. Return Value:
  348. TRUE - Continue enumeration
  349. FALSE - Stop enumeration
  350. --*/
  351. {
  352. PFIND_MODULE_INFO pFindModuleInfo;
  353. pFindModuleInfo = (PFIND_MODULE_INFO)Context;
  354. if (MatchPattern(Name, pFindModuleInfo->szModuleToFind))
  355. {
  356. pFindModuleInfo->fFound = TRUE;
  357. strcpy(pFindModuleInfo->szMatchingModuleName, Name);
  358. return FALSE; // Found Module so stop enumerating
  359. }
  360. return TRUE;
  361. }
  362. BOOL
  363. IsTaskUsingModule(
  364. PTASK_LIST pTask,
  365. LPTSTR szModuleName,
  366. LPTSTR szMatchingModuleName
  367. )
  368. /*++
  369. Routine Description:
  370. Checks if the given task has the given module loaded
  371. Arguments:
  372. pTaskList - task to search for module
  373. szModule - module name to search for
  374. Return Value:
  375. TRUE - if the module is loaded in the task
  376. FALSE - if the module is not loaded in the task
  377. --*/
  378. {
  379. FIND_MODULE_INFO FindModuleInfo;
  380. FindModuleInfo.fFound = FALSE;
  381. FindModuleInfo.szModuleToFind = szModuleName;
  382. FindModuleInfo.szMatchingModuleName = szMatchingModuleName;
  383. EnumerateLoadedModules(
  384. (HANDLE) UlongToPtr(pTask->dwProcessId),
  385. FindSpecificModuleCallback,
  386. &FindModuleInfo
  387. );
  388. return FindModuleInfo.fFound;
  389. }
  390. void
  391. PrintTasksUsingModule(
  392. LPTSTR szModuleName
  393. )
  394. /*++
  395. Routine Description:
  396. Enumerates through all the tasks in the system looking for those that
  397. have loaded modules of the given name.
  398. Arguments:
  399. szModule - module name to search for
  400. Return Value:
  401. None
  402. --*/
  403. {
  404. BOOL fUsed = FALSE;
  405. DWORD i;
  406. CHAR szMatchingModuleName[64];
  407. _strupr(szModuleName); // Needed for wildcarding
  408. for (i=0; i<numTasks; i++) {
  409. if (IsTaskUsingModule(tlist + i, szModuleName, szMatchingModuleName)) {
  410. printf("%s - ", szMatchingModuleName);
  411. PrintTask( i );
  412. fUsed = TRUE;
  413. }
  414. }
  415. if (!fUsed) {
  416. printf( "No tasks found using %s\n", szModuleName );
  417. }
  418. }
  419. BOOL
  420. GetVersionStuff(
  421. LPTSTR szFileName,
  422. VS_FIXEDFILEINFO *pvsRet
  423. )
  424. /*++
  425. Routine Description:
  426. Get fixedfileinfo for szFileName.
  427. Arguments:
  428. szFileName - name of file
  429. pvsRet - fixedfileinfo return struct
  430. Return Value:
  431. TRUE - success
  432. FALSE - failure
  433. --*/
  434. {
  435. DWORD dwHandle;
  436. DWORD dwLength;
  437. BOOL fRet = FALSE;
  438. LPVOID lpvData = NULL;
  439. if (!(dwLength = GetFileVersionInfoSize(szFileName, &dwHandle))) {
  440. goto err;
  441. }
  442. if (lpvData = malloc(dwLength)) {
  443. if (GetFileVersionInfo(szFileName, 0, dwLength, lpvData)) {
  444. UINT uLen;
  445. VS_FIXEDFILEINFO *pvs;
  446. DWORD *pdwTranslation;
  447. DWORD dwDefLang = 0x409;
  448. if (!VerQueryValue(lpvData, "\\VarFileInfo\\Translation",
  449. &pdwTranslation, &uLen)) {
  450. // if we can't get the langid, default to usa
  451. pdwTranslation = &dwDefLang;
  452. uLen = sizeof(DWORD);
  453. }
  454. if (VerQueryValue(lpvData, "\\", (LPVOID *)&pvs, &uLen)) {
  455. *pvsRet = *pvs;
  456. fRet = TRUE;
  457. }
  458. }
  459. }
  460. err:
  461. if (lpvData)
  462. free(lpvData);
  463. return fRet;
  464. }
  465. BOOL
  466. EnumLoadedModulesCallback(
  467. LPSTR Name,
  468. DWORD_PTR Base,
  469. DWORD Size,
  470. PVOID Context
  471. )
  472. /*++
  473. Routine Description:
  474. Callback function for module enumeration
  475. Arguments:
  476. Name - Module name
  477. Base - Base address
  478. Size - Size of image
  479. Context - User context pointer
  480. Return Value:
  481. TRUE - Continue enumeration
  482. FALSE - Stop enumeration
  483. --*/
  484. {
  485. VS_FIXEDFILEINFO vs;
  486. CHAR szBuffer[100];
  487. szBuffer[0] = 0;
  488. if (GetVersionStuff( Name, &vs )) {
  489. sprintf( szBuffer, "%u.%u.%u.%u %s",
  490. HIWORD(vs.dwFileVersionMS),
  491. LOWORD(vs.dwFileVersionMS),
  492. HIWORD(vs.dwFileVersionLS),
  493. LOWORD(vs.dwFileVersionLS),
  494. vs.dwFileFlags & VS_FF_DEBUG ? "dbg" : "shp"
  495. );
  496. }
  497. printf( " %18.18s 0x%p %s\n", szBuffer, (void *)Base, Name );
  498. return TRUE;
  499. }
  500. BOOL
  501. PrintModuleList(
  502. ULONG ProcessId
  503. )
  504. /*++
  505. Routine Description:
  506. Prints list of modules in ProcessId
  507. Arguments:
  508. ProcessID - process id
  509. Return Value:
  510. TRUE - success
  511. FALSE - failure
  512. --*/
  513. {
  514. EnumerateLoadedModules(
  515. (HANDLE) UlongToPtr(ProcessId),
  516. EnumLoadedModulesCallback,
  517. NULL
  518. );
  519. return TRUE;
  520. }
  521. DWORD
  522. GetWin32StartAddress(
  523. HANDLE hThread
  524. )
  525. /*++
  526. Routine Description:
  527. Get starting address for thread
  528. Arguments:
  529. hThread
  530. Return Value:
  531. Starting Thread address or 0
  532. --*/
  533. {
  534. NTSTATUS Status;
  535. DWORD ThreadInformation;
  536. // make sure we have a handle
  537. if (!hThread)
  538. return 0;
  539. // get the threadinfo
  540. Status = NtQueryInformationThread(hThread, ThreadQuerySetWin32StartAddress,
  541. &ThreadInformation, sizeof(ThreadInformation), NULL);
  542. if (!NT_SUCCESS(Status))
  543. return 0;
  544. return ThreadInformation;
  545. }
  546. ULONG
  547. GetLastThreadErr(
  548. HANDLE hThread
  549. )
  550. /*++
  551. Routine Description:
  552. Get Last Error for a Thread
  553. Arguments:
  554. hThread
  555. Return Value:
  556. LastError or 0
  557. --*/
  558. {
  559. TEB Teb;
  560. NTSTATUS Status;
  561. HANDLE hProcess;
  562. ULONG LastErrorValue;
  563. THREAD_BASIC_INFORMATION ThreadInformation;
  564. // make sure we have a handle
  565. if (!hThread)
  566. return 0;
  567. // query for basic thread info
  568. Status = NtQueryInformationThread(hThread, ThreadBasicInformation,
  569. &ThreadInformation, sizeof(ThreadInformation), NULL);
  570. if (!NT_SUCCESS(Status))
  571. return 0;
  572. // get handle to process
  573. if (!(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE,
  574. (DWORD)(DWORD_PTR)ThreadInformation.ClientId.UniqueProcess))) {
  575. return 0;
  576. }
  577. __try {
  578. // read the TEB from the process and get the last error value
  579. if (ReadProcessMemory(hProcess,
  580. ThreadInformation.TebBaseAddress, &Teb, sizeof(TEB), NULL)) {
  581. LastErrorValue = Teb.LastErrorValue;
  582. }
  583. }
  584. __except(EXCEPTION_EXECUTE_HANDLER) {
  585. }
  586. // close the hProcess
  587. CloseHandle(hProcess);
  588. return LastErrorValue;
  589. }
  590. BOOL
  591. FPrintPEBInfo(
  592. HANDLE hProcess
  593. )
  594. /*++
  595. Routine Description:
  596. Prints cmdline and cwd of hProcess
  597. Arguments:
  598. hProcess.
  599. Return Value:
  600. TRUE - success
  601. FALSE - failure
  602. --*/
  603. {
  604. PEB Peb;
  605. NTSTATUS Status;
  606. PROCESS_BASIC_INFORMATION BasicInfo;
  607. BOOL fRet = FALSE;
  608. WCHAR szT[MAX_PATH * 2];
  609. RTL_USER_PROCESS_PARAMETERS ProcessParameters;
  610. Status = NtQueryInformationProcess(hProcess, ProcessBasicInformation,
  611. &BasicInfo, sizeof(BasicInfo), NULL);
  612. if (!NT_SUCCESS(Status)) {
  613. SetLastError(RtlNtStatusToDosError(Status));
  614. return fRet;
  615. }
  616. __try {
  617. // get the PEB
  618. if (ReadProcessMemory(hProcess, BasicInfo.PebBaseAddress, &Peb,
  619. sizeof(PEB), NULL)) {
  620. // get the processparameters
  621. if (ReadProcessMemory(hProcess, Peb.ProcessParameters,
  622. &ProcessParameters, sizeof(ProcessParameters), NULL)) {
  623. // get the CWD
  624. if (ReadProcessMemory(hProcess,
  625. ProcessParameters.CurrentDirectory.DosPath.Buffer, szT,
  626. sizeof(szT), NULL)) {
  627. wprintf(L" CWD: %s\n", szT);
  628. }
  629. // get cmdline
  630. if (ReadProcessMemory(hProcess, ProcessParameters.CommandLine.Buffer,
  631. szT, sizeof(szT), NULL)) {
  632. wprintf(L" CmdLine: %s\n", szT);
  633. }
  634. fRet = TRUE;
  635. }
  636. }
  637. }
  638. __except(EXCEPTION_EXECUTE_HANDLER) {
  639. }
  640. return fRet;
  641. }
  642. // copied from the win32 API code since we need to run on NT 4 and this is a
  643. // new API to NT 5
  644. HANDLE
  645. TlistOpenThread(
  646. DWORD dwDesiredAccess,
  647. BOOL bInheritHandle,
  648. DWORD dwThreadId
  649. )
  650. /*++
  651. Routine Description:
  652. A handle to a thread object may be created using OpenThread.
  653. Opening a thread creates a handle to the specified thread.
  654. Associated with the thread handle is a set of access rights that
  655. may be performed using the thread handle. The caller specifies the
  656. desired access to the thread using the DesiredAccess parameter.
  657. Arguments:
  658. mDesiredAccess - Supplies the desired access to the thread object.
  659. For NT/Win32, this access is checked against any security
  660. descriptor on the target thread. The following object type
  661. specific access flags can be specified in addition to the
  662. STANDARD_RIGHTS_REQUIRED access flags.
  663. DesiredAccess Flags:
  664. THREAD_TERMINATE - This access is required to terminate the
  665. thread using TerminateThread.
  666. THREAD_SUSPEND_RESUME - This access is required to suspend and
  667. resume the thread using SuspendThread and ResumeThread.
  668. THREAD_GET_CONTEXT - This access is required to use the
  669. GetThreadContext API on a thread object.
  670. THREAD_SET_CONTEXT - This access is required to use the
  671. SetThreadContext API on a thread object.
  672. THREAD_SET_INFORMATION - This access is required to set certain
  673. information in the thread object.
  674. THREAD_SET_THREAD_TOKEN - This access is required to set the
  675. thread token using SetTokenInformation.
  676. THREAD_QUERY_INFORMATION - This access is required to read
  677. certain information from the thread object.
  678. SYNCHRONIZE - This access is required to wait on a thread object.
  679. THREAD_ALL_ACCESS - This set of access flags specifies all of the
  680. possible access flags for a thread object.
  681. bInheritHandle - Supplies a flag that indicates whether or not the
  682. returned handle is to be inherited by a new process during
  683. process creation. A value of TRUE indicates that the new
  684. process will inherit the handle.
  685. dwThreadId - Supplies the thread id of the thread to open.
  686. Return Value:
  687. NON-NULL - Returns an open handle to the specified thread. The
  688. handle may be used by the calling process in any API that
  689. requires a handle to a thread. If the open is successful, the
  690. handle is granted access to the thread object only to the
  691. extent that it requested access through the DesiredAccess
  692. parameter.
  693. NULL - The operation failed. Extended error status is available
  694. using GetLastError.
  695. --*/
  696. {
  697. NTSTATUS Status;
  698. OBJECT_ATTRIBUTES Obja;
  699. HANDLE Handle;
  700. CLIENT_ID ClientId;
  701. ClientId.UniqueThread = (HANDLE)LongToHandle(dwThreadId);
  702. ClientId.UniqueProcess = (HANDLE)NULL;
  703. InitializeObjectAttributes(
  704. &Obja,
  705. NULL,
  706. (bInheritHandle ? OBJ_INHERIT : 0),
  707. NULL,
  708. NULL
  709. );
  710. Status = NtOpenThread(
  711. &Handle,
  712. (ACCESS_MASK)dwDesiredAccess,
  713. &Obja,
  714. &ClientId
  715. );
  716. if ( NT_SUCCESS(Status) ) {
  717. return Handle;
  718. }
  719. else {
  720. return NULL;
  721. }
  722. }
  723. VOID
  724. PrintThreadInfo(
  725. PTASK_LIST pTaskList
  726. )
  727. /*++
  728. Routine Description:
  729. Prints all kinds of info about a task
  730. Arguments:
  731. PTASK_LIST of task to print
  732. Return Value:
  733. None.
  734. --*/
  735. {
  736. UINT nThread;
  737. HANDLE hProcess;
  738. // from \\kernel\razzle2\src\ntos\inc\ke.h
  739. #define MAX_THREADSTATE (sizeof(szThreadState) / sizeof(TCHAR *))
  740. static const TCHAR *szThreadState[] = {
  741. "Initialized",
  742. "Ready ",
  743. "Running ",
  744. "Standby ",
  745. "Terminated",
  746. "Waiting ",
  747. "Transition",
  748. "??? " };
  749. // get a handle to the process
  750. hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pTaskList->dwProcessId);
  751. if (!hProcess)
  752. return;
  753. // print the CWD and CmdLine
  754. FPrintPEBInfo(hProcess);
  755. printf( " VirtualSize: %6ld KB"
  756. " PeakVirtualSize: %6ld KB\n",
  757. pTaskList->VirtualSize / 1024,
  758. pTaskList->PeakVirtualSize / 1024);
  759. printf( " WorkingSetSize:%6ld KB"
  760. " PeakWorkingSetSize:%6ld KB\n",
  761. pTaskList->WorkingSetSize / 1024,
  762. pTaskList->PeakWorkingSetSize / 1024);
  763. printf( " NumberOfThreads: %ld\n",
  764. pTaskList->NumberOfThreads);
  765. // if we got any threadinfo, spit it out
  766. if (pTaskList->pThreadInfo) {
  767. for (nThread = 0; nThread < pTaskList->NumberOfThreads; nThread++) {
  768. PTHREAD_INFO pThreadInfo = &pTaskList->pThreadInfo[nThread];
  769. HANDLE hThread = TlistOpenThread(THREAD_QUERY_INFORMATION, FALSE,
  770. (DWORD)(DWORD_PTR)pThreadInfo->UniqueThread);
  771. printf(" %4d Win32StartAddr:0x%08x LastErr:0x%08x State:%s\n",
  772. HandleToUlong(pThreadInfo->UniqueThread),
  773. GetWin32StartAddress(hThread),
  774. GetLastThreadErr(hThread),
  775. szThreadState[min(pThreadInfo->ThreadState, MAX_THREADSTATE - 1)]);
  776. if (hThread)
  777. NtClose(hThread);
  778. }
  779. }
  780. // print the modules
  781. PrintModuleList( pTaskList->dwProcessId );
  782. // close the hProcess
  783. CloseHandle(hProcess);
  784. }
  785. BOOL
  786. FMatchTaskName(
  787. LPTSTR szPN,
  788. LPTSTR szWindowTitle,
  789. LPTSTR szProcessName
  790. )
  791. {
  792. LPTSTR szT;
  793. TCHAR szTName[PROCESS_SIZE]= {0};
  794. _tcsncat( szTName, szProcessName, (sizeof(szTName)/sizeof(szTName[0]))-1 );
  795. if (szT = _tcschr( szTName, _T('.') ))
  796. szT[0] = _T('\0');
  797. if (MatchPattern( szTName, szPN ) ||
  798. MatchPattern( szProcessName, szPN ) ||
  799. MatchPattern( szWindowTitle, szPN )) {
  800. return TRUE;
  801. }
  802. return FALSE;
  803. }