/*++
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]
Dump token by TOKEN address (Kernel mode)\n");
dprintf(" !token [-n] 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;
}