- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我有一个正在运行的服务,并且想访问像启动这样的普通用户文件夹。为此我想为系统上的每个用户(包括注销)扩展环境变量,如 %APPDATA%
。我可以获得已登录用户的 session ID 并从中创建一个 token ,然后调用 ExpandEnvironmentStringsForUser()
。但是注销的用户呢?他们不会有 session 。我唯一能为他们得到的是帐户名(使用 NetUserEnum()
或 NetQueryDisplayInformation()
) 和来自注册表的 SID (HKLM\software\Microst\Windows NT\current Version\Profile List
)我能否从 SID 获取用户 token 或使用 SID 模拟用户,或者是否有某种方法可以使用 SID 扩展环境变量。
编辑:我需要从所有用户的启动位置删除一些文件。为此,我需要在每个用户的上下文中展开 %APPDATA%
和 %USERPROFILE%
,无论是登录还是不是。
编辑 2:问题归结为为不同的用户扩展环境变量,如 %APPDATA%
而没有该用户的 token 。
最佳答案
从任何给定的 SID 创建 token 是可能的,但不是简单的。存在用于创建 token 的未记录的系统 api:
extern "C" NTSYSCALLAPI NTSTATUS NTAPI NtCreateToken(
_Out_ PHANDLE TokenHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
_In_ TOKEN_TYPE TokenType,
_In_ PLUID AuthenticationId,
_In_ PLARGE_INTEGER ExpirationTime,
_In_ PTOKEN_USER User,
_In_ PTOKEN_GROUPS Groups,
_In_ PTOKEN_PRIVILEGES Privileges,
_In_opt_ PTOKEN_OWNER Owner,
_In_ PTOKEN_PRIMARY_GROUP PrimaryGroup,
_In_opt_ PTOKEN_DEFAULT_DACL DefaultDacl,
_In_ PTOKEN_SOURCE TokenSource
);
这里 AuthenticationId 必须是一些有效的登录 session ID,否则我们会收到 STATUS_NO_SUCH_LOGON_SESSION
错误。例如,我们可以从当前流程 token 中获取此值。所有其他参数,通常可以是任何有效的感知数据。所以可以用下一种方式创建 token :
NTSTATUS CreateUserToken(PHANDLE phToken, PSID Sid)
{
HANDLE hToken;
NTSTATUS status = NtOpenProcessToken(NtCurrentProcess(), TOKEN_QUERY, &hToken);
if (0 <= status)
{
TOKEN_STATISTICS ts;
status = NtQueryInformationToken(hToken, TokenStatistics, &ts, sizeof(ts), &ts.DynamicCharged);
NtClose(hToken);
if (0 <= status)
{
TOKEN_PRIMARY_GROUP tpg = { Sid };
TOKEN_USER User = { { Sid } };
static TOKEN_SOURCE Source = { { "User32 "} };
static TOKEN_DEFAULT_DACL tdd;
static _SID EveryOne = { SID_REVISION, 1, SECURITY_WORLD_SID_AUTHORITY, { SECURITY_WORLD_RID } };
static TOKEN_GROUPS Groups = { 1, { { &EveryOne, SE_GROUP_ENABLED|SE_GROUP_MANDATORY } } };
struct TOKEN_PRIVILEGES_3 {
ULONG PrivilegeCount;
LUID_AND_ATTRIBUTES Privileges[3];
} Privileges = {
3, {
{ { SE_BACKUP_PRIVILEGE }, SE_PRIVILEGE_ENABLED|SE_PRIVILEGE_ENABLED_BY_DEFAULT },
{ { SE_RESTORE_PRIVILEGE }, SE_PRIVILEGE_ENABLED|SE_PRIVILEGE_ENABLED_BY_DEFAULT },
{ { SE_CHANGE_NOTIFY_PRIVILEGE }, SE_PRIVILEGE_ENABLED|SE_PRIVILEGE_ENABLED_BY_DEFAULT }
}
};
static SECURITY_QUALITY_OF_SERVICE sqos = {
sizeof sqos, SecurityImpersonation, SECURITY_DYNAMIC_TRACKING
};
static OBJECT_ATTRIBUTES oa = {
sizeof oa, 0, 0, 0, 0, &sqos
};
status = NtCreateToken(phToken, TOKEN_ALL_ACCESS, &oa, TokenImpersonation,
&ts.AuthenticationId, &ts.ExpirationTime, &User, &Groups, (PTOKEN_PRIVILEGES)&Privileges, 0,
&tpg, &tdd, &Source);
}
}
return status;
}
此 token 将被赋予 SID 作为 token 用户 sid,3 权限(SE_BACKUP_PRIVILEGE
,SE_RESTORE_PRIVILEGE
- 这需要调用 LoadUserProfile
api 和 SE_CHANGE_NOTIFY_PRIVILEGE
具有遍历权限)和一组 - 所有人 (s-1-1-0)。
但是对于调用 NtCreateToken
我们必须有 SE_CREATE_TOKEN_PRIVILEGE
权限否则我们会得到错误 STATUS_PRIVILEGE_NOT_HELD
。大多数系统进程都没有。只有少数(如 lsass.exe)。说 services.exe 和所有服务 - 没有这个特权。所以一开始我们必须得到它。这可以通过枚举进程来完成,看看 - 它具有此特权,从该进程获取 token ,并用它模拟:
BOOL g_IsXP;// true if we on winXP, false otherwise
static volatile UCHAR guz;
OBJECT_ATTRIBUTES zoa = { sizeof zoa };
NTSTATUS ImpersonateIfConformToken(HANDLE hToken)
{
ULONG cb = 0, rcb = 0x200;
PVOID stack = alloca(guz);zoa;
union {
PVOID buf;
PTOKEN_PRIVILEGES ptp;
};
NTSTATUS status;
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
if (0 <= (status = NtQueryInformationToken(hToken, TokenPrivileges, buf, cb, &rcb)))
{
if (ULONG PrivilegeCount = ptp->PrivilegeCount)
{
ULONG n = 1;
BOOL bNeedAdjust = FALSE;
PLUID_AND_ATTRIBUTES Privileges = ptp->Privileges;
do
{
if (!Privileges->Luid.HighPart)
{
switch (Privileges->Luid.LowPart)
{
case SE_CREATE_TOKEN_PRIVILEGE:
if (!(Privileges->Attributes & SE_PRIVILEGE_ENABLED))
{
Privileges->Attributes |= SE_PRIVILEGE_ENABLED;
bNeedAdjust = TRUE;
}
if (!--n)
{
static SECURITY_QUALITY_OF_SERVICE sqos = {
sizeof sqos, SecurityImpersonation, SECURITY_STATIC_TRACKING, FALSE
};
static OBJECT_ATTRIBUTES soa = { sizeof(soa), 0, 0, 0, 0, &sqos };
if (0 <= (status = NtDuplicateToken(hToken, TOKEN_ADJUST_PRIVILEGES|TOKEN_IMPERSONATE, &soa, FALSE, TokenImpersonation, &hToken)))
{
if (bNeedAdjust)
{
status = NtAdjustPrivilegesToken(hToken, FALSE, ptp, 0, 0, 0);
}
if (status == STATUS_SUCCESS)
{
status = NtSetInformationThread(NtCurrentThread(), ThreadImpersonationToken, &hToken, sizeof(HANDLE));
}
NtClose(hToken);
}
return status;
}
break;
}
}
} while (Privileges++, --PrivilegeCount);
}
return STATUS_PRIVILEGE_NOT_HELD;
}
} while (status == STATUS_BUFFER_TOO_SMALL);
return status;
}
NTSTATUS GetCreateTokenPrivilege()
{
BOOLEAN b;
NTSTATUS status = RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE, TRUE, FALSE, &b);
ULONG cb = 0x10000;
do
{
status = STATUS_INSUFF_SERVER_RESOURCES;
if (PVOID buf = LocalAlloc(0, cb))
{
if (0 <= (status = NtQuerySystemInformation(SystemProcessInformation, buf, cb, &cb)))
{
status = STATUS_UNSUCCESSFUL;
ULONG NextEntryOffset = 0;
union {
PVOID pv;
PBYTE pb;
PSYSTEM_PROCESS_INFORMATION pspi;
};
pv = buf;
do
{
pb += NextEntryOffset;
HANDLE hProcess, hToken;
if (pspi->UniqueProcessId && pspi->NumberOfThreads)
{
NTSTATUS s = NtOpenProcess(&hProcess,
g_xp ? PROCESS_QUERY_INFORMATION : PROCESS_QUERY_LIMITED_INFORMATION,
&zoa, &pspi->TH->ClientId);
if (0 <= s)
{
s = NtOpenProcessToken(hProcess, TOKEN_DUPLICATE|TOKEN_QUERY, &hToken);
NtClose(hProcess);
if (0 <= s)
{
s = ImpersonateIfConformToken(hToken);
NtClose(hToken);
if (0 <= s)
{
status = STATUS_SUCCESS;
break;
}
}
}
}
} while (NextEntryOffset = pspi->NextEntryOffset);
}
LocalFree(buf);
}
} while (status == STATUS_INFO_LENGTH_MISMATCH);
return status;
}
在我们获得 SE_CREATE_TOKEN_PRIVILEGE
权限后,我们可以通过这种方式获得一些已知的文件夹路径:
HRESULT GetGetKnownFolderPathBySid(REFKNOWNFOLDERID rfid, PSID Sid, PWSTR *ppszPath)
{
PROFILEINFO pi = { sizeof(pi), PI_NOUI };
pi.lpUserName = L"*";
HANDLE hToken;
NTSTATUS status = CreateUserToken(&hToken, Sid);
if (0 <= status)
{
if (LoadUserProfile(hToken, &pi))
{
status = SHGetKnownFolderPath(rfid, 0, hToken, ppszPath);
UnloadUserProfile(hToken, pi.hProfile);
}
else
{
status = HRESULT_FROM_WIN32(GetLastError());
}
CloseHandle(hToken);
}
else
{
status = HRESULT_FROM_NT(status);
}
return status;
}
例如获取 %AppData%
void PrintAppDataBySid(PSID Sid)
{
PWSTR path, szSid;
if (S_OK == GetGetKnownFolderPathBySid(FOLDERID_RoamingAppData, Sid, &path))
{
if (ConvertSidToStringSidW(Sid, &szSid))
{
DbgPrint("%S %S\n", szSid, path);
LocalFree(szSid);
}
CoTaskMemFree(path);
}
}
最后我们可以枚举本地用户配置文件并为每个找到的 sid 获取它的 appdata 路径:
void EnumProf()
{
STATIC_OBJECT_ATTRIBUTES(soa, "\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList");
UNICODE_STRING ObjectName;
OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, &ObjectName, OBJ_CASE_INSENSITIVE };
if (0 <= ZwOpenKey(&oa.RootDirectory, KEY_READ, &soa))
{
PVOID stack = alloca(sizeof(WCHAR));
union
{
PVOID buf;
PKEY_BASIC_INFORMATION pkbi;
PKEY_VALUE_PARTIAL_INFORMATION pkvpi;
};
DWORD cb = 0, rcb = 16;
NTSTATUS status;
ULONG Index = 0;
do
{
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
if (0 <= (status = ZwEnumerateKey(oa.RootDirectory, Index, KeyBasicInformation, buf, cb, &rcb)))
{
*(PWSTR)RtlOffsetToPointer(pkbi->Name, pkbi->NameLength) = 0;
PSID _Sid, Sid = 0;
BOOL fOk = ConvertStringSidToSidW(pkbi->Name, &_Sid);
if (fOk)
{
Sid = _Sid;
}
ObjectName.Buffer = pkbi->Name;
ObjectName.Length = (USHORT)pkbi->NameLength;
HANDLE hKey;
if (0 <= ZwOpenKey(&hKey, KEY_READ, &oa))
{
rcb = 64;
NTSTATUS s;
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
STATIC_UNICODE_STRING(usSid, "Sid");
if (0 <= (s = ZwQueryValueKey(hKey, &usSid, KeyValuePartialInformation, buf, cb, &rcb)))
{
if (pkvpi->DataLength >= sizeof(_SID) &&
IsValidSid(pkvpi->Data) &&
GetLengthSid(pkvpi->Data) == pkvpi->DataLength)
{
Sid = pkvpi->Data;
}
}
} while (s == STATUS_BUFFER_OVERFLOW);
NtClose(hKey);
}
if (Sid)
{
PrintAppDataBySid(Sid);
}
if (fOk)
{
LocalFree(_Sid);
}
}
} while (status == STATUS_BUFFER_OVERFLOW);
Index++;
} while (0 <= status);
NtClose(oa.RootDirectory);
}
}
例如我得到下一个结果:
S-1-5-18 C:\Windows\system32\config\systemprofile\AppData\Roaming
S-1-5-19 C:\Windows\ServiceProfiles\LocalService\AppData\Roaming
S-1-5-20 C:\Windows\ServiceProfiles\NetworkService\AppData\Roaming
S-1-5-21-*-1000 C:\Users\defaultuser0\AppData\Roaming
S-1-5-21-*-1001 C:\Users\<user>\AppData\Roaming
关于c++ - 从 SID 创建用户 token ,在用户上下文中扩展环境变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47412590/
在为 Web 应用程序用例图建模时,为用户可以拥有的每个角色创建一个角色是否更好?或拥有一个角色、用户和一个具有特权的矩阵? guest < 用户 < 版主 < 管理员 1: guest 、用户、版主
我无法使用 Elixir 连接到 Postgres: ** (Mix) The database for PhoenixChat.Repo couldn't be created: FATAL 28P
这个问题已经有答案了: Group by field name in Java (7 个回答) 已关闭 7 年前。 我必须编写一个需要 List 的方法并返回 Map> . User包含 Person
感谢您的帮助,首先我将显示代码: $dotaz = "Select * from customers JOIN contracts where customers.user_id ='".$_SESS
我只想向所有用户中的一个用户显示一个按钮。我尝试了 orderByKey() 但没有成功! 用户模型有 id 成员,我尝试使用 orderByChild("id") 但结果相同! 我什至尝试了以下技巧
我们在工作中从 MongoDB 切换到 Postgres,我正在建立一个 BDR 组。 在这一步,我正在考虑安全性并尽可能锁定。因此,我希望设置一个 replication 用户(角色)并让 BDR
export class UserListComponent implements OnInit{ users; constructor(private userService: UserS
我可以使用 Sonata User Bundle 将 FOS 包集成到 sonata Admin 包中。我的登录功能正常。现在我想添加 FOSUserBundle 中的更改密码等功能到 sonata
在 LinkedIn 中创建新应用程序时,我得到 4 个单独的代码: API key 秘钥 OAuth 用户 token OAuth 用户密码 我在 OAuth 流程中使用前两个。 的目的是什么?最后
所以..我几乎解决了所有问题。但现在我要处理另一个问题。我使用了这个连接字符串: SqlConnection con = new SqlConnection(@"Data Source=.\SQLEX
我有一组“用户”和一组“订单”。我想列出每个 user_id 的所有 order_id。 var users = { 0: { user_id: 111, us
我已经为我的Django应用创建了一个用户模型 class User(Model): """ The Authentication model. This contains the u
我被这个问题困住了,找不到解决方案。寻找一些方向。我正在用 laravel 开发一个新的项目,目前正致力于用户认证。我正在使用 Laravels 5.8 身份验证模块。 对密码恢复 View 做了一些
安装后我正在使用ansible配置几台计算机。 为此,我在机器上本地运行 ansible。安装中的“主要”用户通常具有不同的名称。我想将该用户用于诸如 become_user 之类的变量. “主要”用
我正在尝试制作一个运行 syncdb 的批处理文件来创建一个数据库文件,然后使用用户名“admin”和密码“admin”创建一个 super 用户。 到目前为止我的代码: python manage.
关闭。这个问题是opinion-based 。目前不接受答案。 想要改进这个问题吗?更新问题,以便 editing this post 可以用事实和引文来回答它。 . 已关闭 6 年前。 Improv
我已在 Azure 数据库服务器上设置异地复制。 服务器上运行的数据库之一具有我通过 SSMS 创建的登录名和用户: https://learn.microsoft.com/en-us/azure/s
我有一个 ionic 2 应用程序,正在使用 native FB Login 来检索名称/图片并将其保存到 NativeStorage。流程是我打开WelcomePage、登录并保存数据。从那里,na
这是我的用户身份验证方法: def user_login(request): if request.method == 'POST': username = request.P
我试图获取来自特定用户的所有推文,但是当我迭代在模板中抛出推文时,我得到“User”对象不可迭代 观看次数 tweets = User.objects.get(username__iexact='us
我是一名优秀的程序员,十分优秀!