- /*
- * MIT License
- *
- * Copyright (c) 2025 Roland Mainz <roland.mainz@nrubsig.org>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * allcopies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
- /*
- * runassystem.c - run Win32 program as Windows user "SYSTEM"
- *
- * Written by Roland Mainz <roland.mainz@nrubsig.org>
- */
- /*
- * Compile with:
- * $ clang -target x86_64-pc-windows-gnu -Wall -municode runassystem.c -lWtsapi32 -o runassystem.exe
- */
- #define WIN32_LEAN_AND_MEAN 1
- #include <windows.h>
- #include <strsafe.h>
- #include <stdbool.h>
- #include <stdio.h>
- #include <wchar.h>
- #include <WtsApi32.h>
- #include <sddl.h>
- #include <fcntl.h>
- /* Global variables */
- static const wchar_t* SERVICE_NAME = L"RunAsSYSTEM_temporary_service0001";
- static const wchar_t* SERVICE_DISPLAY_NAME = L"My C System Process Launcher Service";
- static SERVICE_STATUS g_ServiceStatus = {0};
- static SERVICE_STATUS_HANDLE g_StatusHandle = NULL;
- static HANDLE g_ServiceStopEvent = INVALID_HANDLE_VALUE;
- static int service_argc = 0;
- static wchar_t **service_argv = NULL;
- /* Local prototypes */
- static void ReportError(const char* context);
- static void LaunchInteractiveProcess(void);
- static void WINAPI ServiceCtrlHandler(DWORD CtrlCode);
- static void WINAPI ServiceMain(DWORD argc, LPWSTR* argv);
- #define DBG 1
- #ifdef DBG
- #define DbgP(_x_) RASDbgPrint _x_
- #else
- #define DbgP(_x_)
- #endif
- #define TRACE_TAG L"[RAS]"
- #define PTR2PTRDIFF_T(p) (((char *)(p))-((char *)0))
- #define HANDLE2INT(h) ((int)PTR2PTRDIFF_T(h))
- ULONG _cdecl RASDbgPrint(__in LPWSTR fmt, ...)
- {
- DWORD saved_lasterr;
- ULONG rc = 0;
- #define SZBUFFER_SIZE 1024
- wchar_t szbuffer[SZBUFFER_SIZE+1];
- wchar_t *szbp = szbuffer;
- saved_lasterr = GetLastError();
- va_list marker;
- (void)StringCchPrintfW(szbp, SZBUFFER_SIZE-(szbp - szbuffer),
- TRACE_TAG L"[thr=%04x] ", (int)GetCurrentThreadId());
- (void)StringCchVPrintfW(szbp, SZBUFFER_SIZE-(szbp - szbuffer),
- fmt, marker);
- szbuffer[SZBUFFER_SIZE-1] = L'\0';
- OutputDebugStringW(szbuffer);
- SetLastError(saved_lasterr);
- return rc;
- }
- static
- void ReportError(const char* context)
- {
- "ERROR in %s: %d\n",
- context,
- (int)GetLastError());
- }
- static
- void LaunchInteractiveProcess(void)
- {
- STARTUPINFOA si;
- PROCESS_INFORMATION pi;
- char buffer[16384];
- char *s = buffer;
- HANDLE hFile_stdout = INVALID_HANDLE_VALUE;
- HANDLE hFile_stderr = INVALID_HANDLE_VALUE;
- SECURITY_ATTRIBUTES sa = { 0 };
- si.cb = sizeof(si);
- sa.nLength = sizeof(SECURITY_ATTRIBUTES);
- sa.bInheritHandle = TRUE;
- hFile_stdout = CreateFileA("C:\\hjk_stdout",
- GENERIC_READ|GENERIC_WRITE,
- FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
- &sa,
- CREATE_ALWAYS,
- FILE_ATTRIBUTE_TEMPORARY,
- NULL);
- if (hFile_stdout == INVALID_HANDLE_VALUE) {
- DbgP((L"LaunchInteractiveProcess: cannot open stdout, lasterr=%d\n",
- (int)GetLastError()));
- goto done;
- }
- hFile_stderr = CreateFileA("C:\\hjk_stderr",
- GENERIC_READ|GENERIC_WRITE,
- FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
- &sa,
- CREATE_ALWAYS,
- FILE_ATTRIBUTE_TEMPORARY,
- NULL);
- if (hFile_stderr == INVALID_HANDLE_VALUE) {
- DbgP((L"LaunchInteractiveProcess: cannot open stderr, lasterr=%d\n",
- (int)GetLastError()));
- goto done;
- }
- (void)SetHandleInformation(hFile_stdout, HANDLE_FLAG_INHERIT, TRUE);
- (void)SetHandleInformation(hFile_stderr, HANDLE_FLAG_INHERIT, TRUE);
- /*
- * service_argv[0] == *.exe name
- * service_argv[1] == "--service"
- * service_argv[2] == <Service name>
- */
- /* Command name + <space> separator */
- int i;
- for (i=4 ; i < service_argc ; i++) {
- }
- si.dwFlags = STARTF_USESTDHANDLES;
- si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
- si.hStdOutput = hFile_stdout;
- si.hStdError = hFile_stderr;
- if (!CreateProcessA(NULL,
- buffer,
- NULL,
- NULL,
- TRUE,
- 0,
- NULL,
- NULL,
- &si,
- &pi)) {
- return;
- }
- (void)WaitForSingleObject(pi.hProcess, INFINITE);
- done:
- (void)CloseHandle(pi.hProcess);
- (void)CloseHandle(pi.hThread);
- (void)CloseHandle(hFile_stdout);
- (void)CloseHandle(hFile_stderr);
- }
- static
- void WINAPI ServiceCtrlHandler(DWORD CtrlCode)
- {
- switch (CtrlCode) {
- case SERVICE_CONTROL_STOP:
- if (g_ServiceStatus.dwCurrentState != SERVICE_RUNNING)
- break;
- g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
- SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
- SetEvent(g_ServiceStopEvent);
- break;
- default:
- break;
- }
- }
- static
- void WINAPI ServiceMain(DWORD argc, wchar_t *argv[])
- {
- g_StatusHandle = RegisterServiceCtrlHandlerW(service_argv[2], ServiceCtrlHandler);
- if (!g_StatusHandle) {
- ReportError("RegisterServiceCtrlHandlerW");
- return;
- }
- g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
- g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
- g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
- SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
- g_ServiceStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
- if (g_ServiceStopEvent == NULL) {
- g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
- SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
- return;
- }
- g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
- SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
- LaunchInteractiveProcess();
- (void)WaitForSingleObject(g_ServiceStopEvent, INFINITE);
- g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
- SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
- (void)CloseHandle(g_ServiceStopEvent);
- }
- static
- bool InstallService(int argc, wchar_t *argv[])
- {
- bool retval = false;
- wchar_t szPath[MAX_PATH+1];
- wchar_t szPathWithArg[16384];
- wchar_t *s;
- SC_HANDLE hSCManager;
- hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
- if (!hSCManager) {
- ReportError("OpenSCManager");
- return false;
- }
- /* Get our *.exe name */
- if (GetModuleFileNameW(NULL, szPath, MAX_PATH) == 0) {
- ReportError("GetModuleFileNameW");
- retval = false;
- goto done;
- }
- /* Manually construct the path with the argument for the service */
- s = szPathWithArg;
- int i;
- for (i=1 ; i < argc ; i++) {
- /* FIXME: Quoting */
- }
- /* Print arguments */
- /*
- * FIXME: We should implement -u and -g to define username and primary
- * group name
- */
- SC_HANDLE hService = CreateServiceW(hSCManager,
- SERVICE_NAME, SERVICE_DISPLAY_NAME, SERVICE_ALL_ACCESS,
- SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
- szPathWithArg, NULL, NULL, NULL, L"NT AUTHORITY\\SYSTEM", NULL);
- if (!hService) {
- ReportError("CreateServiceW");
- retval = false;
- goto done;
- }
- if (!StartServiceW(hService, 0, NULL)) {
- ReportError("StartServiceW");
- retval = false;
- goto done;
- }
- /* Give service time to work before cleanup */
- Sleep(2000);
- (void)CloseServiceHandle(hService);
- /* Success! */
- retval = true;
- done:
- (void)CloseServiceHandle(hSCManager);
- return retval;
- }
- static
- void UninstallService(void)
- {
- SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
- if (!hSCManager) {
- ReportError("UninstallService: OpenSCManager");
- return;
- }
- SC_HANDLE hService = OpenServiceW(hSCManager, SERVICE_NAME, SERVICE_ALL_ACCESS);
- if (!hService) {
- ReportError("UninstallService: OpenServiceW");
- } else {
- SERVICE_STATUS status;
- ControlService(hService, SERVICE_CONTROL_STOP, &status);
- if (!DeleteService(hService)) {
- ReportError("UninstallService: DeleteService");
- } else {
- }
- (void)CloseServiceHandle(hService);
- }
- (void)CloseServiceHandle(hSCManager);
- }
- int wmain(int argc, wchar_t *argv[])
- {
- int retval = EXIT_FAILURE;
- /*
- * If started with "--service", run as a service
- */
- /*
- * Store argument array passed to |wmain()| because the argument
- * array for |ServiceMain()| does not have these arguments
- */
- service_argc = argc;
- service_argv = argv;
- SERVICE_TABLE_ENTRYW ServiceTable[] = {
- { .lpServiceName = argv[2], .lpServiceProc = ServiceMain },
- { .lpServiceName = NULL, .lpServiceProc = NULL }
- };
- if (!StartServiceCtrlDispatcherW(ServiceTable)) {
- ReportError("StartServiceCtrlDispatcherW");
- return 1;
- }
- return 0;
- }
- /* Otherwise, run as the client to manage the service */
- /* Install and Start */
- if (InstallService(argc, argv)) {
- /* Stop and Uninstall */
- UninstallService();
- retval = EXIT_SUCCESS;
- }
- return retval;
- }
Prototype runassystem.c - run Win32 program as Windows user "SYSTEM"
Posted by Anonymous on Tue 26th Aug 2025 10:45
raw | new post
Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.