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.

869 lines
23 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. token.cxx
  5. Abstract:
  6. Lsaexts debugger extension
  7. Author:
  8. Larry Zhu (LZhu) May 1, 2001
  9. Environment:
  10. User Mode
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. #include "token.h"
  16. //#include "util.h"
  17. //#include "sid.h"
  18. //
  19. // Flags used to control level of info
  20. //
  21. #define SHOW_FRIENDLY_NAME 0x001
  22. #define SHOW_VERBOSE_INFO 0x002
  23. #define SHOW_SINGLE_ENTRY 0x004
  24. #define SHOW_SUMMARY_ONLLY 0x008
  25. #define DECODE_SEC_BUF_DEC 0x010
  26. #define SHOW_NTLM 0x020
  27. #define SHOW_KERB 0x040
  28. #define SHOW_SPNEGO 0x080
  29. #define SHOW_LSAP 0x100
  30. #define TOKEN_LOG 1
  31. static PCSTR ImpLevels[] = {"Anonymous", "Identification", "Impersonation", "Delegation"};
  32. #define ImpLevel(x) ((x < (sizeof(ImpLevels) / sizeof(CHAR *))) ? ImpLevels[x] : "Illegal!")
  33. static void DisplayTokenUsage(void)
  34. {
  35. dprintf("Usage:\n");
  36. dprintf(" !token [-n] <address> Dump token by TOKEN address (Kernel mode)\n");
  37. dprintf(" !token [-n] <handle> Dump token by handle (User mode)\n");
  38. dprintf(" !token [-n] Dump token of active thread\n");
  39. dprintf("Options:\n");
  40. dprintf(" -? Display this message\n");
  41. dprintf(" -n Lookup Sid friendly name on host\n\n");
  42. }
  43. TCHAR* GetPrivName(IN LUID* pPriv)
  44. {
  45. switch (pPriv->LowPart)
  46. {
  47. case SE_CREATE_TOKEN_PRIVILEGE:
  48. return(SE_CREATE_TOKEN_NAME);
  49. case SE_ASSIGNPRIMARYTOKEN_PRIVILEGE:
  50. return(SE_ASSIGNPRIMARYTOKEN_NAME);
  51. case SE_LOCK_MEMORY_PRIVILEGE:
  52. return(SE_LOCK_MEMORY_NAME);
  53. case SE_INCREASE_QUOTA_PRIVILEGE:
  54. return(SE_INCREASE_QUOTA_NAME);
  55. case SE_UNSOLICITED_INPUT_PRIVILEGE:
  56. return(SE_UNSOLICITED_INPUT_NAME);
  57. case SE_TCB_PRIVILEGE:
  58. return(SE_TCB_NAME);
  59. case SE_SECURITY_PRIVILEGE:
  60. return(SE_SECURITY_NAME);
  61. case SE_TAKE_OWNERSHIP_PRIVILEGE:
  62. return(SE_TAKE_OWNERSHIP_NAME);
  63. case SE_LOAD_DRIVER_PRIVILEGE:
  64. return(SE_LOAD_DRIVER_NAME);
  65. case SE_SYSTEM_PROFILE_PRIVILEGE:
  66. return(SE_SYSTEM_PROFILE_NAME);
  67. case SE_SYSTEMTIME_PRIVILEGE:
  68. return(SE_SYSTEMTIME_NAME);
  69. case SE_PROF_SINGLE_PROCESS_PRIVILEGE:
  70. return(SE_PROF_SINGLE_PROCESS_NAME);
  71. case SE_INC_BASE_PRIORITY_PRIVILEGE:
  72. return(SE_INC_BASE_PRIORITY_NAME);
  73. case SE_CREATE_PAGEFILE_PRIVILEGE:
  74. return(SE_CREATE_PAGEFILE_NAME);
  75. case SE_CREATE_PERMANENT_PRIVILEGE:
  76. return(SE_CREATE_PERMANENT_NAME);
  77. case SE_BACKUP_PRIVILEGE:
  78. return(SE_BACKUP_NAME);
  79. case SE_RESTORE_PRIVILEGE:
  80. return(SE_RESTORE_NAME);
  81. case SE_SHUTDOWN_PRIVILEGE:
  82. return(SE_SHUTDOWN_NAME);
  83. case SE_DEBUG_PRIVILEGE:
  84. return(SE_DEBUG_NAME);
  85. case SE_AUDIT_PRIVILEGE:
  86. return(SE_AUDIT_NAME);
  87. case SE_SYSTEM_ENVIRONMENT_PRIVILEGE:
  88. return(SE_SYSTEM_ENVIRONMENT_NAME);
  89. case SE_CHANGE_NOTIFY_PRIVILEGE:
  90. return(SE_CHANGE_NOTIFY_NAME);
  91. case SE_REMOTE_SHUTDOWN_PRIVILEGE:
  92. return(SE_REMOTE_SHUTDOWN_NAME);
  93. case SE_UNDOCK_PRIVILEGE:
  94. return(SE_UNDOCK_NAME);
  95. case SE_SYNC_AGENT_PRIVILEGE:
  96. return(SE_SYNC_AGENT_NAME);
  97. case SE_ENABLE_DELEGATION_PRIVILEGE:
  98. return(SE_ENABLE_DELEGATION_NAME);
  99. case SE_MANAGE_VOLUME_PRIVILEGE:
  100. return(SE_MANAGE_VOLUME_NAME);
  101. default:
  102. return("Unknown Privilege");
  103. }
  104. }
  105. HRESULT LocalDumpSid(IN PCSTR pszPad, PSID pxSid, IN ULONG fOptions)
  106. {
  107. UNICODE_STRING ucsSid = {0};
  108. NTSTATUS NtStatus = STATUS_UNSUCCESSFUL;
  109. PCSTR FriendlyName;
  110. NtStatus = RtlConvertSidToUnicodeString(&ucsSid, pxSid, TRUE);
  111. if (NT_SUCCESS(NtStatus))
  112. {
  113. dprintf("%s", pszPad);
  114. dprintf("%wZ", &ucsSid);
  115. }
  116. else
  117. {
  118. dprintf("LocadDumpSid failed to dump Sid at addr %p\n", pxSid);
  119. }
  120. RtlFreeUnicodeString(&ucsSid);
  121. if (fOptions & SHOW_FRIENDLY_NAME)
  122. {
  123. dprintf(" ");
  124. FriendlyName = ConvertSidToFriendlyName(pxSid, "(%s: %s\\%s)");
  125. if (!FriendlyName)
  126. {
  127. return E_FAIL;
  128. }
  129. dprintf(FriendlyName);
  130. }
  131. dprintf("\n");
  132. return S_OK;
  133. }
  134. void DumpAttr(IN PCSTR pszPad, IN ULONG attributes, IN ULONG SAType)
  135. {
  136. if (SAType == SATYPE_GROUP)
  137. {
  138. dprintf("%sAttributes - ", pszPad);
  139. if (attributes & SE_GROUP_MANDATORY)
  140. {
  141. attributes &= ~SE_GROUP_MANDATORY;
  142. dprintf("Mandatory ");
  143. }
  144. if (attributes & SE_GROUP_ENABLED_BY_DEFAULT)
  145. {
  146. attributes &= ~SE_GROUP_ENABLED_BY_DEFAULT;
  147. dprintf("Default ");
  148. }
  149. if (attributes & SE_GROUP_ENABLED)
  150. {
  151. attributes &= ~SE_GROUP_ENABLED;
  152. dprintf("Enabled ");
  153. }
  154. if (attributes & SE_GROUP_OWNER)
  155. {
  156. attributes &= ~SE_GROUP_OWNER;
  157. dprintf("Owner ");
  158. }
  159. if (attributes & SE_GROUP_LOGON_ID)
  160. {
  161. attributes &= ~SE_GROUP_LOGON_ID;
  162. dprintf("LogonId ");
  163. }
  164. if (attributes & SE_GROUP_USE_FOR_DENY_ONLY)
  165. {
  166. attributes &= ~SE_GROUP_USE_FOR_DENY_ONLY;
  167. dprintf("DenyOnly ");
  168. }
  169. if (attributes & SE_GROUP_RESOURCE)
  170. {
  171. attributes &= ~SE_GROUP_RESOURCE;
  172. dprintf("GroupResource ");
  173. }
  174. if (attributes)
  175. {
  176. dprintf("%#x ", attributes);
  177. }
  178. }
  179. }
  180. void DumpLocalSidAttr(IN PSID_AND_ATTRIBUTES pSA, IN ULONG SAType, IN ULONG fOptions)
  181. {
  182. LocalDumpSid("", pSA->Sid, fOptions);
  183. DumpAttr(" ", pSA->Attributes, SAType);
  184. }
  185. void DumpSidAttr(IN ULONG64 addrSid, IN ULONG attributes, IN ULONG SAType, IN ULONG fOptions)
  186. {
  187. ShowSid("", addrSid, fOptions);
  188. DumpAttr(" ", attributes, SAType);
  189. }
  190. void DumpLuidAttr(PLUID_AND_ATTRIBUTES pLA, ULONG LAType)
  191. {
  192. dprintf("0x%x%08x", pLA->Luid.HighPart, pLA->Luid.LowPart);
  193. dprintf(" %-32s", GetPrivName(&pLA->Luid));
  194. if (LAType == SATYPE_PRIV)
  195. {
  196. dprintf(" Attributes - ");
  197. if (pLA->Attributes & SE_PRIVILEGE_ENABLED)
  198. {
  199. dprintf("Enabled ");
  200. }
  201. if (pLA->Attributes & SE_PRIVILEGE_ENABLED_BY_DEFAULT)
  202. {
  203. dprintf("Default ");
  204. }
  205. }
  206. }
  207. void PrintToken(IN HANDLE hToken, IN ULONG fOptions)
  208. {
  209. TOKEN_USER* pTUser = NULL;
  210. TOKEN_GROUPS* pTGroups = NULL;
  211. TOKEN_PRIVILEGES* pTPrivs = NULL;
  212. TOKEN_PRIMARY_GROUP* pTPrimaryGroup = NULL;
  213. TOKEN_STATISTICS TStats = {0};
  214. ULONG cbRetInfo = 0;
  215. NTSTATUS status = STATUS_UNSUCCESSFUL;
  216. DWORD i = 0;
  217. DWORD dwSessionId = 0;
  218. CHAR bufferUser[256];
  219. CHAR bufferGroups[4096];
  220. CHAR bufferPriv[1024];
  221. CHAR bufferPriGrp[128];
  222. pTUser = (TOKEN_USER*) &bufferUser[0];
  223. pTGroups = (TOKEN_GROUPS*) &bufferGroups[0];
  224. pTPrivs = (TOKEN_PRIVILEGES*) &bufferPriv[0];
  225. pTPrimaryGroup = (TOKEN_PRIMARY_GROUP*) &bufferPriGrp[0];
  226. status = NtQueryInformationToken(hToken, TokenSessionId, &dwSessionId, sizeof(dwSessionId), &cbRetInfo);
  227. if (!NT_SUCCESS(status))
  228. {
  229. dprintf("Failed to query token: %#x\n", status);
  230. return;
  231. }
  232. dprintf("TS Session ID: %#x\n", dwSessionId);
  233. status = NtQueryInformationToken(hToken, TokenUser, pTUser, 256, &cbRetInfo);
  234. if (!NT_SUCCESS(status))
  235. {
  236. dprintf("Failed to query token: %#x\n", status);
  237. return;
  238. }
  239. dprintf("User: ");
  240. DumpLocalSidAttr(&pTUser->User, SATYPE_USER, fOptions);
  241. dprintf("Groups: ");
  242. status = NtQueryInformationToken(hToken, TokenGroups, pTGroups, 4096, &cbRetInfo);
  243. for (i = 0; i < pTGroups->GroupCount; i++)
  244. {
  245. dprintf("\n %02d ", i);
  246. DumpLocalSidAttr(&pTGroups->Groups[i], SATYPE_GROUP, fOptions);
  247. if (CheckControlC())
  248. {
  249. return;
  250. }
  251. }
  252. status = NtQueryInformationToken(hToken, TokenPrimaryGroup, pTPrimaryGroup, 128, &cbRetInfo);
  253. dprintf("\n");
  254. dprintf("Primary Group: ");
  255. LocalDumpSid("", pTPrimaryGroup->PrimaryGroup, fOptions);
  256. dprintf("Privs: ");
  257. status = NtQueryInformationToken(hToken, TokenPrivileges, pTPrivs, 1024, &cbRetInfo);
  258. if (!NT_SUCCESS(status))
  259. {
  260. printf("NtQueryInformationToken returned %#x\n", status);
  261. return;
  262. }
  263. for (i = 0; i < pTPrivs->PrivilegeCount; i++)
  264. {
  265. dprintf("\n %02d ", i);
  266. DumpLuidAttr(&pTPrivs->Privileges[i], SATYPE_PRIV);
  267. if (CheckControlC())
  268. {
  269. return;
  270. }
  271. }
  272. status = NtQueryInformationToken(hToken, TokenStatistics, &TStats, sizeof(TStats), &cbRetInfo);
  273. dprintf("\nAuth ID: %x:%x\n", TStats.AuthenticationId.HighPart, TStats.AuthenticationId.LowPart);
  274. dprintf("Impersonation Level: %s\n", ImpLevel(TStats.ImpersonationLevel));
  275. dprintf("TokenType: %s\n", TStats.TokenType == TokenPrimary ? "Primary" : "Impersonation");
  276. }
  277. HRESULT LiveSessionToken(IN HANDLE hThread, IN HANDLE hRemoteToken, IN ULONG fOptions)
  278. {
  279. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  280. HANDLE hProcess = NULL;
  281. HANDLE hToken = NULL;
  282. GetCurrentProcessHandle(&hProcess);
  283. Status = hProcess ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
  284. if (NT_SUCCESS(Status))
  285. {
  286. if (hRemoteToken == NULL)
  287. {
  288. Status = NtOpenThreadToken(hThread, TOKEN_QUERY, FALSE, &hToken);
  289. if ((Status == STATUS_NO_TOKEN) || (hToken == NULL))
  290. {
  291. dprintf("Thread is not impersonating. Using process token...\n");
  292. Status = NtOpenProcessToken(hProcess, TOKEN_QUERY, &hToken);
  293. }
  294. }
  295. else
  296. {
  297. Status = DuplicateHandle(hProcess, hRemoteToken,
  298. GetCurrentProcess(), &hToken, 0, FALSE,
  299. DUPLICATE_SAME_ACCESS) ? STATUS_SUCCESS : GetLastError() + 0x80000000;
  300. }
  301. }
  302. if (NT_SUCCESS(Status))
  303. {
  304. DBG_LOG(TOKEN_LOG, ("token %p, remote token %p\n", hToken, hRemoteToken));
  305. PrintToken(hToken, fOptions);
  306. CloseHandle(hToken);
  307. }
  308. else
  309. {
  310. dprintf("Error %#x getting thread token\n", Status);
  311. }
  312. return NT_SUCCESS(Status) ? S_OK : E_FAIL;
  313. }
  314. void DisplayPrivilegs(IN ULONG64 privAddr, IN ULONG cPriv)
  315. {
  316. UCHAR buffer[1024] = {0};
  317. LUID_AND_ATTRIBUTES* pPrivileges = (LUID_AND_ATTRIBUTES*) buffer;
  318. ULONG ret;
  319. ULONG i;
  320. if ((cPriv * sizeof(LUID_AND_ATTRIBUTES)) > sizeof(buffer))
  321. {
  322. dprintf("Invalid privilege count %#lx - too large.\n", cPriv);
  323. return;
  324. }
  325. if (!ReadMemory(privAddr, pPrivileges, cPriv * sizeof(LUID_AND_ATTRIBUTES), &ret) ||
  326. (ret != cPriv * sizeof(LUID_AND_ATTRIBUTES)))
  327. {
  328. dprintf("Unable to read DisplayPrivilegs @ %p\n", privAddr);
  329. return;
  330. }
  331. for (i = 0; i < cPriv ; i++)
  332. {
  333. dprintf("\n %02d ", i);
  334. DumpLuidAttr(pPrivileges + i, SATYPE_PRIV);
  335. if (CheckControlC())
  336. {
  337. break;
  338. }
  339. }
  340. }
  341. void DisplayGroups(IN ULONG64 addrGroups, IN ULONG cGroup, IN ULONG cbSA, IN ULONG fOptions)
  342. {
  343. ULONG i;
  344. ULONG64 sa;
  345. for (i = 0; i < cGroup; i++)
  346. {
  347. dprintf("\n %02d ", i);
  348. sa = addrGroups + i * cbSA;
  349. DumpSidAttr(GetSidAddr(sa), GetSidAttributes(sa), SATYPE_GROUP, fOptions);
  350. if (CheckControlC())
  351. {
  352. break;
  353. }
  354. }
  355. }
  356. //
  357. // kd dump token
  358. //
  359. BOOL
  360. DumpKdToken (
  361. IN char *Pad,
  362. IN ULONG64 RealTokenBase,
  363. IN ULONG Flags
  364. )
  365. {
  366. ULONG TokenType, TokenFlags, TokenInUse, UserAndGroupCount;
  367. ULONG RestrictedSidCount, PrivilegeCount;
  368. ULONG64 AuthenticationId, TokenId, ParentTokenId, ModifiedId, UserAndGroups;
  369. ULONG64 RestrictedSids, Privileges, ImpersonationLevel;
  370. CHAR SourceName[16];
  371. #define TokFld(F) GetFieldValue(RealTokenBase, "TOKEN", #F, F)
  372. #define TokSubFld(F,N) GetFieldValue(RealTokenBase, "TOKEN", #F, N)
  373. if (TokFld(TokenType)) {
  374. dprintf("%sUnable to read TOKEN at %p.\n", Pad, RealTokenBase);
  375. return FALSE;
  376. }
  377. if (TokenType != TokenPrimary &&
  378. TokenType != TokenImpersonation) {
  379. dprintf("%sUNKNOWN token type - probably is not a token\n", Pad);
  380. return FALSE;
  381. }
  382. TokSubFld(TokenSource.SourceName, SourceName);
  383. TokFld(TokenFlags); TokFld(AuthenticationId);
  384. TokFld(TokenInUse);
  385. TokFld(ImpersonationLevel); TokFld(TokenId), TokFld(ParentTokenId);
  386. TokFld(ModifiedId); TokFld(RestrictedSids); TokFld(RestrictedSidCount);
  387. TokFld(PrivilegeCount); TokFld(Privileges); TokFld(UserAndGroupCount);
  388. TokFld(UserAndGroups);
  389. dprintf("%sSource: %-18s TokenFlags: 0x%x ",
  390. Pad, &(SourceName[0]), TokenFlags);
  391. //
  392. // Token type
  393. //
  394. if (TokenType == TokenPrimary) {
  395. if (TokenInUse) {
  396. dprintf("( Token in use )\n");
  397. } else {
  398. dprintf("( Token NOT in use ) \n");
  399. }
  400. } else
  401. {
  402. dprintf("\n");
  403. }
  404. //
  405. // Token ID and modified ID
  406. //
  407. dprintf("%sToken ID: %-16I64lx ParentToken ID: %I64lx\n", Pad, TokenId, ParentTokenId );
  408. dprintf("%sModified ID: (%lx, %lx)\n",
  409. Pad, (ULONG) (ModifiedId >> 32) & 0xffffffff, (ULONG) (ModifiedId & 0xffffffff));
  410. dprintf("%sRestrictedSidCount: %-6d RestrictedSids: %p\n", Pad, RestrictedSidCount, RestrictedSids );
  411. #undef TokFld
  412. #undef TokSubFld
  413. return TRUE;
  414. //
  415. // Intentionally left out as detailed info has already been displayed before and
  416. // dt _TOKEN displays these
  417. //
  418. dprintf("%sSidCount: %-16d Sids: %p\n", Pad, UserAndGroupCount, UserAndGroups );
  419. dprintf("%sPrivilegeCount: %-10d Privileges: %p\n", Pad, PrivilegeCount, Privileges );
  420. }
  421. void DisplayToken(ULONG64 addrToken, IN ULONG fOptions)
  422. {
  423. ULONG cGroup = 0;
  424. ULONG cbSA = 0;
  425. ULONG64 addrGroups = 0;
  426. ULONG ret;
  427. ULONG64 tsa;
  428. if (ret = (ULONG) InitTypeRead(addrToken, nt!_TOKEN))
  429. {
  430. dprintf("InitTypeRead(%p, nt!_TOKEN) failed - %lx\n", addrToken, ret);
  431. return;
  432. }
  433. dprintf("TS Session ID: %#x\n", (ULONG) ReadField(SessionId));
  434. dprintf("User: "); // nt!_TOKEN
  435. tsa = ReadField(UserAndGroups); // TSID_AND_ATTRIBUTES tsa(LsaReadPtrField(UserAndGroups));
  436. DumpSidAttr(GetSidAddr(tsa), GetSidAttributes(tsa), SATYPE_USER, fOptions);
  437. dprintf("Groups: ");
  438. cGroup = (ULONG) ReadField(UserAndGroupCount);
  439. addrGroups = ReadField(UserAndGroups);
  440. // ReadTypeSize("nt!_SID_AND_ATTRIBUTES[1]") - ReadTypeSize("nt!_SID_AND_ATTRIBUTES[2]");
  441. cbSA = GetTypeSize("nt!_SID_AND_ATTRIBUTES");
  442. //
  443. // stolen from NtQueryInformationToken because the first sid is the user itself
  444. //
  445. addrGroups += cbSA;
  446. cGroup -= 1;
  447. DisplayGroups(addrGroups, cGroup, cbSA, fOptions);
  448. dprintf("\n");
  449. dprintf("Primary Group: ");
  450. ShowSid("", ReadField(PrimaryGroup), fOptions);
  451. dprintf("Privs: ");
  452. DisplayPrivilegs(ReadField(Privileges), (ULONG) ReadField(PrivilegeCount));
  453. dprintf("\nAuthentication ID: (%x,%x)\n", (ULONG) ReadField(AuthenticationId.HighPart), (ULONG) ReadField(AuthenticationId.LowPart));
  454. dprintf("Impersonation Level: %s\n", ImpLevel((ULONG) ReadField(ImpersonationLevel)));
  455. dprintf("TokenType: %s\n", ((ULONG) ReadField(TokenType)) == TokenPrimary ? "Primary" : "Impersonation");
  456. DumpKdToken("", addrToken, 0);
  457. }
  458. #if 0
  459. //
  460. // This is the logic to determine impersonation info in !thread
  461. //
  462. if (ActiveImpersonationInfo)
  463. {
  464. InitTypeRead(ImpersonationInfo, nt!_PS_IMPERSONATION_INFORMATION);
  465. ImpersonationInfo_Token = ReadField(Token);
  466. ImpersonationInfo_ImpersonationLevel = ReadField(ImpersonationLevel);
  467. if (ImpersonationInfo_Token)
  468. {
  469. dprintf("%sImpersonation token: %p (Level %s)\n",
  470. pszPad, ImpersonationInfo_Token,
  471. SecImpLevels( ImpersonationInfo_ImpersonationLevel ) );
  472. }
  473. else
  474. {
  475. dprintf("%sUnable to read Impersonation Information at %x\n",
  476. pszPad, ImpersonationInfo );
  477. }
  478. }
  479. else
  480. {
  481. dprintf("%sNot impersonating\n", pszPad);
  482. }
  483. #endif
  484. HRESULT DumpSessionToken(IN ULONG dwProcessor, IN ULONG64 addrToken, IN ULONG fOptions)
  485. {
  486. HRESULT hRetval = S_OK;
  487. ULONG64 addrThread = 0;
  488. ULONG64 addrProcess = 0;
  489. ULONG ActiveImpersonationInfo = 0;
  490. ULONG64 addrImpersonationInfo = 0;
  491. ULONG64 ret;
  492. //
  493. // If no token addr is input as argument, addrToken is zero
  494. //
  495. if ( ((LONG64)addrToken) > 0 ) // sanity check
  496. {
  497. //
  498. // This can not be a kernel mode access token address
  499. //
  500. dprintf("%#I64x is not a valid KM token address, if this is an access token handle,\n", addrToken);
  501. dprintf("try \"!handle %#I64x\" to get the token address first\n\n", addrToken);
  502. hRetval = E_FAIL;
  503. }
  504. if (SUCCEEDED(hRetval) && !addrToken)
  505. {
  506. addrThread = 0;
  507. GetCurrentThreadAddr(dwProcessor, &addrThread);
  508. hRetval = addrThread ? S_OK : E_FAIL;
  509. if (FAILED(hRetval))
  510. {
  511. dprintf("Unable to read current thread address\n");
  512. }
  513. else
  514. {
  515. //
  516. // ActiveImpersonationInfo is of type C Bit Fields and has a width of 1 (Bitfield Pos 3, 1 Bit)
  517. //
  518. if (ret = InitTypeRead(addrThread, nt!_ETHREAD))
  519. {
  520. dprintf("InitTypeRead(%I64x, nt!_ETHREAD) failed - %lx", addrThread, ret);
  521. return E_FAIL;
  522. }
  523. ActiveImpersonationInfo = (ULONG) ReadField(ActiveImpersonationInfo);
  524. if (ActiveImpersonationInfo)
  525. {
  526. addrImpersonationInfo = ReadField(ImpersonationInfo);
  527. if (!addrImpersonationInfo ||
  528. GetFieldValue(addrImpersonationInfo, "nt!_PS_IMPERSONATION_INFORMATION", "Token", addrToken))
  529. {
  530. dprintf("Cannot read nt!_PS_IMPERSONATION_INFORMATION.Token @ %p\n", addrImpersonationInfo);
  531. }
  532. }
  533. }
  534. //
  535. // If addrToken is NULL, then this is not an impersonation case
  536. //
  537. if (SUCCEEDED(hRetval) && !addrToken)
  538. {
  539. dprintf("Thread is not impersonating. Using process token...\n");
  540. GetCurrentProcessAddr(dwProcessor, addrThread, &addrProcess);
  541. hRetval = addrProcess ? S_OK : E_FAIL;
  542. if (FAILED(hRetval))
  543. {
  544. dprintf("Unable to read current process address\n");
  545. }
  546. else
  547. {
  548. if (GetFieldValue(addrProcess, "nt!_EPROCESS", "Token", addrToken))
  549. {
  550. dprintf("Cannot read nt!_EPROCESS.Token @ %p\n", addrProcess);
  551. }
  552. if (IsPtr64())
  553. {
  554. addrToken = addrToken & ~(ULONG64)15;
  555. } else {
  556. addrToken = addrToken & ~(ULONG64)7;
  557. }
  558. hRetval = addrToken ? S_OK : E_FAIL;
  559. }
  560. }
  561. if (FAILED(hRetval))
  562. {
  563. dprintf("Unable to read token address\n");
  564. }
  565. }
  566. if (SUCCEEDED(hRetval))
  567. {
  568. if (addrProcess)
  569. {
  570. dprintf("_EPROCESS %p, ", addrProcess);
  571. }
  572. if (addrThread)
  573. {
  574. dprintf("_ETHREAD %p, ", addrThread);
  575. }
  576. dprintf("%s %p\n", "_TOKEN", addrToken);
  577. (void)DisplayToken(addrToken, fOptions);
  578. }
  579. return hRetval;
  580. }
  581. HRESULT ProcessTokenOptions(IN OUT PSTR pszArgs, IN OUT ULONG* pfOptions)
  582. {
  583. HRESULT hRetval = pszArgs && pfOptions ? S_OK : E_INVALIDARG;
  584. for (; SUCCEEDED(hRetval) && *pszArgs; pszArgs++)
  585. {
  586. if (*pszArgs == '-' || *pszArgs == '/')
  587. {
  588. switch (*++pszArgs)
  589. {
  590. case 'n':
  591. *pfOptions |= SHOW_FRIENDLY_NAME;
  592. break;
  593. case '?':
  594. default:
  595. hRetval = E_INVALIDARG;
  596. break;
  597. }
  598. *(pszArgs - 1) = *(pszArgs) = ' ';
  599. }
  600. }
  601. if (*pfOptions & SHOW_FRIENDLY_NAME)
  602. {
  603. // "!token -n" will hang the machine if it is running under usermode and
  604. // the process being debugged is lsass.exe
  605. CHAR ProcessDebugged[MAX_PATH];
  606. if (GetCurrentProcessName(ProcessDebugged, sizeof(ProcessDebugged)) == S_OK)
  607. {
  608. if (!_stricmp(ProcessDebugged, "lsass.exe"))
  609. {
  610. dprintf("\n\nWARNING: !token -n while debugging lsass.exe hangs the machine\n\n");
  611. hRetval = E_FAIL;
  612. }
  613. }
  614. }
  615. return hRetval;
  616. }
  617. DECLARE_API( token )
  618. {
  619. HRESULT hRetval = S_OK;
  620. ULONG64 addrToken = 0;
  621. ULONG dwProcessor = 0;
  622. HANDLE hCurrentThread = 0;
  623. ULONG SessionType = DEBUG_CLASS_UNINITIALIZED;
  624. ULONG SessionQual = 0;
  625. CHAR szArgs[64] = {0};
  626. ULONG fOptions = 0;
  627. INIT_API();
  628. if (args && (strlen(args) < sizeof(szArgs)))
  629. {
  630. strcpy(szArgs, args);
  631. }
  632. if (SUCCEEDED(hRetval))
  633. {
  634. hRetval = ProcessTokenOptions(szArgs, &fOptions);
  635. }
  636. if (SUCCEEDED(hRetval) && szArgs[0])
  637. {
  638. hRetval = GetExpressionEx(szArgs, &addrToken, &args) ? S_OK : E_INVALIDARG;
  639. if (!addrToken)
  640. {
  641. hRetval = S_OK;
  642. }
  643. }
  644. if (SUCCEEDED(hRetval))
  645. {
  646. hRetval = GetCurrentProcessor(Client, &dwProcessor, &hCurrentThread);
  647. }
  648. if (SUCCEEDED(hRetval))
  649. {
  650. if (g_TargetClass == DEBUG_CLASS_USER_WINDOWS &&
  651. g_Qualifier == DEBUG_USER_WINDOWS_PROCESS)
  652. {
  653. hRetval = LiveSessionToken(hCurrentThread,
  654. (HANDLE) (ULONG_PTR) addrToken,
  655. fOptions);
  656. }
  657. else if (DEBUG_CLASS_KERNEL == g_TargetClass)
  658. {
  659. hRetval = DumpSessionToken(dwProcessor, addrToken, fOptions);
  660. }
  661. else
  662. {
  663. dprintf("!token only works for kernel targets or live usermode debugging\n");
  664. hRetval = E_FAIL;
  665. }
  666. }
  667. if (E_INVALIDARG == hRetval)
  668. {
  669. (void)DisplayTokenUsage();
  670. }
  671. EXIT_API();
  672. return hRetval;
  673. }