【Windows】检查当前登陆用户是否需要密码

检查当前登陆用户是否需要密码的代码:

cpp 复制代码
#define UNICODE
#define SECURITY_WIN32
#include <iostream>
#include <windows.h>
#include <wtsapi32.h>

#pragma comment(lib, "advapi32.lib")
#pragma comment(lib, "wtsapi32.lib")

struct UserInfo {
    std::wstring userName;
    std::wstring domainName;
};

bool IsRunningAsAdmin() {
    BOOL isAdmin = FALSE;
    HANDLE tokenHandle = NULL;

    // 获取当前进程的访问令牌
    if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &tokenHandle))
    {
        TOKEN_ELEVATION elevation{};
        DWORD cbSize = sizeof(TOKEN_ELEVATION);

        // 获取令牌中的权限信息,判断是否为管理员权限
        if (GetTokenInformation(tokenHandle, TokenElevation,
            &elevation, sizeof(elevation), &cbSize))
        {
            isAdmin = elevation.TokenIsElevated;
        }
        CloseHandle(tokenHandle);
    }
    else {
        std::cerr << "[-] Unable to obtain process token. Error code: "
            << GetLastError() << std::endl;
    }

    return isAdmin;
}

bool CheckAndStartSeclogonService() {
    SC_HANDLE scManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    if (!scManager) {
        std::cerr << "[-] Error: Failed to open service manager. Error code: "
            << GetLastError() << std::endl;
        return false;
    }

    SC_HANDLE seclogonService = OpenService(
        scManager, L"seclogon",
        SERVICE_QUERY_STATUS | SERVICE_START);

    if (!seclogonService) {
        std::cerr << "[-] Error: Failed to open seclogon service. Error code: "
            << GetLastError() << std::endl;
        CloseServiceHandle(scManager);
        return false;
    }

    SERVICE_STATUS_PROCESS serviceStatus{};
    DWORD bytesNeeded;
    if (QueryServiceStatusEx(seclogonService, SC_STATUS_PROCESS_INFO, 
        (LPBYTE)&serviceStatus, sizeof(SERVICE_STATUS_PROCESS), &bytesNeeded))
    {
        if (serviceStatus.dwCurrentState != SERVICE_RUNNING) {
            if (!StartService(seclogonService, 0, NULL)) {
                std::cerr << "[-] Error: Failed to start seclogon service. Error code: "
                    << GetLastError() << std::endl;

                CloseServiceHandle(seclogonService);
                CloseServiceHandle(scManager);
                return false;
            }
            else {
                std::cout << "[+] Seclogon service started successfully." << std::endl;
            }
        }
        else {
            std::cout << "[+] Seclogon service is already running." << std::endl;
        }
    }
    else {
        std::cerr << "[-] Error: Failed to query seclogon service status. Error code: "
            << GetLastError() << std::endl;

        CloseServiceHandle(seclogonService);
        CloseServiceHandle(scManager);
        return false;
    }

    CloseServiceHandle(seclogonService);
    CloseServiceHandle(scManager);
    return true;
}

// 获取当前活动会话的用户名和域名
UserInfo GetActiveUserNameAndDomain() {
    PWTS_SESSION_INFO pSessionInfo = NULL;
    DWORD sessionCount = 0;
    UserInfo activeUserInfo;

    // 枚举所有会话
    if (WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, 
        &pSessionInfo, &sessionCount))
    {
        for (DWORD i = 0; i < sessionCount; ++i) {
            // 查找当前活动的会话
            if (pSessionInfo[i].State == WTSActive) {
                DWORD sessionId = pSessionInfo[i].SessionId;
                LPTSTR pUserName = NULL;
                LPTSTR pDomainName = NULL;
                DWORD bytesReturned = 0;

                // 从活动会话获取用户名
                if (WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, sessionId, 
                    WTSUserName, &pUserName, &bytesReturned) && bytesReturned > 0)
                {
                    activeUserInfo.userName = pUserName;
                }

                // 从活动会话获取域名
                if (WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, sessionId, 
                    WTSDomainName, &pDomainName, &bytesReturned) && bytesReturned > 0)
                {
                    activeUserInfo.domainName = pDomainName;
                }

                // 释放获取到的内存
                if (pUserName) {
                    WTSFreeMemory(pUserName);
                }
                if (pDomainName) {
                    WTSFreeMemory(pDomainName);
                }

                break; // 找到活动用户后,退出循环
            }
        }
        WTSFreeMemory(pSessionInfo);
    }
    else {
        std::cerr << "[-] Unable to enumerate sessions, error code: "
            << GetLastError() << std::endl;
    }

    return activeUserInfo;
}


const INT GetAccountPasswordRequirement(
    const std::wstring& specialArg, 
    const bool IsRunStricted = true
)
{
    bool isCheckSrvFailed = false;
    std::wstring passwordW = L"";  // 空密码

    // 自动解析当前用户名和域名
    UserInfo activeUser = GetActiveUserNameAndDomain();
    if (!activeUser.userName.empty()) {
        // 打印域名和用户名
        std::wcout << L"[+] Domain: " << activeUser.domainName << std::endl;
        std::wcout << L"[+] Username: " << activeUser.userName << std::endl;
    }
    else {
        std::wcout << L"[-] No active users were found." << std::endl;
        return -1;
    }

    // 检查并启动 seclogon 服务
    if (IsRunStricted && !CheckAndStartSeclogonService()) {
        std::cerr << "[-] Error: Unable to ensure seclogon service is running." << std::endl;
        isCheckSrvFailed = true;
    }

    // 获取当前进程的可执行文件路径
    WCHAR modulePath[4096];
    wmemset(modulePath, 0, 4096);
    GetModuleFileNameW(NULL, modulePath, 4095);

    // 构造命令行,包括自身路径和特殊参数
    std::wstring commandLine = L"\"";
    commandLine += modulePath;
    commandLine += L"\" ";
    commandLine += specialArg;  // 添加特殊参数

    // 创建进程信息结构体
    PROCESS_INFORMATION processInfo;
    ZeroMemory(&processInfo, sizeof(processInfo));

    // 创建启动信息结构体
    STARTUPINFOW startupInfo;
    ZeroMemory(&startupInfo, sizeof(startupInfo));
    startupInfo.cb = sizeof(startupInfo);
    startupInfo.wShowWindow = SW_HIDE;

    // 使用 CreateProcessWithLogonW 尝试创建进程
    BOOL result = CreateProcessWithLogonW(
        activeUser.userName.c_str(),   // 用户名
        (activeUser.domainName.empty() ? NULL
            : activeUser.domainName.c_str()),  // 如果域名为空则传入 NULL
        passwordW.c_str(),   // 密码为空
        LOGON_WITH_PROFILE,  // 登录类型
        NULL,                // 不需要具体应用程序
        (LPWSTR)commandLine.c_str(), // 启动参数
        CREATE_NO_WINDOW,  // 创建新控制台
        NULL,                // 环境块
        NULL,                // 当前目录
        &startupInfo,        // 启动信息
        &processInfo         // 进程信息
    );

    // 检查返回结果
    if (!result) {
        DWORD error = GetLastError();
        if (error == 1326) { // ERROR_LOGON_FAILURE
            std::cout << "[+] Password required." << std::endl;
            return 1;
        }
        else if (error == 2) { // ERROR_FILE_NOT_FOUND
            std::cout << "[+] Password not required." << std::endl;
            return 0;
        }
        else if (error == 1385) { // ERROR_LOGON_TYPE_NOT_GRANTED
            std::cerr << "[-] Error 1385: Logon failure, " 
                << "user doesn't have required logon type." << std::endl;
            return 0;
        }
        else if ((!IsRunStricted || isCheckSrvFailed) && error == 5) {
            std::cerr << "[-] Error 5: Unable to access service controller, "
                << "Seclogon service may not start properly." << std::endl;
            return -1;
        }
        else {
            std::cerr << "[-] Error: " << error << std::endl;
            return -1;
        }
    }

    // 成功创建进程,关闭句柄
    CloseHandle(processInfo.hProcess);
    CloseHandle(processInfo.hThread);

    return 0; // 无需密码
}

int wmain(int argc, wchar_t* argv[]) {

    // 检查是否有传递的参数
    if (argc > 1) {
        std::wstring arg = argv[1];
        if (arg == L"--terminate") {
            std::wcout << L"[+] Special argument detected: " << arg << std::endl;
            std::wcout << L"Process will terminate immediately." << std::endl;
            return 0;  // 立即退出
        }
    }

    const bool IsRunStricted = IsRunningAsAdmin();

    if (IsRunStricted) {
        std::cout << "[+] The current process is running as an administrator." << std::endl;
    }
    else {
        std::cout << "[-] The current process is not running as an administrator." << std::endl;
    }

    const INT requireCode = GetAccountPasswordRequirement(L"--terminate", IsRunStricted);

    if (requireCode == 1) {
        std::cout << "[*] The current user requires a password. " << std::endl;
        return 1;
    }
    else if(requireCode == 0) {
        std::cout << "[*] The current user does not require a password. " << std::endl;
        return 0;
    }
    else {
        std::cout << "[*] Unknown Type. " << std::endl;
        return requireCode;
    }
}

支持两种模式:

  • (管理员身份启动):严格检查 Seclogon 服务是否启动;
  • (普通模式):测试程序是否能够以管理员身份启动自身,以此来判断是否需要密码。

返回值:

  • 0 ------ 无密码
  • 1 ------ 有密码
  • -1 或其他值 ------ 未知状态,可能由异常导致

效果截图:
标题

等同于命令:

runas /u:your_domain\a_test_user your_application_name

鸣谢:

@Wormwaker(https://blog.csdn.net/cjz2005)

额外:

【启用/禁用设置中 Windows Hello 登陆选项】

修改以下注册表配置单元:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PolicyManager\default\

Settings\AllowSignInOptions

  1. 进入 AllowSignInOptions 子键后,检查右侧名为 value 的值。

  2. 如果存在,双击它并将数值数据设置为**1(启用)/ 0(禁用)**。

  3. 如果不存在,请通过右键单击右侧面板,选择新建 ,然后选择 **DWORD(32 位)值来创建一个新的 DWORD(32 位)**值。

  4. 将此新值命名为 value 并将值数据设置为**1(启用)/ 0(禁用)**。

  5. 注销登陆会话或者重启计算机生效(主要是使得 smss 和 winlogon 等登陆验证程序更新其内存中的配置)

禁用后设置灰显,无法再操作

【删除 Windows Hello 登陆容器 -- 清除 PIN 密钥】

注意:此操作不需要权限提升,但需要用户注销后才能生效。清除的是当前用户 SID 下的 PIN 密钥。

命令行参数(C:\Windows\System32\CertUtil.exe):
CertUtil -DeleteHelloContainer
删除成功提示

如果已经删除或者不存在容器存根,则会提示:
找不到存根

另一个非官方的方式是通过手动删除存根文件夹及其目录文件。

Windows Hello 登陆容器的本地存储:

C:\Windows\ServiceProfiles\LocalService\AppData\Local\Microsoft\Ngc

此目录下子文件夹名称即用户账户的 SID,文件夹里面包括了多个 dat 文件。

注意:用户需要 TrustedInstaller 权限才能够访问这些目录和文件。(手动删除是比较危险的,仅当您知晓您正在做什么的情况下完成,并且根据分析,注册表中的一些键值也需要正确清除)

您可以使用两种常用的方式之一,操作此文件夹:

  1. (方法一)使用 takeown 获取所有权,然后使用 icacls 授予当前用户访问文件夹及其子目录和文件的完全控制权限;
  2. (方法二)使用 NSudo 等权限提升工具打开具有 TrustedInstaller 特权组并且进程完整性为"系统" 的 cmd.exe 进程,在此命令行中使用 dir 、del、xcopy 等命令操作此目录。

参考文献:


文章出处链接:https://blog.csdn.net/qq_59075481/article/details/143081306

相关推荐
lxyzcm3 分钟前
C++23新特性解析:[[assume]]属性
java·c++·spring boot·c++23
蜀黍@猿21 分钟前
C/C++基础错题归纳
c++
yngsqq28 分钟前
一键打断线(根据相交点打断)——CAD c# 二次开发
windows·microsoft·c#
雨中rain36 分钟前
Linux -- 从抢票逻辑理解线程互斥
linux·运维·c++
ALISHENGYA2 小时前
全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之分支结构(实战项目二)
数据结构·c++·算法
咸鱼桨2 小时前
《庐山派从入门到...》PWM板载蜂鸣器
人工智能·windows·python·k230·庐山派
arong_xu2 小时前
现代C++锁介绍
c++·多线程·mutex
汤姆和杰瑞在瑞士吃糯米粑粑2 小时前
【C++学习篇】AVL树
开发语言·c++·学习
DARLING Zero two♡2 小时前
【优选算法】Pointer-Slice:双指针的算法切片(下)
java·数据结构·c++·算法·leetcode
CodeClimb2 小时前
【华为OD-E卷-木板 100分(python、java、c++、js、c)】
java·javascript·c++·python·华为od