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
869 lines
23 KiB
/*++
|
|
|
|
Copyright (c) 2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
token.cxx
|
|
|
|
Abstract:
|
|
|
|
Lsaexts debugger extension
|
|
|
|
Author:
|
|
|
|
Larry Zhu (LZhu) May 1, 2001
|
|
|
|
Environment:
|
|
|
|
User Mode
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#include "token.h"
|
|
//#include "util.h"
|
|
//#include "sid.h"
|
|
//
|
|
// Flags used to control level of info
|
|
//
|
|
|
|
#define SHOW_FRIENDLY_NAME 0x001
|
|
#define SHOW_VERBOSE_INFO 0x002
|
|
#define SHOW_SINGLE_ENTRY 0x004
|
|
#define SHOW_SUMMARY_ONLLY 0x008
|
|
#define DECODE_SEC_BUF_DEC 0x010
|
|
#define SHOW_NTLM 0x020
|
|
#define SHOW_KERB 0x040
|
|
#define SHOW_SPNEGO 0x080
|
|
#define SHOW_LSAP 0x100
|
|
|
|
|
|
#define TOKEN_LOG 1
|
|
|
|
|
|
static PCSTR ImpLevels[] = {"Anonymous", "Identification", "Impersonation", "Delegation"};
|
|
#define ImpLevel(x) ((x < (sizeof(ImpLevels) / sizeof(CHAR *))) ? ImpLevels[x] : "Illegal!")
|
|
|
|
static void DisplayTokenUsage(void)
|
|
{
|
|
dprintf("Usage:\n");
|
|
dprintf(" !token [-n] <address> Dump token by TOKEN address (Kernel mode)\n");
|
|
dprintf(" !token [-n] <handle> Dump token by handle (User mode)\n");
|
|
dprintf(" !token [-n] Dump token of active thread\n");
|
|
dprintf("Options:\n");
|
|
dprintf(" -? Display this message\n");
|
|
dprintf(" -n Lookup Sid friendly name on host\n\n");
|
|
}
|
|
|
|
TCHAR* GetPrivName(IN LUID* pPriv)
|
|
{
|
|
switch (pPriv->LowPart)
|
|
{
|
|
case SE_CREATE_TOKEN_PRIVILEGE:
|
|
return(SE_CREATE_TOKEN_NAME);
|
|
case SE_ASSIGNPRIMARYTOKEN_PRIVILEGE:
|
|
return(SE_ASSIGNPRIMARYTOKEN_NAME);
|
|
case SE_LOCK_MEMORY_PRIVILEGE:
|
|
return(SE_LOCK_MEMORY_NAME);
|
|
case SE_INCREASE_QUOTA_PRIVILEGE:
|
|
return(SE_INCREASE_QUOTA_NAME);
|
|
case SE_UNSOLICITED_INPUT_PRIVILEGE:
|
|
return(SE_UNSOLICITED_INPUT_NAME);
|
|
case SE_TCB_PRIVILEGE:
|
|
return(SE_TCB_NAME);
|
|
case SE_SECURITY_PRIVILEGE:
|
|
return(SE_SECURITY_NAME);
|
|
case SE_TAKE_OWNERSHIP_PRIVILEGE:
|
|
return(SE_TAKE_OWNERSHIP_NAME);
|
|
case SE_LOAD_DRIVER_PRIVILEGE:
|
|
return(SE_LOAD_DRIVER_NAME);
|
|
case SE_SYSTEM_PROFILE_PRIVILEGE:
|
|
return(SE_SYSTEM_PROFILE_NAME);
|
|
case SE_SYSTEMTIME_PRIVILEGE:
|
|
return(SE_SYSTEMTIME_NAME);
|
|
case SE_PROF_SINGLE_PROCESS_PRIVILEGE:
|
|
return(SE_PROF_SINGLE_PROCESS_NAME);
|
|
case SE_INC_BASE_PRIORITY_PRIVILEGE:
|
|
return(SE_INC_BASE_PRIORITY_NAME);
|
|
case SE_CREATE_PAGEFILE_PRIVILEGE:
|
|
return(SE_CREATE_PAGEFILE_NAME);
|
|
case SE_CREATE_PERMANENT_PRIVILEGE:
|
|
return(SE_CREATE_PERMANENT_NAME);
|
|
case SE_BACKUP_PRIVILEGE:
|
|
return(SE_BACKUP_NAME);
|
|
case SE_RESTORE_PRIVILEGE:
|
|
return(SE_RESTORE_NAME);
|
|
case SE_SHUTDOWN_PRIVILEGE:
|
|
return(SE_SHUTDOWN_NAME);
|
|
case SE_DEBUG_PRIVILEGE:
|
|
return(SE_DEBUG_NAME);
|
|
case SE_AUDIT_PRIVILEGE:
|
|
return(SE_AUDIT_NAME);
|
|
case SE_SYSTEM_ENVIRONMENT_PRIVILEGE:
|
|
return(SE_SYSTEM_ENVIRONMENT_NAME);
|
|
case SE_CHANGE_NOTIFY_PRIVILEGE:
|
|
return(SE_CHANGE_NOTIFY_NAME);
|
|
case SE_REMOTE_SHUTDOWN_PRIVILEGE:
|
|
return(SE_REMOTE_SHUTDOWN_NAME);
|
|
case SE_UNDOCK_PRIVILEGE:
|
|
return(SE_UNDOCK_NAME);
|
|
case SE_SYNC_AGENT_PRIVILEGE:
|
|
return(SE_SYNC_AGENT_NAME);
|
|
case SE_ENABLE_DELEGATION_PRIVILEGE:
|
|
return(SE_ENABLE_DELEGATION_NAME);
|
|
case SE_MANAGE_VOLUME_PRIVILEGE:
|
|
return(SE_MANAGE_VOLUME_NAME);
|
|
default:
|
|
return("Unknown Privilege");
|
|
}
|
|
}
|
|
|
|
HRESULT LocalDumpSid(IN PCSTR pszPad, PSID pxSid, IN ULONG fOptions)
|
|
{
|
|
UNICODE_STRING ucsSid = {0};
|
|
NTSTATUS NtStatus = STATUS_UNSUCCESSFUL;
|
|
PCSTR FriendlyName;
|
|
|
|
NtStatus = RtlConvertSidToUnicodeString(&ucsSid, pxSid, TRUE);
|
|
|
|
if (NT_SUCCESS(NtStatus))
|
|
{
|
|
|
|
dprintf("%s", pszPad);
|
|
dprintf("%wZ", &ucsSid);
|
|
|
|
}
|
|
else
|
|
{
|
|
dprintf("LocadDumpSid failed to dump Sid at addr %p\n", pxSid);
|
|
}
|
|
|
|
RtlFreeUnicodeString(&ucsSid);
|
|
|
|
if (fOptions & SHOW_FRIENDLY_NAME)
|
|
{
|
|
|
|
dprintf(" ");
|
|
|
|
FriendlyName = ConvertSidToFriendlyName(pxSid, "(%s: %s\\%s)");
|
|
|
|
if (!FriendlyName)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
dprintf(FriendlyName);
|
|
}
|
|
|
|
dprintf("\n");
|
|
return S_OK;
|
|
}
|
|
|
|
void DumpAttr(IN PCSTR pszPad, IN ULONG attributes, IN ULONG SAType)
|
|
{
|
|
if (SAType == SATYPE_GROUP)
|
|
{
|
|
dprintf("%sAttributes - ", pszPad);
|
|
|
|
if (attributes & SE_GROUP_MANDATORY)
|
|
{
|
|
attributes &= ~SE_GROUP_MANDATORY;
|
|
dprintf("Mandatory ");
|
|
}
|
|
|
|
if (attributes & SE_GROUP_ENABLED_BY_DEFAULT)
|
|
{
|
|
attributes &= ~SE_GROUP_ENABLED_BY_DEFAULT;
|
|
dprintf("Default ");
|
|
}
|
|
|
|
if (attributes & SE_GROUP_ENABLED)
|
|
{
|
|
attributes &= ~SE_GROUP_ENABLED;
|
|
dprintf("Enabled ");
|
|
}
|
|
|
|
if (attributes & SE_GROUP_OWNER)
|
|
{
|
|
attributes &= ~SE_GROUP_OWNER;
|
|
dprintf("Owner ");
|
|
}
|
|
|
|
if (attributes & SE_GROUP_LOGON_ID)
|
|
{
|
|
attributes &= ~SE_GROUP_LOGON_ID;
|
|
dprintf("LogonId ");
|
|
}
|
|
|
|
if (attributes & SE_GROUP_USE_FOR_DENY_ONLY)
|
|
{
|
|
attributes &= ~SE_GROUP_USE_FOR_DENY_ONLY;
|
|
dprintf("DenyOnly ");
|
|
}
|
|
|
|
if (attributes & SE_GROUP_RESOURCE)
|
|
{
|
|
attributes &= ~SE_GROUP_RESOURCE;
|
|
dprintf("GroupResource ");
|
|
}
|
|
|
|
|
|
if (attributes)
|
|
{
|
|
dprintf("%#x ", attributes);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DumpLocalSidAttr(IN PSID_AND_ATTRIBUTES pSA, IN ULONG SAType, IN ULONG fOptions)
|
|
{
|
|
LocalDumpSid("", pSA->Sid, fOptions);
|
|
DumpAttr(" ", pSA->Attributes, SAType);
|
|
}
|
|
|
|
void DumpSidAttr(IN ULONG64 addrSid, IN ULONG attributes, IN ULONG SAType, IN ULONG fOptions)
|
|
{
|
|
ShowSid("", addrSid, fOptions);
|
|
DumpAttr(" ", attributes, SAType);
|
|
}
|
|
|
|
void DumpLuidAttr(PLUID_AND_ATTRIBUTES pLA, ULONG LAType)
|
|
{
|
|
dprintf("0x%x%08x", pLA->Luid.HighPart, pLA->Luid.LowPart);
|
|
dprintf(" %-32s", GetPrivName(&pLA->Luid));
|
|
|
|
if (LAType == SATYPE_PRIV)
|
|
{
|
|
|
|
dprintf(" Attributes - ");
|
|
if (pLA->Attributes & SE_PRIVILEGE_ENABLED)
|
|
{
|
|
|
|
dprintf("Enabled ");
|
|
}
|
|
|
|
if (pLA->Attributes & SE_PRIVILEGE_ENABLED_BY_DEFAULT)
|
|
{
|
|
|
|
dprintf("Default ");
|
|
}
|
|
}
|
|
}
|
|
|
|
void PrintToken(IN HANDLE hToken, IN ULONG fOptions)
|
|
{
|
|
TOKEN_USER* pTUser = NULL;
|
|
TOKEN_GROUPS* pTGroups = NULL;
|
|
TOKEN_PRIVILEGES* pTPrivs = NULL;
|
|
TOKEN_PRIMARY_GROUP* pTPrimaryGroup = NULL;
|
|
TOKEN_STATISTICS TStats = {0};
|
|
ULONG cbRetInfo = 0;
|
|
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
|
DWORD i = 0;
|
|
DWORD dwSessionId = 0;
|
|
|
|
CHAR bufferUser[256];
|
|
CHAR bufferGroups[4096];
|
|
CHAR bufferPriv[1024];
|
|
CHAR bufferPriGrp[128];
|
|
|
|
pTUser = (TOKEN_USER*) &bufferUser[0];
|
|
pTGroups = (TOKEN_GROUPS*) &bufferGroups[0];
|
|
pTPrivs = (TOKEN_PRIVILEGES*) &bufferPriv[0];
|
|
pTPrimaryGroup = (TOKEN_PRIMARY_GROUP*) &bufferPriGrp[0];
|
|
|
|
status = NtQueryInformationToken(hToken, TokenSessionId, &dwSessionId, sizeof(dwSessionId), &cbRetInfo);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
|
|
dprintf("Failed to query token: %#x\n", status);
|
|
return;
|
|
}
|
|
dprintf("TS Session ID: %#x\n", dwSessionId);
|
|
|
|
status = NtQueryInformationToken(hToken, TokenUser, pTUser, 256, &cbRetInfo);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
|
|
dprintf("Failed to query token: %#x\n", status);
|
|
return;
|
|
}
|
|
|
|
dprintf("User: ");
|
|
DumpLocalSidAttr(&pTUser->User, SATYPE_USER, fOptions);
|
|
|
|
dprintf("Groups: ");
|
|
status = NtQueryInformationToken(hToken, TokenGroups, pTGroups, 4096, &cbRetInfo);
|
|
|
|
for (i = 0; i < pTGroups->GroupCount; i++)
|
|
{
|
|
|
|
dprintf("\n %02d ", i);
|
|
DumpLocalSidAttr(&pTGroups->Groups[i], SATYPE_GROUP, fOptions);
|
|
|
|
if (CheckControlC())
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
status = NtQueryInformationToken(hToken, TokenPrimaryGroup, pTPrimaryGroup, 128, &cbRetInfo);
|
|
|
|
dprintf("\n");
|
|
dprintf("Primary Group: ");
|
|
LocalDumpSid("", pTPrimaryGroup->PrimaryGroup, fOptions);
|
|
|
|
dprintf("Privs: ");
|
|
status = NtQueryInformationToken(hToken, TokenPrivileges, pTPrivs, 1024, &cbRetInfo);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
|
|
printf("NtQueryInformationToken returned %#x\n", status);
|
|
return;
|
|
}
|
|
for (i = 0; i < pTPrivs->PrivilegeCount; i++)
|
|
{
|
|
|
|
dprintf("\n %02d ", i);
|
|
DumpLuidAttr(&pTPrivs->Privileges[i], SATYPE_PRIV);
|
|
|
|
if (CheckControlC())
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
status = NtQueryInformationToken(hToken, TokenStatistics, &TStats, sizeof(TStats), &cbRetInfo);
|
|
|
|
dprintf("\nAuth ID: %x:%x\n", TStats.AuthenticationId.HighPart, TStats.AuthenticationId.LowPart);
|
|
dprintf("Impersonation Level: %s\n", ImpLevel(TStats.ImpersonationLevel));
|
|
dprintf("TokenType: %s\n", TStats.TokenType == TokenPrimary ? "Primary" : "Impersonation");
|
|
}
|
|
|
|
HRESULT LiveSessionToken(IN HANDLE hThread, IN HANDLE hRemoteToken, IN ULONG fOptions)
|
|
{
|
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|
HANDLE hProcess = NULL;
|
|
HANDLE hToken = NULL;
|
|
|
|
GetCurrentProcessHandle(&hProcess);
|
|
|
|
Status = hProcess ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
|
|
if (hRemoteToken == NULL)
|
|
{
|
|
|
|
Status = NtOpenThreadToken(hThread, TOKEN_QUERY, FALSE, &hToken);
|
|
|
|
if ((Status == STATUS_NO_TOKEN) || (hToken == NULL))
|
|
{
|
|
|
|
dprintf("Thread is not impersonating. Using process token...\n");
|
|
|
|
Status = NtOpenProcessToken(hProcess, TOKEN_QUERY, &hToken);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
Status = DuplicateHandle(hProcess, hRemoteToken,
|
|
GetCurrentProcess(), &hToken, 0, FALSE,
|
|
DUPLICATE_SAME_ACCESS) ? STATUS_SUCCESS : GetLastError() + 0x80000000;
|
|
}
|
|
}
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
|
|
DBG_LOG(TOKEN_LOG, ("token %p, remote token %p\n", hToken, hRemoteToken));
|
|
|
|
PrintToken(hToken, fOptions);
|
|
|
|
CloseHandle(hToken);
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
dprintf("Error %#x getting thread token\n", Status);
|
|
}
|
|
|
|
return NT_SUCCESS(Status) ? S_OK : E_FAIL;
|
|
}
|
|
|
|
void DisplayPrivilegs(IN ULONG64 privAddr, IN ULONG cPriv)
|
|
{
|
|
UCHAR buffer[1024] = {0};
|
|
LUID_AND_ATTRIBUTES* pPrivileges = (LUID_AND_ATTRIBUTES*) buffer;
|
|
ULONG ret;
|
|
ULONG i;
|
|
|
|
if ((cPriv * sizeof(LUID_AND_ATTRIBUTES)) > sizeof(buffer))
|
|
{
|
|
dprintf("Invalid privilege count %#lx - too large.\n", cPriv);
|
|
return;
|
|
}
|
|
if (!ReadMemory(privAddr, pPrivileges, cPriv * sizeof(LUID_AND_ATTRIBUTES), &ret) ||
|
|
(ret != cPriv * sizeof(LUID_AND_ATTRIBUTES)))
|
|
{
|
|
dprintf("Unable to read DisplayPrivilegs @ %p\n", privAddr);
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < cPriv ; i++)
|
|
{
|
|
|
|
dprintf("\n %02d ", i);
|
|
DumpLuidAttr(pPrivileges + i, SATYPE_PRIV);
|
|
|
|
if (CheckControlC())
|
|
{
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void DisplayGroups(IN ULONG64 addrGroups, IN ULONG cGroup, IN ULONG cbSA, IN ULONG fOptions)
|
|
{
|
|
ULONG i;
|
|
ULONG64 sa;
|
|
for (i = 0; i < cGroup; i++)
|
|
{
|
|
|
|
dprintf("\n %02d ", i);
|
|
sa = addrGroups + i * cbSA;
|
|
DumpSidAttr(GetSidAddr(sa), GetSidAttributes(sa), SATYPE_GROUP, fOptions);
|
|
|
|
if (CheckControlC())
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// kd dump token
|
|
//
|
|
BOOL
|
|
DumpKdToken (
|
|
IN char *Pad,
|
|
IN ULONG64 RealTokenBase,
|
|
IN ULONG Flags
|
|
)
|
|
{
|
|
ULONG TokenType, TokenFlags, TokenInUse, UserAndGroupCount;
|
|
ULONG RestrictedSidCount, PrivilegeCount;
|
|
ULONG64 AuthenticationId, TokenId, ParentTokenId, ModifiedId, UserAndGroups;
|
|
ULONG64 RestrictedSids, Privileges, ImpersonationLevel;
|
|
CHAR SourceName[16];
|
|
|
|
#define TokFld(F) GetFieldValue(RealTokenBase, "TOKEN", #F, F)
|
|
#define TokSubFld(F,N) GetFieldValue(RealTokenBase, "TOKEN", #F, N)
|
|
|
|
if (TokFld(TokenType)) {
|
|
dprintf("%sUnable to read TOKEN at %p.\n", Pad, RealTokenBase);
|
|
return FALSE;
|
|
}
|
|
|
|
if (TokenType != TokenPrimary &&
|
|
TokenType != TokenImpersonation) {
|
|
dprintf("%sUNKNOWN token type - probably is not a token\n", Pad);
|
|
return FALSE;
|
|
}
|
|
|
|
TokSubFld(TokenSource.SourceName, SourceName);
|
|
TokFld(TokenFlags); TokFld(AuthenticationId);
|
|
TokFld(TokenInUse);
|
|
TokFld(ImpersonationLevel); TokFld(TokenId), TokFld(ParentTokenId);
|
|
TokFld(ModifiedId); TokFld(RestrictedSids); TokFld(RestrictedSidCount);
|
|
TokFld(PrivilegeCount); TokFld(Privileges); TokFld(UserAndGroupCount);
|
|
TokFld(UserAndGroups);
|
|
|
|
dprintf("%sSource: %-18s TokenFlags: 0x%x ",
|
|
Pad, &(SourceName[0]), TokenFlags);
|
|
|
|
//
|
|
// Token type
|
|
//
|
|
if (TokenType == TokenPrimary) {
|
|
if (TokenInUse) {
|
|
dprintf("( Token in use )\n");
|
|
} else {
|
|
dprintf("( Token NOT in use ) \n");
|
|
}
|
|
} else
|
|
{
|
|
dprintf("\n");
|
|
}
|
|
|
|
//
|
|
// Token ID and modified ID
|
|
//
|
|
dprintf("%sToken ID: %-16I64lx ParentToken ID: %I64lx\n", Pad, TokenId, ParentTokenId );
|
|
|
|
dprintf("%sModified ID: (%lx, %lx)\n",
|
|
Pad, (ULONG) (ModifiedId >> 32) & 0xffffffff, (ULONG) (ModifiedId & 0xffffffff));
|
|
|
|
dprintf("%sRestrictedSidCount: %-6d RestrictedSids: %p\n", Pad, RestrictedSidCount, RestrictedSids );
|
|
|
|
#undef TokFld
|
|
#undef TokSubFld
|
|
return TRUE;
|
|
|
|
//
|
|
// Intentionally left out as detailed info has already been displayed before and
|
|
// dt _TOKEN displays these
|
|
//
|
|
dprintf("%sSidCount: %-16d Sids: %p\n", Pad, UserAndGroupCount, UserAndGroups );
|
|
|
|
dprintf("%sPrivilegeCount: %-10d Privileges: %p\n", Pad, PrivilegeCount, Privileges );
|
|
|
|
}
|
|
|
|
|
|
void DisplayToken(ULONG64 addrToken, IN ULONG fOptions)
|
|
{
|
|
ULONG cGroup = 0;
|
|
ULONG cbSA = 0;
|
|
ULONG64 addrGroups = 0;
|
|
ULONG ret;
|
|
ULONG64 tsa;
|
|
|
|
if (ret = (ULONG) InitTypeRead(addrToken, nt!_TOKEN))
|
|
{
|
|
dprintf("InitTypeRead(%p, nt!_TOKEN) failed - %lx\n", addrToken, ret);
|
|
return;
|
|
}
|
|
|
|
dprintf("TS Session ID: %#x\n", (ULONG) ReadField(SessionId));
|
|
|
|
dprintf("User: "); // nt!_TOKEN
|
|
|
|
tsa = ReadField(UserAndGroups); // TSID_AND_ATTRIBUTES tsa(LsaReadPtrField(UserAndGroups));
|
|
DumpSidAttr(GetSidAddr(tsa), GetSidAttributes(tsa), SATYPE_USER, fOptions);
|
|
|
|
dprintf("Groups: ");
|
|
|
|
cGroup = (ULONG) ReadField(UserAndGroupCount);
|
|
|
|
addrGroups = ReadField(UserAndGroups);
|
|
// ReadTypeSize("nt!_SID_AND_ATTRIBUTES[1]") - ReadTypeSize("nt!_SID_AND_ATTRIBUTES[2]");
|
|
cbSA = GetTypeSize("nt!_SID_AND_ATTRIBUTES");
|
|
//
|
|
// stolen from NtQueryInformationToken because the first sid is the user itself
|
|
//
|
|
addrGroups += cbSA;
|
|
cGroup -= 1;
|
|
|
|
DisplayGroups(addrGroups, cGroup, cbSA, fOptions);
|
|
|
|
dprintf("\n");
|
|
dprintf("Primary Group: ");
|
|
ShowSid("", ReadField(PrimaryGroup), fOptions);
|
|
|
|
dprintf("Privs: ");
|
|
DisplayPrivilegs(ReadField(Privileges), (ULONG) ReadField(PrivilegeCount));
|
|
|
|
dprintf("\nAuthentication ID: (%x,%x)\n", (ULONG) ReadField(AuthenticationId.HighPart), (ULONG) ReadField(AuthenticationId.LowPart));
|
|
dprintf("Impersonation Level: %s\n", ImpLevel((ULONG) ReadField(ImpersonationLevel)));
|
|
dprintf("TokenType: %s\n", ((ULONG) ReadField(TokenType)) == TokenPrimary ? "Primary" : "Impersonation");
|
|
|
|
DumpKdToken("", addrToken, 0);
|
|
}
|
|
|
|
#if 0
|
|
|
|
//
|
|
// This is the logic to determine impersonation info in !thread
|
|
//
|
|
if (ActiveImpersonationInfo)
|
|
{
|
|
InitTypeRead(ImpersonationInfo, nt!_PS_IMPERSONATION_INFORMATION);
|
|
ImpersonationInfo_Token = ReadField(Token);
|
|
ImpersonationInfo_ImpersonationLevel = ReadField(ImpersonationLevel);
|
|
|
|
if (ImpersonationInfo_Token)
|
|
{
|
|
dprintf("%sImpersonation token: %p (Level %s)\n",
|
|
pszPad, ImpersonationInfo_Token,
|
|
SecImpLevels( ImpersonationInfo_ImpersonationLevel ) );
|
|
}
|
|
else
|
|
{
|
|
dprintf("%sUnable to read Impersonation Information at %x\n",
|
|
pszPad, ImpersonationInfo );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
dprintf("%sNot impersonating\n", pszPad);
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
HRESULT DumpSessionToken(IN ULONG dwProcessor, IN ULONG64 addrToken, IN ULONG fOptions)
|
|
{
|
|
HRESULT hRetval = S_OK;
|
|
|
|
ULONG64 addrThread = 0;
|
|
ULONG64 addrProcess = 0;
|
|
ULONG ActiveImpersonationInfo = 0;
|
|
ULONG64 addrImpersonationInfo = 0;
|
|
ULONG64 ret;
|
|
|
|
//
|
|
// If no token addr is input as argument, addrToken is zero
|
|
//
|
|
if ( ((LONG64)addrToken) > 0 ) // sanity check
|
|
{
|
|
|
|
//
|
|
// This can not be a kernel mode access token address
|
|
//
|
|
dprintf("%#I64x is not a valid KM token address, if this is an access token handle,\n", addrToken);
|
|
dprintf("try \"!handle %#I64x\" to get the token address first\n\n", addrToken);
|
|
hRetval = E_FAIL;
|
|
}
|
|
|
|
if (SUCCEEDED(hRetval) && !addrToken)
|
|
{
|
|
|
|
addrThread = 0;
|
|
GetCurrentThreadAddr(dwProcessor, &addrThread);
|
|
hRetval = addrThread ? S_OK : E_FAIL;
|
|
|
|
if (FAILED(hRetval))
|
|
{
|
|
|
|
dprintf("Unable to read current thread address\n");
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
//
|
|
// ActiveImpersonationInfo is of type C Bit Fields and has a width of 1 (Bitfield Pos 3, 1 Bit)
|
|
//
|
|
if (ret = InitTypeRead(addrThread, nt!_ETHREAD))
|
|
{
|
|
dprintf("InitTypeRead(%I64x, nt!_ETHREAD) failed - %lx", addrThread, ret);
|
|
return E_FAIL;
|
|
}
|
|
|
|
ActiveImpersonationInfo = (ULONG) ReadField(ActiveImpersonationInfo);
|
|
|
|
if (ActiveImpersonationInfo)
|
|
{
|
|
|
|
addrImpersonationInfo = ReadField(ImpersonationInfo);
|
|
|
|
if (!addrImpersonationInfo ||
|
|
GetFieldValue(addrImpersonationInfo, "nt!_PS_IMPERSONATION_INFORMATION", "Token", addrToken))
|
|
{
|
|
dprintf("Cannot read nt!_PS_IMPERSONATION_INFORMATION.Token @ %p\n", addrImpersonationInfo);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If addrToken is NULL, then this is not an impersonation case
|
|
//
|
|
if (SUCCEEDED(hRetval) && !addrToken)
|
|
{
|
|
|
|
dprintf("Thread is not impersonating. Using process token...\n");
|
|
|
|
GetCurrentProcessAddr(dwProcessor, addrThread, &addrProcess);
|
|
hRetval = addrProcess ? S_OK : E_FAIL;
|
|
|
|
if (FAILED(hRetval))
|
|
{
|
|
|
|
dprintf("Unable to read current process address\n");
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
if (GetFieldValue(addrProcess, "nt!_EPROCESS", "Token", addrToken))
|
|
{
|
|
dprintf("Cannot read nt!_EPROCESS.Token @ %p\n", addrProcess);
|
|
}
|
|
|
|
if (IsPtr64())
|
|
{
|
|
addrToken = addrToken & ~(ULONG64)15;
|
|
} else {
|
|
addrToken = addrToken & ~(ULONG64)7;
|
|
}
|
|
|
|
hRetval = addrToken ? S_OK : E_FAIL;
|
|
}
|
|
}
|
|
|
|
if (FAILED(hRetval))
|
|
{
|
|
|
|
dprintf("Unable to read token address\n");
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
|
|
if (addrProcess)
|
|
{
|
|
|
|
dprintf("_EPROCESS %p, ", addrProcess);
|
|
}
|
|
|
|
if (addrThread)
|
|
{
|
|
|
|
dprintf("_ETHREAD %p, ", addrThread);
|
|
}
|
|
|
|
dprintf("%s %p\n", "_TOKEN", addrToken);
|
|
|
|
|
|
(void)DisplayToken(addrToken, fOptions);
|
|
}
|
|
|
|
return hRetval;
|
|
}
|
|
|
|
HRESULT ProcessTokenOptions(IN OUT PSTR pszArgs, IN OUT ULONG* pfOptions)
|
|
{
|
|
HRESULT hRetval = pszArgs && pfOptions ? S_OK : E_INVALIDARG;
|
|
|
|
for (; SUCCEEDED(hRetval) && *pszArgs; pszArgs++)
|
|
{
|
|
|
|
if (*pszArgs == '-' || *pszArgs == '/')
|
|
{
|
|
|
|
switch (*++pszArgs)
|
|
{
|
|
case 'n':
|
|
*pfOptions |= SHOW_FRIENDLY_NAME;
|
|
break;
|
|
|
|
case '?':
|
|
default:
|
|
hRetval = E_INVALIDARG;
|
|
break;
|
|
}
|
|
|
|
*(pszArgs - 1) = *(pszArgs) = ' ';
|
|
}
|
|
}
|
|
|
|
if (*pfOptions & SHOW_FRIENDLY_NAME)
|
|
{
|
|
// "!token -n" will hang the machine if it is running under usermode and
|
|
// the process being debugged is lsass.exe
|
|
CHAR ProcessDebugged[MAX_PATH];
|
|
|
|
if (GetCurrentProcessName(ProcessDebugged, sizeof(ProcessDebugged)) == S_OK)
|
|
{
|
|
if (!_stricmp(ProcessDebugged, "lsass.exe"))
|
|
{
|
|
dprintf("\n\nWARNING: !token -n while debugging lsass.exe hangs the machine\n\n");
|
|
hRetval = E_FAIL;
|
|
}
|
|
}
|
|
}
|
|
return hRetval;
|
|
}
|
|
|
|
DECLARE_API( token )
|
|
{
|
|
HRESULT hRetval = S_OK;
|
|
|
|
ULONG64 addrToken = 0;
|
|
ULONG dwProcessor = 0;
|
|
HANDLE hCurrentThread = 0;
|
|
ULONG SessionType = DEBUG_CLASS_UNINITIALIZED;
|
|
ULONG SessionQual = 0;
|
|
|
|
CHAR szArgs[64] = {0};
|
|
ULONG fOptions = 0;
|
|
|
|
INIT_API();
|
|
|
|
|
|
if (args && (strlen(args) < sizeof(szArgs)))
|
|
{
|
|
strcpy(szArgs, args);
|
|
}
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
|
|
hRetval = ProcessTokenOptions(szArgs, &fOptions);
|
|
}
|
|
|
|
if (SUCCEEDED(hRetval) && szArgs[0])
|
|
{
|
|
|
|
hRetval = GetExpressionEx(szArgs, &addrToken, &args) ? S_OK : E_INVALIDARG;
|
|
if (!addrToken)
|
|
{
|
|
hRetval = S_OK;
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
|
|
hRetval = GetCurrentProcessor(Client, &dwProcessor, &hCurrentThread);
|
|
}
|
|
|
|
if (SUCCEEDED(hRetval))
|
|
{
|
|
|
|
if (g_TargetClass == DEBUG_CLASS_USER_WINDOWS &&
|
|
g_Qualifier == DEBUG_USER_WINDOWS_PROCESS)
|
|
{
|
|
|
|
hRetval = LiveSessionToken(hCurrentThread,
|
|
(HANDLE) (ULONG_PTR) addrToken,
|
|
fOptions);
|
|
|
|
}
|
|
else if (DEBUG_CLASS_KERNEL == g_TargetClass)
|
|
{
|
|
|
|
hRetval = DumpSessionToken(dwProcessor, addrToken, fOptions);
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
dprintf("!token only works for kernel targets or live usermode debugging\n");
|
|
hRetval = E_FAIL;
|
|
}
|
|
}
|
|
|
|
if (E_INVALIDARG == hRetval)
|
|
{
|
|
|
|
(void)DisplayTokenUsage();
|
|
}
|
|
|
|
EXIT_API();
|
|
return hRetval;
|
|
}
|