我有一台配置好的电脑自动登录。Windows
重新启动后,它会自动使用预定义的用户登录。
我也想通过远程桌面连接到这台计算机。但是我需要这个特定用户的密码。
我已经知道可以在注册表中配置 AutoLogon:
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon
AutoAdminLogon
(REG_SZ) = 1
DefaultDomainName
(REG_SZ) = MyDomain(或为空)
DefaultUserName
(REG_SZ) = MyUser
DefaultPassword
(REG_SZ) = MyPass
但在我的例子中没有输入DefaultPassword
。尽管缺少密码,AutoLogon 仍然有效。并且密码不是空字符串。
我如何找回密码?
答案1
解决方案:LsaRetrievePrivateData
Windows 可以以隐藏的方式存储键值对,当系统启用自动登录时,密码将存储在 DefaultPassword 字段中。要检索它,请使用以下方式:
LsaOpenPolicy(NULL, &attribs, POLICY_ALL_ACCESS, &lsa_handle)
打开一个LSA_HANDLE
对象- 您创建一个
LSA_UNICODE_STRING
结构并让它指向wchar_t
包含的数据缓冲区DefaultPassword
。 - 然后调用
LsaRetrievePrivateData(lsa_handle, &key, &ptr_value)
,将字符串结构作为键传递给它。 - 返回的指针(
ptr_value
)保存一个新的 Unicode 字符串数据结构,其中应包含解密的密码,如果不存在则不包含。
必须在管理员权限下进行调用,否则访问将被拒绝。
起源:https://www.opengate.at/blog/2021/11/win32-stored-password/
下面是在我的情况下可以运行并显示密码所需的 C 代码:
#include <string>
#include <exception>
#include <wchar.h>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include "windows.h"
#include "Ntsecapi.h"
typedef std::string string_t;
typedef std::wstring wstring_t;
struct LsaHandle
{
private:
LsaHandle(const LsaHandle&);
LsaHandle& operator=(const LsaHandle&);
LSA_HANDLE handle;
public:
LsaHandle(LSA_HANDLE h = LSA_HANDLE())
: handle(h)
{
}
~LsaHandle()
{
if(this->handle)
{
LsaClose(this->handle);
}
}
LSA_HANDLE& operator*()
{
return this->handle;
}
};
wstring_t getSecretPwd()
{
LsaHandle hPolicy;
LSA_OBJECT_ATTRIBUTES attribs;
ZeroMemory(&attribs, sizeof(attribs));
NTSTATUS dwStatus = LsaOpenPolicy(NULL, &attribs, POLICY_ALL_ACCESS, &*hPolicy);
DWORD dwError = LsaNtStatusToWinError(dwStatus);
if(dwError != 0)
{
DWORD dwError = ::GetLastError();
std::stringstream ss;
ss << "Failed to open storage, error-code = " << dwError;
throw std::runtime_error(ss.str());
}
WCHAR wstrKeyName[] = L"DefaultPassword";
LSA_UNICODE_STRING keyName;
keyName.Buffer = wstrKeyName;
keyName.Length = static_cast<USHORT>(wcslen(wstrKeyName) * sizeof(wstrKeyName[0]));
keyName.MaximumLength = static_cast<USHORT>((wcslen(wstrKeyName) + 1) * sizeof(wstrKeyName[0]));
PLSA_UNICODE_STRING privateData = NULL;
dwStatus = LsaRetrievePrivateData(*hPolicy, &keyName, &privateData);
if(dwStatus != 0)
{
dwError = LsaNtStatusToWinError(dwStatus);
std::stringstream ss;
ss << "Failed to retrieve data, error-code = " << dwError;
throw std::runtime_error(ss.str());
}
wstring_t secret_pwd(privateData->Buffer, privateData->Length / sizeof(privateData->Buffer[0]));
LsaFreeMemory(privateData);
return secret_pwd;
}
struct KeyHandle
{
private:
HKEY handle;
KeyHandle(const KeyHandle&);
KeyHandle& operator=(const KeyHandle&);
public:
KeyHandle(HKEY h = HKEY())
: handle(h)
{
}
~KeyHandle()
{
if(this->handle)
{
RegCloseKey(this->handle);
}
}
HKEY& operator*()
{
return this->handle;
}
};
wstring_t getRegistryPwd()
{
wchar_t strPass[2048];
DWORD dwType;
DWORD dwSize = sizeof(strPass);
KeyHandle hKey;
LONG result = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
0,
KEY_QUERY_VALUE,
&*hKey);
if(ERROR_SUCCESS != result)
{
throw std::exception("Failed to open storage");
}
result = RegQueryValueExW(*hKey, L"DefaultPassword", 0, &dwType, (LPBYTE)strPass, &dwSize);
switch(result)
{
case ERROR_SUCCESS:
{
if(dwType != REG_SZ)
return wstring_t();
else
return wstring_t(strPass, dwSize / 2);
break;
}
case ERROR_FILE_NOT_FOUND:
case ERROR_PATH_NOT_FOUND:
{
return wstring_t();
}
default:
{
throw std::exception("Failed to retrieve data");
}
}
}
void showPassword(wstring_t(*pwdfunc)(), char const* pwdname)
{
wstring_t pwd;
try
{
pwd = pwdfunc();
if(!pwd.empty())
{
std::cout << "[" << pwdname << " = ";
std::wcout << pwd;
std::cout << "]" << std::endl;
}
else
{
std::cout << "No " << pwdname << std::endl;
}
}
catch(std::exception& ex)
{
std::cout << "[" << pwdname << "] Exception: " << ex.what() << std::endl;
}
catch(...)
{
std::cout << "[" << pwdname << "] Unknown exception" << std::endl;
}
}
int main()
{
showPassword(&getSecretPwd, "Secret Password");
showPassword(&getRegistryPwd, "Default Password");
return 0;
}
答案2
有一些产品可以检索 Windows AutoLogon 密码,但您可能需要暂时禁用 Defender 的实时保护,以免它将其检测为病毒。
以下列出几个:
从这两款产品来看,我更信赖Nirsoft。