Created
July 9, 2025 13:11
-
-
Save caloni/13a3e806debd752d10b106ec34b4d572 to your computer and use it in GitHub Desktop.
Win32 GUI "control‑center" that can spawn further copies of itself
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // spawn_control_center.cpp – Win32 GUI "control‑center" that can spawn further | |
| // copies of itself under a (parametrizable) Job Object, optionally at Low‑IL, and | |
| // demonstrates ChangeWindowMessageFilterEx + UserHandleGrantAccess so processes can | |
| // PostMessage across UIPI. | |
| // | |
| // Build (VS Developer Prompt): | |
| // cl /EHsc /W4 /nologo /D_UNICODE /DUNICODE spawn_control_center.cpp \ | |
| // user32.lib advapi32.lib | |
| // | |
| // Notes / How to use at runtime | |
| // -------------------------------- | |
| // 1. Start the EXE once. The initial instance shows its HWND in the upper edit box. | |
| // 2. (Optional) Tick the UI‑limit checkboxes and/or "Low IL" and press **Spawn**. | |
| // – A 2nd copy of the EXE appears (child). Its window caption states whether it is | |
| // running Low or Medium IL, and whether it is inside a Job. | |
| // – The parent grants the child access to its HWND (if the relevant checkbox was | |
| // ticked) via UserHandleGrantAccess. | |
| // – The child allows the registered custom message (WM_FWD) through UIPI if | |
| // the corresponding checkbox was selected. | |
| // 3. Copy a HWND from any instance into the "Target HWND" edit of any other instance | |
| // and press **Send Ping**. The receiver pops a message box proving that the post | |
| // made it across. | |
| // | |
| // This is *not* production‑hardened code; it is meant as a concise playground so you | |
| // can observe Job/UI limits, IL levels and cross‑process window messaging behaviour | |
| // in Process Explorer / ProcMon / Spy++. | |
| #define WIN32_LEAN_AND_MEAN | |
| #include <windows.h> | |
| #include <commctrl.h> | |
| #include <strsafe.h> | |
| #include <string> | |
| #include <cstdio> | |
| #include <sddl.h> | |
| #include <sstream> | |
| #pragma comment(lib, "comctl32.lib") | |
| #pragma comment(lib, "advapi32.lib") | |
| // ----------------------------- Constants & globals ----------------------------- | |
| // control IDs | |
| enum { | |
| IDC_MYHWND = 1001, | |
| IDC_TEXTHWND = 1002, | |
| IDC_UI_GROUP = 1003, | |
| IDC_UI_DESK = 1004, | |
| IDC_UI_HANDLES = 1005, | |
| IDC_UI_SYSPAR = 1006, | |
| IDC_LOWIL = 1007, | |
| IDC_ALLOWMSG = 1008, | |
| IDC_GRANT = 1009, | |
| IDC_SPAWN = 1010, | |
| IDC_SEND = 1011, | |
| IDC_JOB_NAMES = 1012, | |
| IDC_ALLOWMSG_NOW = 1013, | |
| IDC_GRANT_NOW = 1014, | |
| IDC_JOB_RESTRICT = 1015, | |
| IDC_NOT_ALLOWMSG_NOW = 1016, | |
| IDC_NOT_GRANT_NOW = 1017, | |
| IDC_SEND_COPYDATA = 1018, | |
| }; | |
| static const wchar_t *g_clsName = L"SpawnCtrlCenterWndClass"; | |
| static UINT g_uMsgFwd; // registered custom message | |
| static const wchar_t *g_uMsgName = L"WM_FWD_{3272E8E2-43C1-4A0A-A5AE-2D0FF6903DF0}"; | |
| static const wchar_t *g_pipeName = L"\\\\.\\pipe\\SpawnCtrlCenter"; | |
| struct CState { | |
| HWND hwnd; // our main window | |
| HANDLE hJob = nullptr; // if we created/are part of a Job in this instance | |
| bool isLow = false; // did we start at Low IL? | |
| std::wstring title; // window title based on its handle and pid | |
| } g_state; | |
| // ----------------------------- Helper: error exit ----------------------------- | |
| void Box(DWORD error, const wchar_t *msg) | |
| { | |
| std::wstring msgS(msg); | |
| wchar_t buf[256]; | |
| FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, error, 0, buf, 256, nullptr); | |
| msgS = msgS + L"\n" + buf; | |
| MessageBoxW(g_state.hwnd, msgS.c_str(), g_state.title.c_str(), error ? MB_ICONERROR : MB_ICONINFORMATION); | |
| } | |
| // ----------------------------- Helper: create Low‑IL token --------------------- | |
| HANDLE MakeLowIntegrityToken() | |
| { | |
| HANDLE hOrigTok = nullptr; | |
| if (!OpenProcessToken(GetCurrentProcess(), | |
| TOKEN_DUPLICATE | TOKEN_ADJUST_DEFAULT | TOKEN_QUERY | TOKEN_ASSIGN_PRIMARY, | |
| &hOrigTok)) { | |
| Box(GetLastError(), L"OpenProcessToken"); | |
| return nullptr; | |
| } | |
| HANDLE hDup = nullptr; | |
| if (!DuplicateTokenEx(hOrigTok, MAXIMUM_ALLOWED, nullptr, | |
| SecurityImpersonation, TokenPrimary, &hDup)) { | |
| Box(GetLastError(), L"DuplicateTokenEx"); | |
| return nullptr; | |
| } | |
| PSID pLowSID = nullptr; | |
| if (!ConvertStringSidToSidW(L"S-1-16-4096", &pLowSID)) { | |
| Box(GetLastError(), L"ConvertStringSidToSid"); | |
| return nullptr; | |
| } | |
| TOKEN_MANDATORY_LABEL tml = {}; | |
| tml.Label.Attributes = SE_GROUP_INTEGRITY; | |
| tml.Label.Sid = pLowSID; | |
| if (!SetTokenInformation(hDup, TokenIntegrityLevel, | |
| &tml, sizeof(tml) + GetLengthSid(pLowSID))) { | |
| Box(GetLastError(), L"SetTokenInformation"); | |
| return nullptr; | |
| } | |
| LocalFree(pLowSID); | |
| CloseHandle(hOrigTok); | |
| return hDup; // caller closes | |
| } | |
| // ----------------------------- UI helpers -------------------------------------- | |
| void SetDlgItemHex(HWND hDlg, int id, UINT_PTR value) | |
| { | |
| wchar_t buf[32]; | |
| StringCchPrintfW(buf, 32, L"0x%p", (void*)value); | |
| SetDlgItemTextW(hDlg, id, buf); | |
| } | |
| UINT_PTR GetDlgItemHex(HWND hDlg, int id) | |
| { | |
| wchar_t buf[64] = {}; | |
| GetDlgItemTextW(hDlg, id, buf, 64); | |
| return (UINT_PTR)_wcstoui64(buf, nullptr, 0); | |
| } | |
| // ----------------------------- Spawn child ------------------------------------- | |
| void SpawnChild(HWND hDlg, HWND hUiRestrictionsGroup) | |
| { | |
| static int st_jobCount = 0; // static to keep track of job names | |
| WCHAR jobName[64] = {}; | |
| GetDlgItemTextW(hDlg, IDC_JOB_NAMES, jobName, 64); | |
| DWORD uiFlags = 0; | |
| if (IsDlgButtonChecked(hUiRestrictionsGroup, IDC_UI_DESK ) == BST_CHECKED) uiFlags |= JOB_OBJECT_UILIMIT_DESKTOP; | |
| if (IsDlgButtonChecked(hUiRestrictionsGroup, IDC_UI_HANDLES) == BST_CHECKED) uiFlags |= JOB_OBJECT_UILIMIT_HANDLES; | |
| if (IsDlgButtonChecked(hUiRestrictionsGroup, IDC_UI_SYSPAR ) == BST_CHECKED) uiFlags |= JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS; | |
| bool wantJob = uiFlags || jobName[0] != '\0'; | |
| bool lowIL = (IsDlgButtonChecked(hDlg, IDC_LOWIL) == BST_CHECKED); | |
| bool allowMsg = (IsDlgButtonChecked(hDlg, IDC_ALLOWMSG)== BST_CHECKED); | |
| bool grantHwnd = (IsDlgButtonChecked(hDlg, IDC_GRANT) == BST_CHECKED); | |
| // Create/prepare Job if requested | |
| HANDLE hJob = nullptr; | |
| HANDLE hJobFull = nullptr; | |
| if (wantJob) | |
| { | |
| PWSTR newJobName = jobName; | |
| if (newJobName[0] == L'\0') | |
| { | |
| // If the combobox is empty, use a new job name | |
| newJobName = new WCHAR[64]; // is this necessary? | |
| StringCchPrintfW(newJobName, 64, L"SpawnJob #%d", ++st_jobCount); | |
| } | |
| hJob = CreateJobObjectW(nullptr, newJobName); | |
| if (!hJob) return Box(GetLastError(), L"CreateJobObject"); | |
| hJobFull = OpenJobObjectW(JOB_OBJECT_ALL_ACCESS, FALSE, newJobName); | |
| if( uiFlags ) | |
| { | |
| JOBOBJECT_BASIC_UI_RESTRICTIONS ui = { uiFlags }; | |
| if (!SetInformationJobObject(hJobFull ? hJobFull : hJob, JobObjectBasicUIRestrictions, &ui, sizeof(ui))) | |
| return Box(GetLastError(), L"SetInformationJobObject"); | |
| } | |
| if (newJobName != jobName) | |
| { | |
| // Add the job name to the combobox if it was a new job | |
| LRESULT result = SendMessageW(GetDlgItem(hDlg, IDC_JOB_NAMES), CB_ADDSTRING, 0, (LPARAM)newJobName); | |
| if( result == CB_ERR || result == CB_ERRSPACE ) { | |
| return Box(GetLastError(), L"UpdateJobNames"); | |
| } | |
| } | |
| } | |
| // Build command line (pass self HWND + options as args) | |
| wchar_t exePath[MAX_PATH]; | |
| GetModuleFileNameW(nullptr, exePath, MAX_PATH); | |
| wchar_t cmd[512]; | |
| StringCchPrintfW(cmd, 512, L"\"%s\" --parent %p --allowmsg %d", exePath, g_state.hwnd, allowMsg); | |
| STARTUPINFOW si{ sizeof(si) }; | |
| PROCESS_INFORMATION pi{}; | |
| DWORD createFlags = CREATE_UNICODE_ENVIRONMENT; | |
| HANDLE hTok = nullptr; | |
| if (lowIL) { | |
| hTok = MakeLowIntegrityToken(); | |
| if (!hTok) return Box(GetLastError(), L"MakeLowIntegrityToken"); | |
| if (!CreateProcessAsUserW(hTok, nullptr, cmd, nullptr, nullptr, TRUE, | |
| createFlags, nullptr, nullptr, &si, &pi)) | |
| return Box(GetLastError(), L"CreateProcessAsUser (low)"); | |
| } else { | |
| if (!CreateProcessW(nullptr, cmd, nullptr, nullptr, TRUE, | |
| createFlags, nullptr, nullptr, &si, &pi)) | |
| return Box(GetLastError(), L"CreateProcess (medium)"); | |
| } | |
| if (wantJob && !AssignProcessToJobObject(hJob, pi.hProcess)) | |
| return Box(GetLastError(), L"AssignProcessToJobObject"); | |
| if (grantHwnd) { | |
| if (!UserHandleGrantAccess((HANDLE)g_state.hwnd, hJob, TRUE)) | |
| return Box(GetLastError(), L"UserHandleGrantAccess"); | |
| } | |
| //CloseHandle(hJob); | |
| CloseHandle(pi.hProcess); CloseHandle(pi.hThread); | |
| if (hTok) CloseHandle(hTok); | |
| } | |
| HWND FindSpawnWindow(HWND hDlg) | |
| { | |
| HWND target = (HWND)GetDlgItemHex(hDlg, IDC_TEXTHWND); | |
| if (target == nullptr ) | |
| { | |
| target = FindWindowW(g_clsName, nullptr); | |
| if( target != nullptr ) | |
| { | |
| wchar_t buf[128]; | |
| StringCchPrintfW(buf, 128, L"0x%p", (void*)target); | |
| SetDlgItemText(hDlg, IDC_TEXTHWND, buf); | |
| } | |
| } | |
| return target; | |
| } | |
| // ----------------------------- Send ping --------------------------------------- | |
| void SendPing(HWND hDlg) | |
| { | |
| HWND target = FindSpawnWindow(hDlg); | |
| if (!IsWindow(target)) { | |
| std::wostringstream os; os << L"SendPing HWND " << target << " is invalid"; | |
| return Box(ERROR_INVALID_WINDOW_HANDLE, os.str().c_str()); | |
| } | |
| if(!PostMessageW(target, g_uMsgFwd, (WPARAM)g_state.hwnd, 0)) { | |
| std::wostringstream os; os << L"SendPing PostMessageW HWND " << target << L"."; | |
| return Box(GetLastError(), os.str().c_str()); | |
| } | |
| } | |
| bool TrySendCopyDataUsingNamedPipe(HWND hDlg) | |
| { | |
| return false; | |
| } | |
| bool TrySendCopyDataUsingSendMessage(HWND hDlg, std::wstring& error) | |
| { | |
| HWND target = FindSpawnWindow(hDlg); | |
| if (!IsWindow(target)) | |
| { | |
| std::wostringstream os; os << L"SendCopyData HWND " << target << " is invalid (INVALID_WINDOW_HANDLE)"; | |
| error = os.str(); | |
| return false; | |
| } | |
| COPYDATASTRUCT copyData = { 1, 0, nullptr }; | |
| if(!SendMessageW(target, WM_COPYDATA, (WPARAM)g_state.hwnd, (LPARAM)©Data)) | |
| { | |
| std::wostringstream os; os << L"SendCopyData PostMessageW HWND " << target << L"."; | |
| error = os.str(); | |
| return false; | |
| } | |
| return true; | |
| } | |
| void SendCopyData(HWND hDlg) | |
| { | |
| std::wstring error; | |
| if( !TrySendCopyDataUsingSendMessage(hDlg, error)) | |
| return Box(GetLastError(), L"TrySendCopyDataUsingSendMessage WM_COPYDATA"); | |
| /*WIP | |
| { | |
| std::wstring error2; | |
| if (!TrySendCopyDataUsingNamedPipe(hDlg)) | |
| { | |
| } | |
| } | |
| */ | |
| } | |
| void AllowMsgNow(HWND hDlg, bool allow = true) | |
| { | |
| if( ! ChangeWindowMessageFilterEx(g_state.hwnd, g_uMsgFwd, allow ? MSGFLT_ALLOW : MSGFLT_DISALLOW, nullptr) ) | |
| return Box(GetLastError(), L"ChangeWindowMessageFilterEx registered message"); | |
| if( ! ChangeWindowMessageFilterEx(g_state.hwnd, WM_COPYDATA, allow ? MSGFLT_ALLOW : MSGFLT_DISALLOW, nullptr) ) | |
| return Box(GetLastError(), L"ChangeWindowMessageFilterEx WM_COPYDATA"); | |
| Box(0, L"ChangeWindowMessageFilterEx"); | |
| } | |
| void GrantNow(HWND hDlg, bool allow = true) | |
| { | |
| WCHAR jobName[64] = {}; | |
| GetDlgItemText(hDlg, IDC_JOB_NAMES, jobName, 64); | |
| if (jobName[0] != L'\0') { | |
| HANDLE hJob = OpenJobObjectW(JOB_OBJECT_ALL_ACCESS, FALSE, jobName); | |
| if (!hJob) return Box(GetLastError(), L"OpenJobObject"); | |
| if (!UserHandleGrantAccess((HANDLE)g_state.hwnd, hJob, allow ? TRUE : FALSE)) return Box(GetLastError(), L"UserHandleGrantAccess"); | |
| CloseHandle(hJob); | |
| Box(0, L"UserHandleGrantAccess"); | |
| } else { | |
| Box(ERROR_INVALID_PARAMETER, L"Specify a job name"); | |
| } | |
| } | |
| void RestrictJob(HWND hDlg, HWND hUiRestrictionsGroup) | |
| { | |
| WCHAR jobName[64] = {}; | |
| GetDlgItemTextW(hDlg, IDC_JOB_NAMES, jobName, 64); | |
| if (jobName[0] != L'\0') { | |
| HANDLE hJob = OpenJobObjectW(JOB_OBJECT_ALL_ACCESS, FALSE, jobName); | |
| if (!hJob) return Box(GetLastError(), L"OpenJobObject"); | |
| DWORD uiFlags = 0; | |
| if (IsDlgButtonChecked(hUiRestrictionsGroup, IDC_UI_DESK) == BST_CHECKED) uiFlags |= JOB_OBJECT_UILIMIT_DESKTOP; | |
| if (IsDlgButtonChecked(hUiRestrictionsGroup, IDC_UI_HANDLES) == BST_CHECKED) uiFlags |= JOB_OBJECT_UILIMIT_HANDLES; | |
| if (IsDlgButtonChecked(hUiRestrictionsGroup, IDC_UI_SYSPAR) == BST_CHECKED) uiFlags |= JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS; | |
| JOBOBJECT_BASIC_UI_RESTRICTIONS ui = { uiFlags }; | |
| if (!SetInformationJobObject(hJob, JobObjectBasicUIRestrictions, &ui, sizeof(ui))) | |
| return Box(GetLastError(), L"SetInformationJobObject"); | |
| Box(0, L"SetInformationJobObject"); | |
| } else { | |
| Box(ERROR_INVALID_PARAMETER, L"Specify a job name"); | |
| } | |
| } | |
| // ----------------------------- Window procedure -------------------------------- | |
| LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) | |
| { | |
| static HWND st_uiRestrictions = nullptr; // groupbox for UI restrictions | |
| switch (msg) | |
| { | |
| case WM_CREATE: | |
| { | |
| INITCOMMONCONTROLSEX icc{ sizeof(icc), ICC_STANDARD_CLASSES }; | |
| InitCommonControlsEx(&icc); | |
| // Store our HWND globally | |
| g_state.hwnd = hwnd; | |
| DWORD pid = GetCurrentProcessId(); | |
| std::wostringstream os; os << L"SpawnControlCenter 0x" << g_state.hwnd << " PID " << pid; | |
| g_state.title = os.str(); | |
| // ---------------- Controls layout (simplistic) ---------------- | |
| CreateWindowExW(WS_EX_CLIENTEDGE, L"edit", L"", WS_CHILD|WS_VISIBLE|ES_READONLY, | |
| 10,8, 200,24, hwnd, (HMENU)IDC_MYHWND, nullptr, nullptr); | |
| CreateWindowW(L"static", L"=>", WS_CHILD|WS_VISIBLE, | |
| 210,10, 20,20, hwnd, nullptr, nullptr, nullptr); | |
| CreateWindowExW(WS_EX_CLIENTEDGE, L"edit", L"0x0", WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL, | |
| 230,8, 200,24, hwnd, (HMENU)IDC_TEXTHWND, nullptr, nullptr); | |
| CreateWindowW(L"static", L"Job:", WS_CHILD|WS_VISIBLE, | |
| 10,38, 50,20, hwnd, nullptr, nullptr, nullptr); | |
| CreateWindowExW(WS_EX_CLIENTEDGE, L"combobox", L"", WS_CHILD|WS_VISIBLE|CBS_DROPDOWN|CBS_HASSTRINGS|CBS_SORT, | |
| 60,38, 150,150, hwnd, (HMENU)IDC_JOB_NAMES, nullptr, nullptr); | |
| st_uiRestrictions = CreateWindowW(L"button", L"UI Restrictions (Job)", | |
| WS_CHILD|WS_VISIBLE|BS_GROUPBOX, | |
| 10,70, 220, 120, hwnd, (HMENU)IDC_UI_GROUP, nullptr, nullptr); | |
| CreateWindowW(L"button", L"DESKTOP", WS_CHILD|WS_VISIBLE|BS_AUTOCHECKBOX, | |
| 20,20, 110,20, st_uiRestrictions, (HMENU)IDC_UI_DESK, nullptr, nullptr); | |
| CreateWindowW(L"button", L"HANDLES", WS_CHILD|WS_VISIBLE|BS_AUTOCHECKBOX, | |
| 20,40, 110,20, st_uiRestrictions, (HMENU)IDC_UI_HANDLES, nullptr, nullptr); | |
| CreateWindowW(L"button", L"SYSPARAM", WS_CHILD|WS_VISIBLE|BS_AUTOCHECKBOX, | |
| 20,60, 110,20, st_uiRestrictions, (HMENU)IDC_UI_SYSPAR, nullptr, nullptr); | |
| CreateWindowW(L"button", L"Apply", WS_CHILD|WS_VISIBLE|BS_DEFPUSHBUTTON, | |
| 20,150, 100,28, hwnd, (HMENU)IDC_JOB_RESTRICT, nullptr, nullptr); | |
| CreateWindowW(L"button", L"Low Integrity", WS_CHILD|WS_VISIBLE|BS_AUTOCHECKBOX, | |
| 10,200, 120,20, hwnd, (HMENU)IDC_LOWIL, nullptr, nullptr); | |
| CreateWindowW(L"button", L"Allow Msg (ChangeWindowMessageFilterEx)", WS_CHILD|WS_VISIBLE|BS_AUTOCHECKBOX, | |
| 140,200, 320,20, hwnd, (HMENU)IDC_ALLOWMSG, nullptr, nullptr); | |
| CreateWindowW(L"button", L"Grant HWND to child (UserHandleGrantAccess)", WS_CHILD|WS_VISIBLE|BS_AUTOCHECKBOX, | |
| 140,225, 380,20, hwnd, (HMENU)IDC_GRANT, nullptr, nullptr); | |
| CreateWindowW(L"button", L"Spawn Child", WS_CHILD|WS_VISIBLE|BS_DEFPUSHBUTTON, | |
| 10,250, 100,28, hwnd, (HMENU)IDC_SPAWN, nullptr, nullptr); | |
| CreateWindowW(L"button", L"Send Ping", WS_CHILD|WS_VISIBLE, | |
| 120,250, 100,28, hwnd, (HMENU)IDC_SEND, nullptr, nullptr); | |
| CreateWindowW(L"button", L"CopyData", WS_CHILD|WS_VISIBLE, | |
| 120,280, 100,28, hwnd, (HMENU)IDC_SEND_COPYDATA, nullptr, nullptr); | |
| CreateWindowW(L"button", L"Allow Msg", WS_CHILD|WS_VISIBLE, | |
| 230,250, 100,28, hwnd, (HMENU)IDC_ALLOWMSG_NOW, nullptr, nullptr); | |
| CreateWindowW(L"button", L"Grant", WS_CHILD|WS_VISIBLE|BS_DEFPUSHBUTTON, | |
| 340,250, 100,28, hwnd, (HMENU)IDC_GRANT_NOW, nullptr, nullptr); | |
| CreateWindowW(L"button", L"Disallow", WS_CHILD|WS_VISIBLE, | |
| 230,280, 100,28, hwnd, (HMENU)IDC_NOT_ALLOWMSG_NOW, nullptr, nullptr); | |
| CreateWindowW(L"button", L"Revoke", WS_CHILD|WS_VISIBLE|BS_DEFPUSHBUTTON, | |
| 340,280, 100,28, hwnd, (HMENU)IDC_NOT_GRANT_NOW, nullptr, nullptr); | |
| // show our own HWND | |
| SetDlgItemHex(hwnd, IDC_MYHWND, (UINT_PTR)hwnd); | |
| return 0; | |
| } | |
| case WM_COMMAND: | |
| { | |
| int id = LOWORD(wp); | |
| if (id == IDC_SPAWN) | |
| SpawnChild(hwnd, st_uiRestrictions); | |
| else if (id == IDC_SEND) | |
| SendPing(hwnd); | |
| else if (id == IDC_SEND_COPYDATA) | |
| SendCopyData(hwnd); | |
| else if (id == IDC_ALLOWMSG_NOW) | |
| AllowMsgNow(hwnd); | |
| else if (id == IDC_GRANT_NOW) | |
| GrantNow(hwnd); | |
| else if (id == IDC_NOT_ALLOWMSG_NOW) | |
| AllowMsgNow(hwnd, false); | |
| else if (id == IDC_NOT_GRANT_NOW) | |
| GrantNow(hwnd, false); | |
| else if (id == IDC_JOB_RESTRICT) | |
| RestrictJob(hwnd, st_uiRestrictions); | |
| return 0; | |
| } | |
| case WM_CLOSE: | |
| { | |
| PostQuitMessage(0); | |
| } | |
| default: | |
| if (msg == g_uMsgFwd) { | |
| wchar_t buf[128]; | |
| StringCchPrintfW(buf, 128, L"Received ping from HWND 0x%p!", (void*)wp); | |
| Box(0, buf); | |
| StringCchPrintfW(buf, 128, L"0x%p", (void*)wp); | |
| SetDlgItemText(hwnd, IDC_TEXTHWND, buf); | |
| return 0; | |
| } else if (msg == WM_COPYDATA) { | |
| wchar_t buf[128]; | |
| StringCchPrintfW(buf, 128, L"Received WM_COPYDATA from HWND 0x%p!", (void*)wp); | |
| Box(0, buf); | |
| StringCchPrintfW(buf, 128, L"0x%p", (void*)wp); | |
| SetDlgItemText(hwnd, IDC_TEXTHWND, buf); | |
| return TRUE; | |
| } | |
| return DefWindowProcW(hwnd, msg, wp, lp); | |
| } | |
| } | |
| bool JobHasBasicUILimits() | |
| { | |
| // Ask for the UI‑restriction block that is attached to the job | |
| JOBOBJECT_BASIC_UI_RESTRICTIONS ui = {}; | |
| if (!QueryInformationJobObject( | |
| /*JobHandle*/ nullptr, // “nullptr” → “the job that I’m running in” | |
| JobObjectBasicUIRestrictions, // what we want | |
| &ui, sizeof(ui), | |
| /*ReturnLength*/ nullptr)) | |
| { | |
| // If the call fails the process probably just isn’t in a job | |
| // (ERROR_NOT_FOUND or ERROR_INVALID_PARAMETER on older versions) | |
| return false; | |
| } | |
| return ui.UIRestrictionsClass != 0; // any bit means some UI limit is set | |
| } | |
| // Wire format = 3 dwords followed by cbData bytes | |
| // | dwData | cbData | reserved | payload ... | | |
| struct PIPE_DATA_HDR | |
| { | |
| DWORD dwData; // like COPYDATASTRUCT.dwData | |
| DWORD cbData; // size of payload | |
| DWORD reserved; // keep 8‑byte alignment, future use | |
| }; | |
| // Helper: send one "WM_COPYDATA‑style" message | |
| inline bool SendPipeMessage( | |
| HANDLE hPipe, | |
| DWORD dwData, | |
| const void* pBuf, | |
| DWORD cbBuf) | |
| { | |
| PIPE_DATA_HDR hdr{ dwData, cbBuf, 0 }; | |
| DWORD written = 0; | |
| return WriteFile(hPipe, &hdr, sizeof(hdr), &written, nullptr) && | |
| WriteFile(hPipe, pBuf, cbBuf, &written, nullptr); | |
| } | |
| // Helper: blocking receive. Returns false on EOF/error. | |
| // *dwData and *payload are filled; caller frees payload with LocalFree. | |
| inline bool RecvPipeMessage( | |
| HANDLE hPipe, | |
| DWORD* dwData, | |
| void** payload, | |
| DWORD* cbBuf) | |
| { | |
| PIPE_DATA_HDR hdr{}; | |
| DWORD read = 0; | |
| if (!ReadFile(hPipe, &hdr, sizeof(hdr), &read, nullptr) || | |
| read != sizeof(hdr)) | |
| return false; | |
| void* buf = LocalAlloc(LMEM_FIXED, hdr.cbData); | |
| if (!buf) return false; | |
| if (!ReadFile(hPipe, buf, hdr.cbData, &read, nullptr) || | |
| read != hdr.cbData) | |
| { | |
| LocalFree(buf); | |
| return false; | |
| } | |
| *dwData = hdr.dwData; | |
| *cbBuf = hdr.cbData; | |
| *payload = buf; | |
| return true; | |
| } | |
| HANDLE CreateLowIntegrityPipe() | |
| { | |
| SECURITY_ATTRIBUTES sa = { sizeof(sa) }; | |
| PSECURITY_DESCRIPTOR pSD = nullptr; | |
| // Define low integrity SDDL | |
| LPCWSTR lowIntegritySDDL = L"D:(A;OICI;GA;;;WD)S:(ML;;NW;;;LW)"; | |
| if (!ConvertStringSecurityDescriptorToSecurityDescriptorW( | |
| lowIntegritySDDL, SDDL_REVISION_1, &pSD, nullptr)) | |
| { | |
| return nullptr; | |
| } | |
| sa.lpSecurityDescriptor = pSD; | |
| sa.bInheritHandle = FALSE; | |
| HANDLE hPipe = CreateNamedPipeW( | |
| g_pipeName, | |
| PIPE_ACCESS_DUPLEX, | |
| PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, | |
| 1, 4096, 4096, 0, &sa); | |
| LocalFree(pSD); | |
| return hPipe; | |
| } | |
| DWORD WINAPI PipeProcThread(LPVOID lpThreadParameter) | |
| { | |
| HANDLE hPipe = CreateLowIntegrityPipe(); | |
| if (hPipe == INVALID_HANDLE_VALUE) | |
| { | |
| return 1; | |
| } | |
| ConnectNamedPipe(hPipe, nullptr); | |
| // Example: send a greeting | |
| const char msg[] = "Hello from parent!"; | |
| SendPipeMessage(hPipe, 1, msg, sizeof(msg)); | |
| // Loop receiving data | |
| for (;;) | |
| { | |
| DWORD id, cb; | |
| void* payload; | |
| if (!RecvPipeMessage(hPipe, &id, &payload, &cb)) | |
| break; | |
| LocalFree(payload); | |
| } | |
| CloseHandle(hPipe); | |
| return 0; | |
| } | |
| // ----------------------------- WinMain ---------------------------------------- | |
| int APIENTRY wWinMain(HINSTANCE hInst, HINSTANCE, LPWSTR lpCmdLine, int nCmdShow) | |
| { | |
| // Parse minimal cmdline flags (only ones we need when launched as child) | |
| bool allowMsgThis = false; | |
| if (wcsstr(lpCmdLine, L"--allowmsg 1")) allowMsgThis = true; | |
| // Register message (must be done *before* any ChangeWindowMessageFilterEx) | |
| g_uMsgFwd = RegisterWindowMessageW(g_uMsgName); | |
| wchar_t cap[64]; | |
| BOOL inJob = false; | |
| BOOL b = IsProcessInJob(GetCurrentProcess(), nullptr, &inJob); | |
| DWORD il = SECURITY_MANDATORY_MEDIUM_RID; | |
| HANDLE hTok; | |
| if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hTok)) { | |
| DWORD sz = 0; GetTokenInformation(hTok, TokenIntegrityLevel, nullptr, 0, &sz); | |
| BYTE *buf = new BYTE[sz]; | |
| if (GetTokenInformation(hTok, TokenIntegrityLevel, buf, sz, &sz)) { | |
| auto tml = reinterpret_cast<TOKEN_MANDATORY_LABEL*>(buf); | |
| il = *GetSidSubAuthority(tml->Label.Sid, | |
| *GetSidSubAuthorityCount(tml->Label.Sid)-1); | |
| } | |
| delete [] buf; CloseHandle(hTok); | |
| } | |
| StringCchPrintfW(cap, 64, L"Spawn Ctrl Center – %s IL – %sJob - %d", | |
| (il == SECURITY_MANDATORY_LOW_RID ? L"LOW" : L"MED"), inJob ? L"in " : L"no ", GetCurrentProcessId()); | |
| MessageBox(nullptr, cap, L"Starting", MB_ICONINFORMATION | MB_OK); | |
| bool highPriv = false; | |
| std::wstring className; | |
| if( il == SECURITY_MANDATORY_LOW_RID || (inJob && JobHasBasicUILimits()) ) | |
| { | |
| className = g_clsName + std::wstring(L"_low"); | |
| } | |
| else | |
| { | |
| className = g_clsName; | |
| highPriv = true; | |
| } | |
| if( highPriv ) | |
| { | |
| CreateThread(NULL, 0, PipeProcThread, nullptr, 0, nullptr); | |
| } | |
| // If launched as child: optional ChangeWindowMessageFilterEx | |
| WNDCLASSEXW wc{ sizeof(wc) }; | |
| wc.lpfnWndProc = WndProc; | |
| wc.hInstance = hInst; | |
| wc.hCursor = LoadCursor(nullptr, IDC_ARROW); | |
| wc.lpszClassName = className.c_str(); | |
| wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1); | |
| RegisterClassExW(&wc); | |
| g_state.isLow = (il==SECURITY_MANDATORY_LOW_RID); | |
| g_state.hwnd = CreateWindowW(className.c_str(), cap, | |
| WS_OVERLAPPEDWINDOW|WS_VISIBLE, | |
| CW_USEDEFAULT, CW_USEDEFAULT, 540, 350, | |
| nullptr, nullptr, hInst, nullptr); | |
| if (allowMsgThis) { | |
| ChangeWindowMessageFilterEx(g_state.hwnd, g_uMsgFwd, MSGFLT_ALLOW, nullptr); | |
| } | |
| // Main loop | |
| MSG m; | |
| while (GetMessageW(&m, nullptr, 0, 0)) { | |
| TranslateMessage(&m); | |
| DispatchMessageW(&m); | |
| } | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment