Ir al contenido



Foto

MiniSystem, una miniaplicación para ejecutar programas con privilegios SYSTEM


  • Por favor identifícate para responder
3 respuestas en este tema

#1 escafandra

escafandra

    Advanced Member

  • Moderadores
  • PipPipPip
  • 3.849 mensajes
  • LocationMadrid - España

Escrito 23 mayo 2011 - 05:28

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:


delphi
  1. 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:


cpp
  1. #include <windows.h>
  2. #include <Shlwapi.h>
  3. #pragma hdrstop
  4.  
  5. #define SimbolName L"_shuttle_"
  6. BOOL IsService()
  7. {
  8.   SC_HANDLE scManager;
  9.   SC_HANDLE scService = 0;
  10.  
  11.   scManager = OpenSCManagerW(0, NULL, SC_MANAGER_ALL_ACCESS);
  12.   if(scManager){
  13.     scService = OpenServiceW(scManager, SimbolName, SERVICE_ALL_ACCESS);
  14.     CloseServiceHandle(scService);
  15.     CloseServiceHandle(scManager);
  16.   }
  17.   return (BOOL)scService;
  18. }
  19.  
  20. void ExecuteAsSystem(WCHAR* Path)
  21. {
  22.   SC_HANDLE scManager;
  23.   SC_HANDLE scService;
  24.  
  25.   scManager = OpenSCManagerW(0, NULL, SC_MANAGER_ALL_ACCESS);
  26.   if(scManager){
  27.     scService = CreateServiceW(scManager, SimbolName, SimbolName, SERVICE_ALL_ACCESS,
  28.                                 SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START,
  29.                                 SERVICE_ERROR_NORMAL, Path, NULL, NULL, NULL, NULL, NULL);
  30.     if(!scService)
  31.         scService = OpenServiceW(scManager, SimbolName, SERVICE_ALL_ACCESS);
  32.     StartService(scService, 0, NULL);
  33.     DeleteService(scService);
  34.     CloseServiceHandle(scService);
  35.     CloseServiceHandle(scManager);
  36.   }
  37. }
  38.  
  39. bool ExecuteAs(WCHAR* FileExe, WCHAR* User, WCHAR* Domain, WCHAR* Password, int nCmdShow = SW_SHOW)
  40. {
  41.   PROCESS_INFORMATION piProcInfo;
  42.   STARTUPINFOW siStartInfo = {0};
  43.   siStartInfo.cb = sizeof(STARTUPINFOW);
  44.   siStartInfo.dwFlags = STARTF_USESHOWWINDOW;
  45.   siStartInfo.wShowWindow = nCmdShow;
  46.  
  47.   WCHAR CurrentDir[MAX_PATH];
  48.   GetCurrentDirectoryW(sizeof(CurrentDir), CurrentDir);
  49.   HRESULT hRes = CreateProcessWithLogonW(User, Domain, Password, LOGON_WITH_PROFILE,
  50.                                         NULL, FileExe, NULL, NULL, CurrentDir,
  51.                                         &siStartInfo, &piProcInfo) ;
  52.   if(hRes){
  53.     CloseHandle(piProcInfo.hProcess);
  54.     CloseHandle(piProcInfo.hThread);
  55.   }
  56.   return (bool)hRes;
  57. }
  58.  
  59. typedef BOOL (WINAPI *PAttachConsole)(DWORD dwProcessId);
  60.  
  61. #pragma argsused
  62. WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
  63. {
  64.   WCHAR *User = 0, *Pass = 0, *Path = 0;
  65.   WCHAR AppCmdLine[MAX_PATH*2];
  66.   int Argc;
  67.   LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc);
  68.   if(Argc == 1){
  69.     char Help[] = "\nMiniSystem [-u User] [-p Password] Path";
  70.     PAttachConsole AttachConsole = (PAttachConsole)GetProcAddress(GetModuleHandle("Kernel32.dll"), "AttachConsole");
  71.     AttachConsole(-1);
  72.     HANDLE F = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0 );
  73.     WriteConsole(F, Help, lstrlen(Help), 0, 0);
  74.     return 0;
  75.   }
  76.   for(int n=1; n<Argc; n++){
  77.     if(!StrCmpNIW(Argv[n], L"-u", 2) && n<Argc-1){
  78.       User = Argv[++n];
  79.     }else if(!StrCmpNIW(Argv[n], L"-p", 2) && n<Argc-1){
  80.       Pass = Argv[++n];
  81.     }else{
  82.       Path = Argv[n];
  83.     }
  84.   }
  85.   if(User && Pass){
  86.     wsprintfW(AppCmdLine, L"\"%s\" \"%s\"", Argv[0], Path);
  87.     ExecuteAs(AppCmdLine, User, 0, Pass);
  88.   }else if(IsService()) {
  89.     PROCESS_INFORMATION pi = {0};
  90.     STARTUPINFOW si = {0};
  91.     si.cb = sizeof(si);
  92.     si.lpDesktop = L"WinSta0\\Default";
  93.     CreateProcessW(0, Path, 0,0,0,0,0,0,&si,&pi);
  94.   }else{
  95.     if(*(Argv[0]+1) != L':'){
  96.       WCHAR CurrentDir[MAX_PATH];
  97.       GetCurrentDirectoryW(sizeof(CurrentDir), CurrentDir);
  98.       wsprintfW(AppCmdLine, L"\"%s\\%s\" \"%s\"", CurrentDir, Argv[0], Path);
  99.     }
  100.     else
  101.       wsprintfW(AppCmdLine, L"\"%s\" \"%s\"", Argv[0], Path);
  102.     ExecuteAsSystem(AppCmdLine);
  103.   }
  104.  
  105.   LocalFree(Argv);
  106.   return 0;
  107. }

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

Archivos adjuntos


  • 0

#2 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.137 mensajes

Escrito 23 mayo 2011 - 06:10

Gracias, escafandra, como siempre excelentes tus trabajos. (y) (y)

Saludos

  • 0

#3 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 13.966 mensajes
  • LocationMéxico

Escrito 23 mayo 2011 - 07:43

Admiro la forma como "juegas" con el API de windows amigo escafandra, que envidia me das :)

Salud OS
  • 0

#4 escafandra

escafandra

    Advanced Member

  • Moderadores
  • PipPipPip
  • 3.849 mensajes
  • LocationMadrid - España

Escrito 24 mayo 2011 - 02:39

Admiro la forma como "juegas" con el API de windows amigo escafandra, que envidia me das

Salud OS



Una de las desventajas de jugar con la API de un S.O. es su dependencia e este.  ^o|
Aunque una de las ventajas es su portabilidad entre distintos lenguajes para un mismo S.O.  Así que migrar el código a delphi es casi inmediato.  :)




Saludos.




  • 0