Mi viejo chivato

Hoy me puse a recordar viejos tiempos (no tan viejos, no soy tan mayor), y me acorde de un pequeño programa que hice, cuando estaba encargado de las aulas de informática de una universidad, para controlar a los alumnos. Si, lo se, era un poco cabroncete, debia de haber dejado a los chavales que se divirtieran, vieran porno, hablaran por el messenger y que instalaran juegos. Si volviera a dedicarme a lo mismo (no es mal trabajo, te pagan por no hacer casi nada) les dejaria hacer lo que quisieran, pero en aquella epoca me tomaba mi trabajo muy en serio y me salio el policia que llevo dentro.

El programa es bastante curioso, esta hecho completamente en C y compilado con MinGW, pesa sobre 12 Kb y se instala como un servicio de windows. Entre sus funciones estan las de controlar que procesos se ejecutan en la maquina, los titulos de la ventanas y el estado del cable de red. Si el programa detecta una palabra sospechosa en el titulo de una ventana avisa al encargado o la cierra, tambien si detecta que un programa se ejecuta desde un directorio no permitido el programa avisa al encargado o simplemente termina con el. En resumen es un chivato en toda regla, y por si fuera poco emite pitidos por el altavoz del pc a modo de alarma.

El programa tiene dos modos de funcionamiento: el normal y el "agresivo". En el modo normal cuando detecta una infracción envía un mensaje por UDP al ordenador del encargado del aula y en el modo agresivo es cuando "destruye" la causa de la infracción, cerrando la ventana o terminando el proceso. Para pasar de un modo a otro se utilizan los códigos de control del servicio. Os preguntareis que pasa si un listillo desconecta el cable de red con la esperanza de que los avisos nunca lleguen hasta el encargado, pues lo que pasa es que el programa lo detecta y pasa inmediatamente al modo "agresivo".

Pero veamos un poco de código:

#include <windows.h>;
#include <winsock.h>;
#include <psapi.h>;
#include <stdio.h>;
 
#define INFO "Version: 1.0.2 (15/09/2005)\n" 
 
#define ServiceName "ChvtServ"
#define DisplayName "Chivato NT Service"
#define SERVICE_CONTROL_KILLALL 150
#define SERVICE_CONTROL_RESET 151
 
#define DIR1 "c:\\Archivos de programa\\"
#define DIR2 "c:\\Archiv~1\\"
#define DIR3 "c:\\Windows\\"
#define DIR4 "\\SystemRoot\\"
#define DIR5 "\\??\\"
#define DIR6 "c:\\PIPOVEN\\"
 
#define VIGILANTE "EDU000"
#define INIFILE "C:\\windows\\chvt.ini"
 
#define ROOTKEY HKEY_LOCAL_MACHINE
#define KEY "SOFTWARE\\Chivato"
#define AUTOR "Domingo Seoane"
 
//NT Service
SERVICE_STATUS ServiceStatus;
SERVICE_STATUS_HANDLE ServiceStatusHandle = 0;
HANDLE StopServiceEvent = 0;
HANDLE KillAllEvent = 0;
 
//Lista negra
struct item
{
 char *texto;
 struct item *next;      
};
 
struct item *lista_negra = NULL;
 
char Vigilante[15];
 
// NT Service
void WINAPI ServiceControlHandler(DWORD fdwControl);
void WINAPI ServiceMain(DWORD dwArgc,LPTSTR *lpszArgv);
void RunService();
void InstallService();
void UninstallService();
 
BOOL ComprobarRed();
void EnviarMensaje(char *Mensaje, u_short Puerto);
void ComprobarProcesos();
 
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam);
BOOL Sospechoso(char *texto, char *nombre);
void AgregarPalabra(char *text);
void CargarLista();
void Configuracion();
 
int main(int argc, char *argv[])
{
 if (argc == 2)
 {
  if (stricmp(argv[1],"/I")==0 || stricmp(argv[1],"-I")==0) 
  {
   InstallService(); 
   return 0;
  }
  if (stricmp(argv[1],"/U")==0 || stricmp(argv[1],"-U")==0) 
  {
   UninstallService(); 
   return 0;
  }  
  if (stricmp(argv[1],"/V")==0 || stricmp(argv[1],"-V")==0) 
  {
   MessageBox(0,INFO,"Acerca de ...",MB_OK);
   return 0;
  } 
 }
 RunService();
 return 0;
}
 
void WINAPI ServiceControlHandler(DWORD fdwControl)
{
 switch (fdwControl)
 {
  case SERVICE_CONTROL_INTERROGATE:
    break;
  case SERVICE_CONTROL_SHUTDOWN:
  case SERVICE_CONTROL_STOP:
    ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
    SetServiceStatus( ServiceStatusHandle, &ServiceStatus );
    SetEvent( StopServiceEvent );
    return;
  case SERVICE_CONTROL_KILLALL:
    SetEvent(KillAllEvent);
    break;
  case SERVICE_CONTROL_RESET:
    ResetEvent(KillAllEvent);   
    break;
 }
 SetServiceStatus(ServiceStatusHandle, &ServiceStatus );
}
 
 
void WINAPI ServiceMain(DWORD dwArgc,LPTSTR *lpszArgv)
{   
 WSADATA wsaData; 
 
 ServiceStatus.dwServiceType = SERVICE_WIN32;
 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
 ServiceStatus.dwControlsAccepted = 0;
 ServiceStatus.dwWin32ExitCode = NO_ERROR;
 ServiceStatus.dwServiceSpecificExitCode = NO_ERROR;
 ServiceStatus.dwCheckPoint = 0;
 ServiceStatus.dwWaitHint = 0;
 
 ServiceStatusHandle = RegisterServiceCtrlHandler(ServiceName, ServiceControlHandler);
 
 if (ServiceStatusHandle)
 {
  // Iniciando ...
  ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
  SetServiceStatus(ServiceStatusHandle, &ServiceStatus );
  StopServiceEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  KillAllEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  if (StopServiceEvent && KillAllEvent)
  {
   WSAStartup(MAKEWORD(1,1), &wsaData);
   if (wsaData.wVersion==MAKEWORD(1,1))
   {
    CargarLista();
    Configuracion();
    ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
    ServiceStatus.dwCurrentState = SERVICE_RUNNING;
    SetServiceStatus(ServiceStatusHandle, &ServiceStatus );
    // Corriendo ..
    do
    {
      ComprobarProcesos();
      EnumWindows(EnumWindowsProc,0);
    }
    while (WaitForSingleObject(StopServiceEvent, 500 ) == WAIT_TIMEOUT);
    WSACleanup(); 
   } 
  }
  // Parando ...
  ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
  SetServiceStatus(ServiceStatusHandle, &ServiceStatus );
  CloseHandle(StopServiceEvent);
  CloseHandle(KillAllEvent);
  StopServiceEvent = NULL;
  KillAllEvent = NULL;
  // Parado
  ServiceStatus.dwControlsAccepted = 0;
  ServiceStatus.dwCurrentState = SERVICE_STOPPED;
  SetServiceStatus(ServiceStatusHandle, &ServiceStatus );
 }
}
 
void RunService()
{
 SERVICE_TABLE_ENTRY ServiceTable[] =
 {
  {ServiceName, ServiceMain},
  { 0, 0 }
 };
 
 StartServiceCtrlDispatcher( ServiceTable );
}
 
void InstallService()
{
 SC_HANDLE ServiceControlManager;
 SC_HANDLE Service;
 char Path[MAX_PATH + 1]; 
 
 ServiceControlManager = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE);
 if (ServiceControlManager)
 {
  memset(Path,0,sizeof(Path));
  if (GetModuleFileName(0,Path,sizeof(Path)-1) > 0)
  {
   Service = CreateService(ServiceControlManager,ServiceName, DisplayName,
                           SERVICE_ALL_ACCESS, 
                           SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
                           SERVICE_AUTO_START, SERVICE_ERROR_IGNORE, Path,
                           0, 0, 0, 0, 0 );
   if (Service) CloseServiceHandle(Service);
  }
  CloseServiceHandle(ServiceControlManager);
 }
}
 
void UninstallService()
{
 SC_HANDLE ServiceControlManager; 
 SC_HANDLE Service;
 SERVICE_STATUS ServiceStatus; 
 
 ServiceControlManager = OpenSCManager( 0, 0, SC_MANAGER_CONNECT );
 if (ServiceControlManager)
 {
  Service = OpenService( ServiceControlManager,ServiceName, 
                         SERVICE_QUERY_STATUS | DELETE );
  if (Service)  
  {   
   if (QueryServiceStatus(Service, &ServiceStatus ))
   {
    if (ServiceStatus.dwCurrentState == SERVICE_STOPPED )
    DeleteService(Service);
   }
   CloseServiceHandle(Service);
  }
  CloseServiceHandle(ServiceControlManager);
 }
}
 
char *strscat (char *to, const char *from, size_t size)
{
 return strncat(to,from,size - (strlen(to)+1)); 
}
 
void EnviarMensaje(char *Mensaje, u_short Puerto)
{
 LPHOSTENT lpHostEntry;
 SOCKET Socket;
 SOCKADDR_IN SockAddr;
 char buf[256];
 
 memset(buf,0,sizeof(buf));
 if (gethostname(buf, sizeof(buf)) == 0)
 { 
  lpHostEntry = gethostbyname(Vigilante);
  if (lpHostEntry != NULL)
  {   
   Socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
   if (Socket != INVALID_SOCKET)
   {         
    SockAddr.sin_family = AF_INET;
    SockAddr.sin_addr = *((LPIN_ADDR)*lpHostEntry->h_addr_list);
    SockAddr.sin_port = htons(Puerto); 
    strupr(buf);
    strscat(buf,":",sizeof(buf));
    strscat(buf,Mensaje,sizeof(buf)); 
    sendto(Socket,buf,strlen(buf),0,(LPSOCKADDR)&SockAddr,sizeof(struct sockaddr));   	
    closesocket(Socket); 
   } 
  } 
 }   
}
 
BOOL ComprobarRed()
{
 LPHOSTENT lpHostEntry;
 struct in_addr addr;
 char buf[128];
 
 memset(buf,0,sizeof(buf));
 if (gethostname(buf, sizeof(buf)) == 0)
 {   
  lpHostEntry = gethostbyname(buf);
  if (lpHostEntry != NULL)
  {   
   memcpy(&addr, lpHostEntry->h_addr_list[0], sizeof(struct in_addr));
   if (addr.S_un.S_un_b.s_b1!=10) return FALSE; 
     else return TRUE;   
  } else return FALSE;
 } else return FALSE;
}
 
void ComprobarProcesos()
{
 DWORD lista[1024];
 HANDLE proceso;
 char nombre[1024];
 DWORD l;
 int i;
 BOOL ok; 
 BOOL kill;
 
 ok = TRUE;
 kill = !ComprobarRed() || (WaitForSingleObject(KillAllEvent,0)==WAIT_OBJECT_0);
 if (!EnumProcesses(lista, sizeof(lista), &l))
   return;
 l = l / sizeof(DWORD); 
 for ( i = 0; i<l && ok; i++ )
 {
  proceso = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ 
                        | PROCESS_TERMINATE,FALSE,lista[i]);
  if (proceso != NULL)
  { 
   if (GetModuleFileNameEx(proceso,NULL,nombre,sizeof(nombre)-1))
   {
    if (strncasecmp(nombre,DIR1,strlen(DIR1))!=0)
      if (strncasecmp(nombre,DIR2,strlen(DIR2))!=0) 
        if (strncasecmp(nombre,DIR3,strlen(DIR3))!=0)
          if (strncasecmp(nombre,DIR4,strlen(DIR4))!=0)
            if (strncasecmp(nombre,DIR5,strlen(DIR5))!=0)
              if (strncasecmp(nombre,DIR5,strlen(DIR6))!=0)
                if (kill) TerminateProcess(proceso,0);
                  else ok = FALSE;       
   }    
   CloseHandle( proceso );               
  }
 }
 if (!ok) 
 {
  EnviarMensaje(nombre,1978);
  WaitForSingleObject(StopServiceEvent, 2000);
 }  
}
 
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
 char *texto;
 char *nombre;
 int l;
 DWORD ProcessID;
 HANDLE hProcess;
 BOOL ok = TRUE;
 
 if (IsWindowVisible(hwnd))
 {                                                   
  l = SendMessage(hwnd,WM_GETTEXTLENGTH,0,0) + 1;
  if (l>1)
  {
   texto = (char*) malloc(l);
   if (texto)
   {
    SendMessage(hwnd,WM_GETTEXT,l,(WPARAM)texto);
    strupr(texto);
    nombre = (char*) malloc(MAX_PATH+1);
    if (nombre)
    {
     GetWindowThreadProcessId(hwnd,&ProcessID);  
     hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | 
                            PROCESS_VM_READ  | 
                            PROCESS_TERMINATE ,FALSE,ProcessID);
     if (hProcess!=NULL)
     {      
      if (GetModuleBaseName(hProcess,NULL,nombre,MAX_PATH))
      {  
       strupr(nombre);                                                        
       if (Sospechoso(texto, nombre)) 
       {                          
        EnviarMensaje(texto,1979);
        ok = FALSE;
       }  
      }
      CloseHandle( hProcess );      
     }
     free(nombre);   
    }
    free(texto);     
   }        
  }        
 } 
 if (!ok) 
 {  
  WaitForSingleObject(StopServiceEvent, 2000);
  return FALSE;
 }  
 return TRUE;    
}
 
BOOL Sospechoso(char *texto, char *nombre)
{ 
 struct item *guia;    
 if (strstr(nombre,"IEXPLORE.EXE"))
 {
  if (lista_negra)
  {
   guia=lista_negra;
   while (guia)
   {
    if (strstr(texto,guia->texto))
     return TRUE;  
    guia = guia->next;      
   }
   return FALSE;  
  } else return TRUE;                           
 } 
 return FALSE; 
}
 
// Lista negra
void AgregarPalabra(char *text)
{
 struct item *nuevo; 
 struct item *guia; 
 
 if (text==NULL) return;   
 guia=lista_negra;
 while (guia)
 {
  if (strstr(text,guia->texto))
    return; 
  guia = guia->next;      
 }  
 nuevo = (struct item*) malloc(sizeof(struct item));
 nuevo->texto = strdup(text);
 nuevo->next = lista_negra;
 lista_negra = nuevo; 
}
 
void CargarLista()
{
 FILE *archivo;
 char buf[50];
 
 archivo = fopen(INIFILE,"r");
 if (archivo != NULL)
 {
  memset(buf,0,sizeof(buf));
  while (fgets(buf,sizeof(buf)-1,archivo)!=NULL)
  {   
   if (strlen(buf)>0) 
   { 
    if (buf[strlen(buf)-1]=='\n')  
      buf[strlen(buf)-1]='\0';      
    if (strlen(buf)>0) 
    {      
     strupr(buf);
     AgregarPalabra(buf);     
    } 
   }     
  }
  fclose(archivo);           
 }    
}
 
void Configuracion()
{
 HKEY hKey;
 DWORD Disp;
 DWORD Type;
 DWORD Data;
 DWORD Size;
 char  buf[15];
 
 strcpy(Vigilante,VIGILANTE);
 if (RegCreateKeyEx(ROOTKEY,KEY,0,NULL,REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,&hKey,&Disp)==ERROR_SUCCESS)
 {
  RegSetValueEx(hKey,"Autor",0,REG_SZ,(BYTE*)AUTOR,strlen(AUTOR)+1);
  Size = sizeof(Data);
  if (RegQueryValueEx(hKey,"Killall",0,&Type,(BYTE*)&Data,&Size)==ERROR_SUCCESS)
   if (Type==REG_DWORD)
    if (Data) SetEvent(KillAllEvent);
  memset(buf,0,sizeof(buf));
  Size = sizeof(buf);
  if (RegQueryValueEx(hKey,"Vigilante",0,&Type,buf,&Size)==ERROR_SUCCESS)
   if (Type==REG_SZ)
    if (strlen(buf)>0) strcpy(Vigilante,buf);
  RegCloseKey(hKey);                                                
 }      
 
}

Solo pongo el código para recordar viejos tiempos, pero si a alguien le interesa profundizar mas en el tema que me lo haga saber.

Que buen código !! Funcionará

Que buen código !!

Funcionará para linux en alguna de sus distribuciones ?

De cualquier manera saludos desde México !!

Hola seaone. Resulta que

Hola seaone.

Resulta que ahora me han encomendado un proyecto parecido, yo el c ni lo he tocado, tienes algo parecido en delphi, o tal ves me puedes dar algunos tips para traducir este código, bueno por el momento estoy estudiandomelo que al parecer me va a dar mucho trigo.

saludos

Enviar un comentario nuevo

El contenido de este campo se mantiene privado y no se mostrará públicamente.