3

让我根据 Derek 的建议重新表述我的问题。

在 Windows Vista/7/8/8.1 中,任务调度程序可以在本地用户帐户的安全上下文中执行任务,而无需存储本地帐户用户密码。当任务同时选择“无论用户是否登录时运行”和“不存储密码”选项时都会出现这种情况。唯一的限制是,选择了上述选项的任务无法访问加密文件或网络资源。

我需要在独立机器上开发一个高度可信的应用程序(作为本地系统执行),它在本地用户帐户的安全上下文中执行一些任务而不存储本地帐户用户密码,这些任务不需要访问网络资源或本地加密文件。不能模拟已经登录的本地用户帐户,即使系统重新启动并且用户没有登录系统,我也需要运行该应用程序。

由于任务调度程序可以做我需要的事情,这意味着必须有一个 api 能够创建本地用户访问令牌而无需提供用户密码。有谁知道这个api是什么?

您可以提供的任何帮助将不胜感激。

ps:机器是单机的,没有加入域。

4

1 回答 1

6

迟到总比不到好。您建立与 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;
}
于 2016-02-27T14:24:09.000 回答