Ejecutar un programa con permisos SYSTEM puede ser muy útil. La utilidad puede ir desde indagar y borrar archivos y puntos de restauración inservibles de la carpeta System Volume Information, hasta inmiscuirse en el mismo winlogon. Cada uno encontrará su utilidad.
MiniSystem es una pequeña aplicación creada para ese fin, lo escribí en un rato libre como un juguete pero al final creo que me ha salido un juguetito al que se le puede sacar alguna utilidad práctica. Se trata de una aplicación en línea de comandos de apenas 3,5k. Recibe como parámetros la ruta de la aplicación a ejecutar como SYSTEM y opcionalmente el usuario y password del administrador, en caso de que se ejecute desde un usuario no administrador. La sintaxis es como sigue:
MiniSystem [-u User] [-p Password] Path
Su funcionalidad al 100% es en Windows XP. En Windows7 funciona, pero con los impedimentos propios del UAC y cortapisas en la comunicación de la aplicación lanzada como SYSTEM con el escritorio del usuario activo. Lo he probado sobre una maquina virtual.
Para minimizar el código y empaquetarlo en un solo archivo, he ideado una filosofía recurrente. De esta forma si se pasa los parámetros del login de administrador, el programa se relanza a si mismo con esas credenciales y termina. La segunda copia, ahora con permisos de administrador, ejecutará una tercera copia, esta vez como servicio con permisos elevados a SYSTEM. Este servicio ejecutará la aplicación pasada en el parámetro Path como SYSTEM, después terminará y se desinstalará.
El programa está escrito en C y compilado en Builder 5 y 6 uso exclusivamente la API de Window, de esta forma se puede compilar la versión "Mini". Inicialmente no es un programa de consola pero como curiosidad, decir que si lo ejecutamos desde una consola sin pasar parámetros, se comportará como si lo fuese, mostrando la sintaxis apropiada. En otro caso, será un programa Windows sin ventanas normal y corriente.
El código es el siguiente:
#include <windows.h> #include <Shlwapi.h> #pragma hdrstop #define SimbolName L"_shuttle_" BOOL IsService() { SC_HANDLE scManager; SC_HANDLE scService = 0; scManager = OpenSCManagerW(0, NULL, SC_MANAGER_ALL_ACCESS); if(scManager){ scService = OpenServiceW(scManager, SimbolName, SERVICE_ALL_ACCESS); CloseServiceHandle(scService); CloseServiceHandle(scManager); } return (BOOL)scService; } void ExecuteAsSystem(WCHAR* Path) { SC_HANDLE scManager; SC_HANDLE scService; scManager = OpenSCManagerW(0, NULL, SC_MANAGER_ALL_ACCESS); if(scManager){ scService = CreateServiceW(scManager, SimbolName, SimbolName, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, Path, NULL, NULL, NULL, NULL, NULL); if(!scService) scService = OpenServiceW(scManager, SimbolName, SERVICE_ALL_ACCESS); StartService(scService, 0, NULL); DeleteService(scService); CloseServiceHandle(scService); CloseServiceHandle(scManager); } } bool ExecuteAs(WCHAR* FileExe, WCHAR* User, WCHAR* Domain, WCHAR* Password, int nCmdShow = SW_SHOW) { PROCESS_INFORMATION piProcInfo; STARTUPINFOW siStartInfo = {0}; siStartInfo.cb = sizeof(STARTUPINFOW); siStartInfo.dwFlags = STARTF_USESHOWWINDOW; siStartInfo.wShowWindow = nCmdShow; WCHAR CurrentDir[MAX_PATH]; GetCurrentDirectoryW(sizeof(CurrentDir), CurrentDir); HRESULT hRes = CreateProcessWithLogonW(User, Domain, Password, LOGON_WITH_PROFILE, NULL, FileExe, NULL, NULL, CurrentDir, &siStartInfo, &piProcInfo) ; if(hRes){ CloseHandle(piProcInfo.hProcess); CloseHandle(piProcInfo.hThread); } return (bool)hRes; } typedef BOOL (WINAPI *PAttachConsole)(DWORD dwProcessId); #pragma argsused WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WCHAR *User = 0, *Pass = 0, *Path = 0; WCHAR AppCmdLine[MAX_PATH*2]; int Argc; LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc); if(Argc == 1){ char Help[] = "\nMiniSystem [-u User] [-p Password] Path"; PAttachConsole AttachConsole = (PAttachConsole)GetProcAddress(GetModuleHandle("Kernel32.dll"), "AttachConsole"); AttachConsole(-1); HANDLE F = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0 ); WriteConsole(F, Help, lstrlen(Help), 0, 0); return 0; } for(int n=1; n<Argc; n++){ if(!StrCmpNIW(Argv[n], L"-u", 2) && n<Argc-1){ User = Argv[++n]; }else if(!StrCmpNIW(Argv[n], L"-p", 2) && n<Argc-1){ Pass = Argv[++n]; }else{ Path = Argv[n]; } } if(User && Pass){ wsprintfW(AppCmdLine, L"\"%s\" \"%s\"", Argv[0], Path); ExecuteAs(AppCmdLine, User, 0, Pass); }else if(IsService()) { PROCESS_INFORMATION pi = {0}; STARTUPINFOW si = {0}; si.cb = sizeof(si); si.lpDesktop = L"WinSta0\\Default"; CreateProcessW(0, Path, 0,0,0,0,0,0,&si,&pi); }else{ if(*(Argv[0]+1) != L':'){ WCHAR CurrentDir[MAX_PATH]; GetCurrentDirectoryW(sizeof(CurrentDir), CurrentDir); wsprintfW(AppCmdLine, L"\"%s\\%s\" \"%s\"", CurrentDir, Argv[0], Path); } else wsprintfW(AppCmdLine, L"\"%s\" \"%s\"", Argv[0], Path); ExecuteAsSystem(AppCmdLine); } LocalFree(Argv); return 0; }
Compilado de forma estándar ocupará 48k. Su versión Mini ocupa 6k que tras tratarla con PEShrink se reduce a 4k (3.548 Bytes)
Seguro que le encontráis utilidad.
PD: Quizás el tema corresponda mas a un truco, una aplicación terminada, un ejercicio práctico o incluso un minitutorial, pero he preferido publicarlo aquí para animar un poco el subforo ce C/C++, que últimamente está algo aletargado.
Subo un fichero adjunto con el código fuente y el binario compilado.
Saludos.
Edito para restaurar las etiquetas de código perdidas con la última mudanza