如果我被模拟,为啥 Win32 API 函数 CredEnumerate() 返回 ERROR_NOT_FOUND?
Posted
技术标签:
【中文标题】如果我被模拟,为啥 Win32 API 函数 CredEnumerate() 返回 ERROR_NOT_FOUND?【英文标题】:Why does Win32 API function CredEnumerate() return ERROR_NOT_FOUND if I'm impersonated?如果我被模拟,为什么 Win32 API 函数 CredEnumerate() 返回 ERROR_NOT_FOUND? 【发布时间】:2010-09-09 16:08:47 【问题描述】:我编写了一些示例代码,当我在普通用户帐户的上下文中从 Windows 命令提示符调用时,使用 CredEnumerate() 转储所有用户保存的凭据。但是,我真的希望能够从 SYSTEM 用户上下文中执行此操作,因此我已经从 SYSTEM cmd 提示符测试了我的程序。
当我以 SYSTEM 身份运行程序时,我会像这样运行 LogonUser:
bLoggedOn = LogonUser(userName.c_str(), domain.c_str(), password.c_str(), LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &userToken_);
然后我在令牌上运行 ImpersonateLoggedOnUser() 以提供本地用户的安全上下文。之后我会这样做:
bOk = CredEnumerate(NULL, 0, &count, &pCredentials);
而且我希望这会以与我没有从系统进入并被冒充一样的方式返回凭据。任何人都可以发现我错过的任何东西以真正将自己置于用户的上下文中吗?
【问题讨论】:
这些凭据是否存储在注册表中?也许您需要在调用 CredEnumerate 之前加载用户的注册表配置单元。您可以使用 Process Monitor 来查看是否发生了这种情况。 嗯,这是个好主意,但我没有考虑过。但是,即使我在模拟的用户实际登录时使用 psexec 启动系统属性,我实际上也遇到了同样的问题。大概在那种情况下,用户的注册表配置单元已经加载。 凭证管理 API 的文档似乎表明这些凭证与登录会话相关联。也许 LogonUser 会导致新的登录会话,因此那里不存在凭据。您可以通过使用现有令牌调用 ImpersonateLoggedOnUser() 来测试这一点,而不是通过 LogonUser() 获取一个。 【参考方案1】:我想我自己应该回答这个问题,因为我现在已经花了很长时间研究如何做到这一点,但我不确定它是否广为人知。 CredEnumerate/CredRead 永远不会提供域密码的密码信息,无论您处于什么进程上下文或您拥有什么令牌,尽管它似乎在 MSDN 上暗示了什么。访问保存的凭证信息的唯一方法是使用 lsasrv.dll 中未记录的函数 LSAICryptUnprotectData()。这可以解密您在 %APPDATA%\Microsoft\Credentials 中找到的文件,并且可以提供与 CredEnumerate 相同的数据结构,除了填写密码。唯一的问题是这必须在 lsass.exe 的进程上下文中完成( Windows 安全子系统),没有设置权限等足以让正常进程有权执行此操作。如果您是一名黑客,您可以通过执行 CreateRemoteThread() 将线程注入 lsass.exe 来执行此操作,或者如果您尝试以合法方式执行此操作,即您正在以某种方式扩展 Windows 操作系统对于像我一样的第三方应用程序,您可以通过创建一个 lsass 将加载的 Windows 身份验证包来做到这一点。然后,此 AP 可以使用命名管道或某种此类方法来允许与您的其余代码进行交互。
【讨论】:
以上是关于如果我被模拟,为啥 Win32 API 函数 CredEnumerate() 返回 ERROR_NOT_FOUND?的主要内容,如果未能解决你的问题,请参考以下文章
stm32 RCC_CR上电为啥不是复位0X0000xx83值?
GVim Win32 中的仅键盘列块选择,或者当包含 mswin.vim 时,为啥 Ctrl-Q 不模拟 Ctrl-V?
C#-使用Win32_API的SendMessage实现指定窗口的模拟点击操作