检查当前登陆用户是否需要密码的代码:
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
-
进入 AllowSignInOptions 子键后,检查右侧名为 value 的值。
-
如果存在,双击它并将数值数据设置为**
1(启用)/ 0(禁用)
**。 -
如果不存在,请通过右键单击右侧面板,选择新建 ,然后选择 **DWORD(32 位)值来创建一个新的 DWORD(32 位)**值。
-
将此新值命名为 value 并将 其值数据设置为**
1(启用)/ 0(禁用)
**。 -
注销登陆会话或者重启计算机生效(主要是使得 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 权限才能够访问这些目录和文件。(手动删除是比较危险的,仅当您知晓您正在做什么的情况下完成,并且根据分析,注册表中的一些键值也需要正确清除)
您可以使用两种常用的方式之一,操作此文件夹:
- (方法一)使用 takeown 获取所有权,然后使用 icacls 授予当前用户访问文件夹及其子目录和文件的完全控制权限;
- (方法二)使用 NSudo 等权限提升工具打开具有 TrustedInstaller 特权组并且进程完整性为"系统" 的 cmd.exe 进程,在此命令行中使用 dir 、del、xcopy 等命令操作此目录。
参考文献:
- https://serverfault.com/questions/67706/tool-to-test-a-user-account-and-password-test-login
- https://learn.microsoft.com/zh-cn/windows/win32/api/winbase/nf-winbase-createprocesswithlogonw
文章出处链接:https://blog.csdn.net/qq_59075481/article/details/143081306。