- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
使用管理员权限,我需要枚举 Windows 7+ 系统上的所有用户(甚至是已注销的用户)。然后我需要为每个用户加载注册表配置单元并设置一个键。
NetUserEnum 为我提供了 SID(我想 LsaEnumerateLogonSessions 也会)。 WTSEnumerateSessions 后跟 WTSQueryUserToken(以获取 token )会很好,但它不适用于未主动登录的用户。
所以,我的问题是,在调用 NetUserEnum 之后,我如何使用 SID 为该用户加载注册表?有什么推荐的方法吗?
最佳答案
有关本地用户配置文件的信息存储在此注册表项中:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList
可以枚举它的子项,其中每个子项都有一个 ProfileImagePath
指向ntuser.dat
所在的文件夹位于。
但是,通过RegLoadKey()
直接加载用户配置文件|很糟糕。首先,配置文件可能已经加载。其次,有可能在您自己加载配置文件后,系统也可能会尝试加载配置文件。注意 RefCount
值(value)。如果尚未加载,系统将使用该值加载配置文件,递增 RefCount
.和 UnloadUserProfile()
减量 RefCount
并仅在配置文件变为 0 时通过调用 RegUnLoadKey()
卸载配置文件.因此所有配置文件加载/卸载操作必须同步。
加载配置文件只有一种正确方法 - 调用 LoadUserProfile()
. (在内部它对 profsvc.LoadUserProfileServer
中的 svchost.exe -k netsvcs
执行 RPC 调用,所有同步都在这里完成)。
那么如何获得 LoadUserProfile()
的用户 token 呢? ?我想调用 LogonUser()
,你说你不想这样做(除非你有用户的密码,否则不能)。
但是,确实存在另一种可行的方法(我对此进行了测试),但它未记录。 LoadUserProfile
仅使用用户 Sid
来自 token (使用 TOKEN_USER
信息类查询 TokenUser
信息)然后使用
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\<Sid>
键
可以通过调用 ZwCreateToken()
创建 token 使用任何给定的 SID,但对于此调用,您需要 SE_CREATE_TOKEN_PRIVILEGE
.此权限仅存在于 lsass.exe
过程。所以一个可能的解决方案是:
lsass.exe
并获取其 token ,或模拟其线程。SE_CREATE_TOKEN_PRIVILEGE
在 token 中,在模拟之后HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows
NT\CurrentVersion\ProfileList
,并为每个子项查询其 Sid
值,或者(如果 Sid
不存在)使用 ConvertStringSidToSid()
将子项名称转换为 SID LoadUserProfile()
---------------- 按要求编辑代码示例------------------------ ---
代码使用了 ntdll 导出(这里有人非常不喜欢)但原样
SE_CREATE_TOKEN_PRIVILEGE
自己创建 token future 枚举系统中的进程,为每个进程打开token,看都是SE_CREATE_TOKEN_PRIVILEGE
存在于 token 中,如果是 - 复制此 token ,如果需要启用 SE_CREATE_TOKEN_PRIVILEGE
在里面。最后用重复的 token 模拟
BOOL g_IsXP;// true if we on winXP, false otherwise
static volatile UCHAR guz;
static OBJECT_ATTRIBUTES zoa = { sizeof(zoa) };
NTSTATUS ImpersonateIfConformToken(HANDLE hToken)
{
ULONG cb = 0, rcb = 0x200;
PVOID stack = alloca(guz);
union {
PVOID buf;
PTOKEN_PRIVILEGES ptp;
};
NTSTATUS status;
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
if (0 <= (status = ZwQueryInformationToken(hToken, TokenPrivileges, buf, cb, &rcb)))
{
if (ULONG PrivilegeCount = ptp->PrivilegeCount)
{
PLUID_AND_ATTRIBUTES Privileges = ptp->Privileges;
do
{
if (Privileges->Luid.LowPart == SE_CREATE_TOKEN_PRIVILEGE && !Privileges->Luid.HighPart)
{
static SECURITY_QUALITY_OF_SERVICE sqos = {
sizeof sqos, SecurityImpersonation, SECURITY_DYNAMIC_TRACKING, FALSE
};
static OBJECT_ATTRIBUTES soa = { sizeof(soa), 0, 0, 0, 0, &sqos };
if (0 <= (status = ZwDuplicateToken(hToken, TOKEN_ADJUST_PRIVILEGES|TOKEN_IMPERSONATE, &soa, FALSE, TokenImpersonation, &hToken)))
{
if (Privileges->Attributes & SE_PRIVILEGE_ENABLED)
{
status = STATUS_SUCCESS;
}
else
{
static TOKEN_PRIVILEGES tp = {
1, { { { SE_CREATE_TOKEN_PRIVILEGE }, SE_PRIVILEGE_ENABLED } }
};
status = ZwAdjustPrivilegesToken(hToken, FALSE, &tp, 0, 0, 0);
}
if (status == STATUS_SUCCESS)
{
status = ZwSetInformationThread(NtCurrentThread(), ThreadImpersonationToken, &hToken, sizeof(HANDLE));
}
ZwClose(hToken);
}
return status;
}
} while (Privileges++, --PrivilegeCount);
}
return STATUS_PRIVILEGE_NOT_HELD;
}
} while (status == STATUS_BUFFER_TOO_SMALL);
return status;
}
NTSTATUS GetCreateTokenPrivilege()
{
BOOLEAN b;
RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE, TRUE, FALSE, &b);
ULONG cb = 0, rcb = 0x10000;
PVOID stack = alloca(guz);
union {
PVOID buf;
PBYTE pb;
PSYSTEM_PROCESS_INFORMATION pspi;
};
NTSTATUS status;
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
if (0 <= (status = ZwQuerySystemInformation(SystemProcessInformation, buf, cb, &rcb)))
{
status = STATUS_UNSUCCESSFUL;
ULONG NextEntryOffset = 0;
do
{
pb += NextEntryOffset;
if (pspi->InheritedFromUniqueProcessId && pspi->UniqueProcessId)
{
CLIENT_ID cid = { pspi->UniqueProcessId };
NTSTATUS s = STATUS_UNSUCCESSFUL;
HANDLE hProcess, hToken;
if (0 <= ZwOpenProcess(&hProcess, g_IsXP ? PROCESS_QUERY_INFORMATION : PROCESS_QUERY_LIMITED_INFORMATION, &zoa, &cid))
{
if (0 <= ZwOpenProcessToken(hProcess, TOKEN_DUPLICATE|TOKEN_QUERY, &hToken))
{
s = ImpersonateIfConformToken(hToken);
NtClose(hToken);
}
NtClose(hProcess);
}
if (s == STATUS_SUCCESS)
{
return STATUS_SUCCESS;
}
}
} while (NextEntryOffset = pspi->NextEntryOffset);
return status;
}
} while (status == STATUS_INFO_LENGTH_MISMATCH);
return STATUS_UNSUCCESSFUL;
}
如果我们有SE_CREATE_TOKEN_PRIVILEGE
- 我们可以创建 token !
NTSTATUS CreateUserToken(PHANDLE phToken, PSID Sid)
{
HANDLE hToken;
TOKEN_STATISTICS ts;
NTSTATUS status = ZwOpenProcessToken(NtCurrentProcess(), TOKEN_QUERY, &hToken);
if (0 <= status)
{
if (0 <= (status = ZwQueryInformationToken(hToken, TokenStatistics, &ts, sizeof(ts), &ts.DynamicCharged)))
{
ULONG cb = 0, rcb = 0x200;
PVOID stack = alloca(guz);
union {
PVOID buf;
PTOKEN_PRIVILEGES ptp;
};
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
if (0 <= (status = ZwQueryInformationToken(hToken, TokenPrivileges, buf, cb, &rcb)))
{
TOKEN_USER User = { { Sid } };
static TOKEN_SOURCE Source = { {' ','U','s','e','r','3','2', ' '} };
static TOKEN_DEFAULT_DACL tdd;// 0 default DACL
static TOKEN_GROUPS Groups;// no groups
static SECURITY_QUALITY_OF_SERVICE sqos = {
sizeof sqos, SecurityImpersonation, SECURITY_DYNAMIC_TRACKING
};
static OBJECT_ATTRIBUTES oa = {
sizeof oa, 0, 0, 0, 0, &sqos
};
status = ZwCreateToken(phToken, TOKEN_ALL_ACCESS, &oa, TokenPrimary,
&ts.AuthenticationId, &ts.ExpirationTime, &User, &Groups, ptp, (PTOKEN_OWNER)&Sid,
(PTOKEN_PRIMARY_GROUP)&Sid, &tdd, &Source);
break;
}
} while (status == STATUS_BUFFER_TOO_SMALL);
}
ZwClose(hToken);
}
return status;
}
最后枚举和加载/卸载用户配置文件
void EnumProf()
{
PROFILEINFO pi = { sizeof(pi), PI_NOUI };
pi.lpUserName = L"*";
STATIC_OBJECT_ATTRIBUTES(soa, "\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList");
HANDLE hKey;
if (0 <= ZwOpenKey(&hKey, KEY_READ, &soa))
{
PVOID stack = alloca(sizeof(WCHAR));
union
{
PVOID buf;
PKEY_BASIC_INFORMATION pkbi;
PKEY_VALUE_PARTIAL_INFORMATION pkvpi;
} u = {};
DWORD cb = 0, rcb = 64;
NTSTATUS status;
ULONG Index = 0;
do
{
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(u.buf = alloca(rcb - cb), stack);
}
if (0 <= (status = ZwEnumerateKey(hKey, Index, KeyBasicInformation, u.buf, cb, &rcb)))
{
*(PWSTR)RtlOffsetToPointer(u.pkbi->Name, u.pkbi->NameLength) = 0;
PSID Sid;
if (ConvertStringSidToSidW(u.pkbi->Name, &Sid))
{
HANDLE hToken;
if (0 <= CreateUserToken(&hToken, Sid))
{
if (LoadUserProfile(hToken, &pi))
{
UnloadUserProfile(hToken, pi.hProfile);
}
NtClose(hToken);
}
LocalFree(Sid);
}
}
} while (status == STATUS_BUFFER_OVERFLOW);
Index++;
} while (0 <= status);
ZwClose(hKey);
}
}
关于c++ - 如何为循环中的所有用户加载注册表配置单元,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40325495/
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 6 年前。
如何打开注册表 Win98/98SE/Me 运行中输入regedit.exe 无权限限制 Win2000/XP 1·开始>>运行.中输入regedit 2.运行中
目录 前言 使用简单工厂改进 使用注册表改进 参考文章 前言 在上一篇文章中我们提到了抽象工厂模式初版代码的一些缺点:①客户端违反开闭原则②提供方违反开
目录 工厂方法模式的瑕疵 注册表 工厂方法模式的瑕疵 在前一篇笔记中我们介绍了工厂方法模式,示例的类图如下: 考虑一种情况:现在要在程序运行时,根据外部资源
我在一个带有一个主节点和两个节点的 AWS 集群中安装了 mesosphere,分别称为主节点、节点 1 和节点 2。主节点是可见的,节点是私有(private)的。 我得到一个默认运行的马拉松实例和
我想用 PHP 制作一个注册表,将他们的用户名和密码注册到我的 SQL 数据库中。这是我所拥有的: 配置.php: 索引.php: Deltalus Account Regi
我正在尝试将我的软件添加到注册表中,我找到了一些我可以使用的代码,但不是完整的工作代码 C/C++ 对我来说是新的,无法自己创建它。但基本思想是:检查 reg key 是否已设置(如果未创建)。 我能
我尝试创建一个注册 php 代码,这样当我不在计算机旁时我就可以注册人们,但由于某种原因,它不会创建表,也不会创建文件夹,即使不存在。 输出是: ( ! ) Notice: Undefined var
我使用 HKLM\Software\etc\etc 来存储我的基本设置,这基本上是我的程序及其相关数据库的位置。 我现在遇到的问题是我已经创建了一个 Windows 服务并且需要读取这些位置。我无法将
我正在尝试将我的软件添加到注册表中,我找到了一些我可以使用的代码片段,但不是完整的工作代码 C/C++ 对我来说是新的,我无法自己创建它。但这里是基本的想法:如果没有创建它,请检查是否设置了注册键。
1、保存以下代码到:c:\windows\system32\vdm.vbs 复制代码 代码如下: Dim Args Set Args = WScript.Argum
不懂注册表、VBS、批处理不要紧,只要会学、会吸收别人的精华,会查找资料,|论坛|百度|GOOGLE|,然后能用好,就非常不错了 贴一些搜集的文字放到这吧。(绿色是标题, 蓝色的是原作者
(绿色是标题, 蓝色的是原作者,红色的部分就是需要修改的部分,根据你自己的实际情况修改) ======打开迅闪菜单的同时连接虚拟磁盘的VBS====== Set WshShell = WScrip
简单使用 复制代码 代码如下: <?php require_once("Zend/Loader.php"); Zend_Loader::loadCl
但并不是每次都打开同一个键值,在每多时候我们还是习惯于Windows 98那样每次打开都在根目录中。 通过修改注册表可以达到这样的效果。打开HKEY_CURRENT_USER\Software\M
何谓REG文件 REG文件实际上是一种注册表脚本文件,双击REG文件即可将其中的数据导入到注册表中。利用REG文件我们可以直接对注册表进行任何修改操作,它对注册表的操作可以不受注册表编辑器被禁用的
我应该将哪些数据和位置添加到 Windows 注册表中以正确创建文件关联? 我问这个问题主要是因为我多年前编写的一些旧应用程序使用 Visual Studio .NET 的 Windows Insta
我想阻止对默认 docker.io 注册表的访问。为了安全/IP 保护,我们需要阻止对公共(public) Docker 集线器的推/拉访问。 已有许多尝试将此作为配置选项,但所有 PR 都不断被拒绝
Lua 提供了一个 "registry" “任何 C 代码都可以使用它来存储它需要存储的任何 Lua 值”。正如 here 所说,线程“与原始线程共享其全局环境” .但是我找不到任何地方说它是否共享注
我的软件在 HKCU\Software\mysoftware 中存储了一些值,这从来都不是问题。但是,我现在还在 HKCU\Software\mysoftware\Licenses 中存储了一些值 -
我是一名优秀的程序员,十分优秀!