Friday, October 28, 2011

Windows下获取Logon Session信息

什么是LSA?什么是session?MSDN中的描述如下:
Local Security Authority

(LSA) A protected subsystem that authenticates and logs users onto the local system. LSA also maintains information about all aspects of local security on a system, collectively known as the Local Security Policy of the system.

(LSA) 一个判断用户登陆本系统时候的保护子系统。LSA也包含有关本系统中安全的所有方面,统称为本地安全策略的系统。
logon session

A logon session begins whenever a user logs on to a computer. All processes in a logon session have the same primary access token. The access token contains information about the security context of the logon session, including the user's SID, the logon identifier, and the logon SID.

当用户登陆计算机时,一个对应的logon session就开始了。一个logon session可以拥有多个进程,计算机上运行着的所有进程都属于一个唯一的session。怎么获取这些session和进程的相关信息呢?

LsaEnumerateLogonSessions函数可以获取已经存在的logon session identifiers (LUIDs) 和session的总数。

NTSTATUS NTAPI LsaEnumerateLogonSessions(
PULONG LogonSessionCount,
PLUID* LogonSessionList
);

当LogonSessionList不再需要时,需要调用LSAFreeReturnBuffer函数来释放所占用的内存。

看看刚才获取的LogonSessionList,数据类型为LUID。

typedef struct _LUID {
DWORD LowPart;
LONG HighPart;
} LUID, *PLUID;

为了通过LUID来获取详细的logon session信息,需要调用函数LsaGetLogonSessionData,调用者必须是拥有该session或者是本地的系统管理员。

NTSTATUS NTAPI LsaGetLogonSessionData(
PLUID LogonId,
PSECURITY_LOGON_SESSION_DATA* ppLogonSessionData
);

LsaGetLogonSessionData函数返回一个PSECURITY_LOGON_SESSION_DATA结构体。

typedef struct _SECURITY_LOGON_SESSION_DATA {
ULONG Size;
LUID LogonId;
LSA_UNICODE_STRING UserName;
LSA_UNICODE_STRING LogonDomain;
LSA_UNICODE_STRING AuthenticationPackage;
ULONG LogonType;
ULONG Session;
PSID Sid;
LARGE_INTEGER LogonTime;
LSA_UNICODE_STRING LogonServer;
LSA_UNICODE_STRING DnsDomainName;
LSA_UNICODE_STRING Upn;
} SECURITY_LOGON_SESSION_DATA, *PSECURITY_LOGON_SESSION_DATA;

其中包含了登陆标识(LogonId)、登陆的账号(UserName)、域(LogonDomain)、认证方式 (AuthenticationPackage)、登陆类型(LogonType)、会话ID(Session)、用户的Sid(Sid)、用户登陆时间 (LogonTime)等信息。

登陆类型(LogonType)是个枚举类型。

typedef enum _SECURITY_LOGON_TYPE {
Interactive = 2, // Interactively logged on (locally or remotely)
Network, // Accessing system via network
Batch, // Started via a batch queue
Service, // Service started by service controller
Proxy, // Proxy logon
Unlock, // Unlock workstation
NetworkCleartext, // Network logon with cleartext credentials
NewCredentials, // Clone caller, new default credentials
RemoteInteractive, // Remote, yet interactive. Terminal server
CachedInteractive, // Try cached credentials without hitting the net.
CachedRemoteInteractive, // Same as RemoteInteractive, this is used internally for auditing purpose
CachedUnlock // Cached Unlock workstation
} SECURITY_LOGON_TYPE, *PSECURITY_LOGON_TYPE;

用户的Sid(Sid)可以用ConvertSidToStringSid来转换成常见的SID格式字符串。

BOOL ConvertSidToStringSid(
PSID Sid,
LPTSTR* StringSid
);

这样,所有logon session的信息就获取到了。

更进一步的,用EnumProcesses函数枚举进程ID,OpenProcess获取每一个进程的句柄。在分别通过OpenProcessToken 和GetTokenInformation打开并获取进程的访问令牌信息。

BOOL OpenProcessToken(
HANDLE ProcessHandle,
DWORD DesiredAccess,
PHANDLE TokenHandle
);

BOOL GetTokenInformation(
HANDLE TokenHandle,
TOKEN_INFORMATION_CLASS TokenInformationClass,
LPVOID TokenInformation,
DWORD TokenInformationLength,
PDWORD ReturnLength
);

TokenInformationClass是个枚举类型,用来指明要获取的信息类型,这里用TokenStatistics即可。获取的信息在 TokenInformation中,数据类型为TOKEN_STATISTICS的结构体。

typedef struct _TOKEN_STATISTICS {
LUID TokenId;
LUID AuthenticationId;
LARGE_INTEGER ExpirationTime;
TOKEN_TYPE TokenType;
SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
DWORD DynamicCharged;
DWORD DynamicAvailable;
DWORD GroupCount;
DWORD PrivilegeCount;
LUID ModifiedId;
} TOKEN_STATISTICS, *PTOKEN_STATISTICS;

其中LUID AuthenticationId如果和前面logon session的LUID一致,说明该进程的拥有者是相应的logon session。

通过类似的方法,能获取很多有用的信息。下面的程序是用这些API写的一个windows下获取logon session信息,并列举属于该session的进程。

No comments:

Post a Comment