迟到总比不到好。您建立与 LSA 服务器的连接,搜索“协商”身份验证包,创建身份验证信息结构,填写登录类型常量 MsV1_0S4ULogon,用于标识用户 (S4U) 登录服务。使用 S4U 登录时,系统不存储密码,也无法访问网络或加密文件。需要 SeTcbPrivilege 权限才能创建用于模拟目的的令牌。如果您以管理员身份执行程序,默认情况下没有 SeTcbPrivilege 权限,程序会返回成功,但创建的令牌不是主令牌,只能用于识别目的。
#include "stdafx.h"
#include <Windows.h>
#include <Ntsecapi.h>
#include <stdio.h>
#include <Userenv.h>
size_t wcsByteLen(const wchar_t* str);
void InitUnicodeString(UNICODE_STRING& str, const wchar_t* value, BYTE* buffer, size_t& offset);
//#define NEGOSSP_NAME_A "Negotiate"
int main(int argc, char * argv[])
{
HANDLE lsa;
ULONG Flags = MSV1_0_S4U_LOGON_FLAG_CHECK_LOGONHOURS;
DWORD len;
TOKEN_STATISTICS tokenstats;
LsaConnectUntrusted(&lsa);
const wchar_t* domain = L"Computer_name";
const wchar_t* user = L"User_name";
// prepare the authentication info
ULONG authInfoSize = sizeof(MSV1_0_S4U_LOGON) + wcsByteLen(user) + wcsByteLen(domain);
BYTE* authInfoBuf = new BYTE[authInfoSize];
MSV1_0_S4U_LOGON* authInfo = (MSV1_0_S4U_LOGON*)authInfoBuf;
// https://msdn.microsoft.com/en-us/aa378764
authInfo->MessageType = MsV1_0S4ULogon;
/*authInfo->Flags = Flags;*/
size_t offset = sizeof(MSV1_0_S4U_LOGON);
InitUnicodeString(authInfo->UserPrincipalName, user, authInfoBuf, offset);
InitUnicodeString(authInfo->DomainName, domain, authInfoBuf, offset);
// find the Negotiate security package
char packageNameRaw[] = "Negotiate";
LSA_STRING packageName;
packageName.Buffer = packageNameRaw;
packageName.Length = packageName.MaximumLength = (USHORT)strlen(packageName.Buffer);
ULONG packageId;
NTSTATUS stao_05 = LsaLookupAuthenticationPackage(lsa, &packageName, &packageId);
// create a test origin and token source
LSA_STRING origin = {};
origin.Buffer = _strdup("Test");
origin.Length = (USHORT)strlen(origin.Buffer);
origin.MaximumLength = origin.Length;
TOKEN_SOURCE source = {};
strcpy_s(source.SourceName, "Test");
bool test = AllocateLocallyUniqueId(&source.SourceIdentifier);
void* profileBuffer;
DWORD profileBufLen;
LUID luid;
HANDLE token;
QUOTA_LIMITS qlimits;
NTSTATUS subStatus;
NTSTATUS status = LsaLogonUser(lsa, &origin, Batch, packageId, authInfo, authInfoSize, NULL, &source, &profileBuffer, &profileBufLen, &luid, &token, &qlimits, &subStatus);
if (status == ERROR_SUCCESS)
{
if (GetTokenInformation(token, TokenStatistics, &tokenstats, sizeof(TOKEN_STATISTICS), &len) == TRUE)
{
switch (tokenstats.TokenType)
{
case TokenPrimary: printf("Token type: %s\n", "Primary");
break;
case TokenImpersonation: printf("Token type: %s\n", "Impersonation");
break;
}
switch (tokenstats.ImpersonationLevel)
{
case SecurityAnonymous: printf("Impersonation level: %s\n", "Anonymous");
break;
case SecurityIdentification: printf("Impersonation level: %s\n", "Identification");
break;
case SecurityImpersonation: printf("Impersonation level: %s\n", "Impersonation");
break;
case SecurityDelegation: printf("Impersonation level: %s\n", "Delegation");
break;
}
}
}
else
{
ULONG err = LsaNtStatusToWinError(status);
printf("LsaLogonUser failed: %x\n", status);
return 1;
}
}
size_t wcsByteLen(const wchar_t* str)
{
return wcslen(str) * sizeof(wchar_t);
}
void InitUnicodeString(UNICODE_STRING& str, const wchar_t* value, BYTE* buffer, size_t& offset)
{
size_t size = wcsByteLen(value);
str.Length = str.MaximumLength = (USHORT)size;
str.Buffer = (PWSTR)(buffer + offset);
memcpy(str.Buffer, value, size);
offset += size;
}