如果您希望一次仅限于单个用户,最合乎逻辑的解决方案 - 在公共全局命名空间中创建一些命名对象(对所有人可见)并只允许具体用户 Sid 访问它目的。结果,由同一用户运行的所有实例都可以打开此对象,当另一个用户将拥有另一个 Sid 并且如果它已经存在,则可能无法打开它。我们不是强制需要互斥锁。最好用的命名事件——这是最简单的小对象。还需要使用不是CreateEvent api 而是CreateEventExW,因为它可以指定 dwDesiredAccess - 这在某些代码将以低/不受信任的完整性运行的情况下很重要。他无法打开具有所有访问权限的现有对象(如果我们不向对象添加不受信任的标签),但可以打开具有通用读取/通用执行访问权限的对象。我们可以说只请求SYNCHRONIZE 访问事件。 poc代码:
ULONG BOOL_TO_ERROR(BOOL f)
{
return f ? NOERROR : GetLastError();
}
volatile UCHAR guz = 0;
ULONG CanRun(BOOL& bCan)
{
bCan = false;
HANDLE hToken;
ULONG dwError = BOOL_TO_ERROR(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken));
if (dwError == NOERROR)
{
ULONG cb = 0, rcb = sizeof(TOKEN_USER) + GetSidLengthRequired(5);
PVOID stack = alloca(guz);
union {
PVOID buf;
PTOKEN_USER User;
};
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
dwError = BOOL_TO_ERROR(GetTokenInformation(hToken, TokenUser, buf, cb, &rcb));
} while (dwError == ERROR_INSUFFICIENT_BUFFER);
CloseHandle(hToken);
if (dwError == NOERROR)
{
PSID UserSid = User->User.Sid;
SECURITY_DESCRIPTOR sd;
SECURITY_ATTRIBUTES sa = { sizeof(sa), &sd, FALSE };
PACL Dacl = (PACL)alloca(cb = sizeof(ACL) + FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + GetLengthSid(UserSid));
if (
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION) &&
InitializeAcl(Dacl, cb, ACL_REVISION) &&
AddAccessAllowedAce(Dacl, ACL_REVISION, GENERIC_ALL, UserSid) &&
SetSecurityDescriptorDacl(&sd, TRUE, Dacl, FALSE) &&
CreateEventExW(&sa, L"Global\\<Your Unique Name>", CREATE_EVENT_MANUAL_RESET, SYNCHRONIZE)
)
{
bCan = true;
}
else
{
switch (dwError = GetLastError())
{
case ERROR_ACCESS_DENIED:
dwError = NOERROR;
break;
}
}
}
}
return dwError;
}
所以我们从当前进程令牌中查询TOKEN_USER 并创建(或打开)命名事件"Global\\<Your Unique Name>"。如果甚至不存在 - 我们创建它并分配 SD 只允许同一个用户 sid 打开它。任何其他用户(甚至本地系统)都无法使用ERROR_ACCESS_DENIED 打开此事件(无需先更改 dacl)。
演示用法:
BOOL bCan;
ULONG dwError = CanRun(bCan);
if (dwError == NOERROR)
{
MessageBoxW(0, 0, bCan ? L"Yes" : L"No", bCan ? MB_ICONINFORMATION : MB_ICONWARNING);
}
else
{
PWSTR sz;
if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, 0, dwError, 0, (PWSTR)&sz, 0, 0))
{
MessageBoxW(0, sz, 0, MB_ICONHAND);
LocalFree(sz);
}
}