gpt4 book ai didi

c++ - 如何为循环中的所有用户加载注册表配置单元

转载 作者:行者123 更新时间:2023-11-28 01:58:42 28 4
gpt4 key购买 nike

使用管理员权限,我需要枚举 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过程。所以一个可能的解决方案是:

  1. 打开lsass.exe并获取其 token ,或模拟其线程。
  2. 启用SE_CREATE_TOKEN_PRIVILEGE在 token 中,在模拟之后
  3. 枚举HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows
    NT\CurrentVersion\ProfileList
    ,并为每个子项查询其 Sid值,或者(如果 Sid 不存在)使用 ConvertStringSidToSid() 将子项名称转换为 SID
  4. 使用该 SID 创建 token
  5. 最后调用LoadUserProfile()

---------------- 按要求编辑代码示例------------------------ ---

代码使用了 ntdll 导出(这里有人非常不喜欢)但原样

  1. 我们需要 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/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com