我遇到了Google Chrome和一些密码管理器(如KeePass)中使用的“安全桌面”概念。在Chrome中,安全桌面是用于Chrome进程且受访问限制的桌面,并且受到良好保护;在KeePass中,所谓的安全桌面用于主密码对话框。但是在KeePass中,似乎他们只是创建了另一个桌面而没有设置任何DACL来真正保护它。对我来说,安全桌面是指在同一桌面上运行的任何其他进程都无法打开和输入的东西。
我问自己,是否可能有一个单独的桌面,您可以在其中启动应用程序并将其与其他进程分开。这包括被攻击者滥用以收集按键或屏幕的已收获应用程序。
使用API函数CreateDesktop,ConvertStringSecurityDescriptorToSecurityDescriptor和SetUserObjectSecurity,我可以创建另一个桌面并减少访问权限。但是,如果我太严格,则无法在其中启动进程;如果我太粗心,新创建的桌面也太开放,那么攻击者可以打开桌面并将其线程切换到该桌面。
你们中的每个人都知道我可以使用的SecurityDescriptor字符串组合,这样才能真正保护新创建的桌面,以便除创建者进程及其在受保护的桌面中运行进程的子进程以外的其他应用程序都不能在那里切换和创建流程?
任何建议或提示都非常受欢迎。
假设:
这是我当前正在使用的代码:
#include <windows.h>
#include <stdio.h>
#include <Sddl.h>
#include <AclAPI.h>
#include <time.h>
static const unsigned char nameCharTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-[]()<>@~#.:%&$§=";
// create new desktop or open an already existing one
HDESK CreateHiddenDesktop(CHAR *desktop_name)
{
CHAR explorer_path[MAX_PATH];
HDESK hNewDesktop = NULL, hOldDesktop;
STARTUPINFOA startup_info = { 0 };
PROCESS_INFORMATION process_info = { 0 };
ExpandEnvironmentStringsA("%windir%\\notepad.exe", explorer_path, MAX_PATH - 1);
hNewDesktop = OpenDesktopA(desktop_name, NULL, FALSE, GENERIC_ALL);
if (!hNewDesktop)
{
hNewDesktop = CreateDesktopA(desktop_name, NULL, NULL, 0, GENERIC_ALL, NULL);
if (hNewDesktop)
{
hOldDesktop = GetThreadDesktop(GetCurrentThreadId());
if (SetThreadDesktop(hNewDesktop))
{
BOOL bRet = FALSE;
PSECURITY_DESCRIPTOR SecDes = NULL;
// just for us to obtain hex values we can use with ConvertStringSecurityDescriptorToSecurityDescriptor
DWORD access = DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER | DESKTOP_CREATEMENU |
DESKTOP_CREATEWINDOW | DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL |
DESKTOP_READOBJECTS | DESKTOP_SWITCHDESKTOP | DESKTOP_WRITEOBJECTS | ACCESS_SYSTEM_SECURITY;
access = DESKTOP_ENUMERATE | WRITE_DAC | WRITE_OWNER | ACCESS_SYSTEM_SECURITY;
printf("Access mask in hex: 0x%08x.\n", access);
//bRet = ConvertStringSecurityDescriptorToSecurityDescriptor(TEXT("D:P(D;OICI;GARCSDWDWO;;;WD)(A;OICI;GAGRGWGXRCSDWDWOWPCCCR;;;CO)"), SDDL_REVISION_1, &SecDes, NULL);
bRet = ConvertStringSecurityDescriptorToSecurityDescriptor(TEXT("D:P(OD;OICI;0x010c0040;;;WD)(OA;OICI;0xffffffff;;;WD)"), SDDL_REVISION_1, &SecDes, NULL);
if (bRet)
{
BOOL bSaclDefaulted = FALSE;
BOOL bSaclPresent = FALSE;
PACL SecACL = NULL;
SECURITY_INFORMATION si;
si = DACL_SECURITY_INFORMATION;
if (SetUserObjectSecurity(hNewDesktop, &si, SecDes)) {
printf("SetUserObjectSecurity succeeded.\n");
}
}
// create process and wait until it is initialized and ready
startup_info.cb = sizeof(startup_info);
startup_info.lpDesktop = desktop_name;
CreateProcessA(explorer_path, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &startup_info, &process_info);
WaitForInputIdle(process_info.hProcess, INFINITE);
// handles in PROCESS_INFORMATION must be closed with CloseHandle when they are no longer needed.
CloseHandle(process_info.hProcess);
CloseHandle(process_info.hThread);
SetThreadDesktop(hOldDesktop);
}
}
}
return hNewDesktop;
}
int main(int argc, char **argv) {
HDESK hOldDesktop, hNewDesktop;
MSG msg = { 0 };
char desktopName[128] = { 0 };
BOOLEAN binNewDesktop = FALSE;
srand((unsigned int)time(NULL));
for (int i = 0; i < 8; i++) {
desktopName[i] = nameCharTable[rand() % (sizeof(nameCharTable)-1)];
}
// just for debugging and testing: print the desktop's name
printf("Desktop's name: %s\n", desktopName);
hNewDesktop = CreateHiddenDesktop(desktopName);
hOldDesktop = GetThreadDesktop(GetCurrentThreadId());
printf("Entering the hidden desktop\n");
// switch thread into context of new desktop to register hotkeys
SetThreadDesktop(hNewDesktop);
SwitchDesktop(hNewDesktop);
binNewDesktop = TRUE;
RegisterHotKey(NULL, 0, MOD_CONTROL | MOD_ALT | MOD_NOREPEAT, 0x53); // S = switch desktop
RegisterHotKey(NULL, 1, MOD_CONTROL | MOD_ALT | MOD_NOREPEAT, 0x51); // Q = quit
while (GetMessage(&msg, NULL, 0, 0) != 0) {
if (msg.message==WM_HOTKEY) {
// switch Desktop hotkey
if (msg.wParam == 0) {
if (binNewDesktop) {
UnregisterHotKey(NULL, 0);
UnregisterHotKey(NULL, 1);
SetThreadDesktop(hOldDesktop);
SwitchDesktop(hOldDesktop);
RegisterHotKey(NULL, 0, MOD_CONTROL | MOD_ALT | MOD_NOREPEAT, 0x53); // S = switch desktop
RegisterHotKey(NULL, 1, MOD_CONTROL | MOD_ALT | MOD_NOREPEAT, 0x51); // Q = quit
binNewDesktop = FALSE;
}
else {
UnregisterHotKey(NULL, 0);
UnregisterHotKey(NULL, 1);
SetThreadDesktop(hNewDesktop);
SwitchDesktop(hNewDesktop);
RegisterHotKey(NULL, 0, MOD_CONTROL | MOD_ALT | MOD_NOREPEAT, 0x53); // S = switch desktop
RegisterHotKey(NULL, 1, MOD_CONTROL | MOD_ALT | MOD_NOREPEAT, 0x51); // Q = quit
binNewDesktop = TRUE;
}
}
// switch Quit hotkey
if (msg.wParam == 1) {
printf("Exiting hidden desktop\n");
UnregisterHotKey(NULL, 0);
UnregisterHotKey(NULL, 1);
SwitchDesktop(hOldDesktop);
SetHandleInformation(hNewDesktop, 0, 0);
SwitchDesktop(hOldDesktop);
CloseDesktop(hNewDesktop);
CloseDesktop(hOldDesktop);
//getchar();
break;
}
}
}
return 0;
}