miércoles, 3 de marzo de 2010

Sólo Memorias USB autorizadas

Introducción

En este artículo les explico como hacer una aplicación que esté corriendo en nuestro equipo como un "servicio de windows", este software nos detectará cuando se conecte una memoria USB a nuestro computador y determinará si está autorizada, si no lo está la formatea sin pedir confirmación.

IMPORTANTE:

POR FAVOR LEE ATENTAMENTE ESTE ARTÍCULO ANTES DE USAR EL
CÓDIGO.

YA QUE SI LO USAS DE FORMA INADECUADA PUEDES PERDER INFORMACIÓN GRABADA EN DISCOS (o memorias) USB.

Tal como se indica en el texto:
La comprobación de si la memoria está o no autorizada para conectarse en nuestro equipo lo hacemos evaluando si existe un archivo que llamaremos kill.dll

Contenido

En la empresa donde trabajo actualmente teníamos muchos problemas con los virus, ya que algunos empleados (tal vez mal intencionados) conectaban memorias USB infectadas en los computadores que tenemos en las sucursales, propagando de esa forma los virus, algunos muy dañinos, otros no tanto.
Luego de tratar de encontrar una solución a dicha problemática, decidí crear un software que sólo permitiera que ciertas memorias USB autorizadas se pudiesen conectar a nuestros equipos y si esta memoria no estaba "autorizada" sería formateada. Todo el código ha sido hecho por mí, lo único diferente que utilizo es una dll que descargué de Internet, la cual sirve para colocar el icono de la aplicación en el systray y mostrará un mensaje cuando la memoria no esté "autorizada" diciendo que la ha formateado... jejeje... Esta aplicación esta hecha en Visual Basic .NET 2008, pero debe funcionar para las versiones anteriores

El código:

Vamos a iniciar un nuevo proyecto del tipo Aplicación de Windows, al formulario que se crea sólo le vamos a agregar un control de tipo Timer, lo llamaré Temporizador. En la clase del formulario colocaremos las siguientes declaraciones:
'Esta constante corresponde al valor del WParam del mensaje que se envia a la forma cuando se minimiza
    Private Const SC_MINIMIZE = &HF020&
    'Esta variable nos coloca el icono en el systray y nos muestra los mensajes correspondientes
    Private Msg As New globoShell
    'Para el tipo del disco
    Private l_Tipo As String = As String Nothing
    'Vector que tiene guardado las posibles unidades
    Private Vector() As String = {"C", "D", "E", "F", "G", "H", "I"}
Utilizaré un método que nos va a permitir saber si nuestra aplicación está en ejecución, esto lo hacemos para evitar que nuestra aplicación se cargue más de una vez. Este método no recibe ningún parámetro y retorna un
booleano:
Public Function InstanciaPrev() As Boolean
    If UBound(Diagnostics.Process.GetProcessesByName(Diagnostics.Process.GetCurrentProcess.ProcessName)) > 0 Then
     Return True
    Else
        Return False
    End If
End Function
En el Load del Formulario colocaremos el siguiente código, primero preguntaremos si ya se está ejecutando la aplicación, luego preguntaremos si tenemos un acceso directo de nuestra aplicación en la carpeta inicio, esto es para que cada vez que un usuario inicie sesión en nuestro equipo la aplicación comience automáticamente, minimizamos nuestra aplicación, no permitimos que se muestre en la barra de tareas, mandamos el formulario al systray y habilitamos el temporizador... Por cierto, nuestra aplicación la llamaremos Daemon y nuestro formulario Frm_BorradoUSB:
'Evaluamos que no esté cargada la aplicación
    If InstanciaPrev() Then
        'Cerramos la nueva aplicación
     Application.Exit()
    End If
    'Evaluaremos si no se encuentra el acceso directo a nuestra aplicación en la carpeta inicio
    If Not File.Exists("C:\Documents and Settings\All Users\Menú Inicio\Programas\Inicio\Daemon.exe.lnk") Then
        'Creamos el acceso directo
     Dim ob As Object = CreateObject("WScript.Shell")
     Dim vlnk As Object
     vlnk = ob.CreateShortcut & _
     ("C:\Documents and Settings\All Users\Menú Inicio\Programas\Inicio\Daemon.exe.lnk")
     'Buscamos nuestro .exe, puede estar en cualquier carpeta
     vlnk.Targetpath = Application.StartupPath & "\Daemon.exe"
     vlnk.Save()
    End If
    'Minimizamos la ventana
    WindowState = FormWindowState.Minimized
    'No permitimos que aparezca en la barra de herramientas
    ShowInTaskbar = False
    'Adicionamos el icono en el systray
    Msg.AddIcon( Me )
    'Habilitamos el temporizador
    Temporizador.Enabled = True
Utilizaré una propiedad llamada Tipo que nos retornará el tipo de disco que se encuentra conectado a nuestro computador, tenga en cuenta que las memorias USB siempre son de tipo USB:
Public Property Tipo() As String
    Get
        Return l_Tipo
    End Get
    Set(ByVal value As String)
        l_Tipo = value
    End Set
End Property
Al timer utilizado le coloqué un intervalo por defecto de 1000 milisegundos (un segundo), esto quiere decir que el software cada segundo estará buscando si tenemos una memoria USB conectada. Ahora, en el evento
Tick del Timer colocaremos el siguiente código:
'Determinamos los discos que tenemos
    Dim DatosHDD As New ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive")
    'Recorremos todos los discos conectados para ver cuales son de tipo USB
    For Each DskWmi As ManagementObject In DatosHDD.[Get]()
        Dim Dsk As New Frm_BorradoUSB
        Dsk.Tipo = DskWmi("InterfaceType").ToString()
        If Dsk.Tipo = "USB" Then
            'Ejecutamos el método que nos verifica si es una memoria autorizada
            Ejecutar()
        End If
    Next
Crearemos un método que se llamará Ejecutar el cual nos determinará si la memoria USB está autorizada o no, si no lo está llamará a otro método que se encargará de formatear la USB. La comprobación de si la memoria está o no autorizada para conectarse en nuestro equipo lo hacemos evaluando si existe un archivo que llamaremos kill.dll:
Private Sub Ejecutar()
    'Deshabilitamos temporalmente el timer
    Temporizador.Enabled = False
    'Variable que guarda la unidad de la memoria
    Dim U As String = Unidad()
    'Obtenemos los subdirectorios y los archivos localizados en la carpeta raíz de la memoria
    Dim strDir2() As String
    Dim strFlies2() As String
    strDir2 = System.IO.Directory.GetDirectories(U & ":\", "*.*")
    strFlies2 = System.IO.Directory.GetFiles(U & ":\", "*.*")
    'Evaluamos si la memoria está autorizada
    If Not File.Exists(U & ":\kill.dll") Then
        'La memoria no está autorizada, pero evaluamos si está vacía
        If strDir2.Length > 0 Or strFlies2.Length > 0 Then
            'Mostramos el mensaje de formateo
            Msg.WNotification("HAS CONECTADO UNA MEMORIA USB COMO DISCO " & U & ":\ FORMATEANDO MEMORIA...")
            'Borramos los datos
            BorrarDatos(U)
            'Mostramos el mensaje de que se ha formateado correctamente
            Msg.WNotification("MEMORIA USB FORMATEADA CORRECTAMENTE!!!")
        End If
    Else
     If Not Temporizador.Interval = 1000 Then
            Temporizador.Interval = 1000
        End If
    End If
    'Habilitamos nuevamente el timer
    Temporizador.Enabled = True
End Sub
El siguiente método formateará completamente la memoria, le enviamos como parámetro la ruta de la memoria, se utilizará un archivo txt para que al momento de formatear no se nos pida confirmación, luego crearemos un .bat que formateará la unidad y por último ejecutaremos este .bat...
Nota:
Amigos, no utilicen este código para hacer cosas indebidas, confío en que le van a dar un uso adecuado...
Private Sub BorrarDatos(ByVal sourceDir As String)
    Temporizador.Interval = 10000
    'Asignamos la ruta del .txt que llamaremos intro
    Dim ruta As String = "C:\Windows\System32\intro.txt"
    'Preguntamos si no existe el .txt
    If Not File.Exists(ruta) Then
        'Abrimos el archivo para escribir
        Dim x As New StreamWriter(ruta)
        'Introducimos los datos necesarios en el documento
        x.WriteLine("S")
        x.WriteLine("")
        x.WriteLine("")
        'Cerramos el archivo
        x.Close()
    End If
    ruta = "C:\Windows\System32\format.bat"
    'Preguntamos si existe la ruta específicada
    If File.Exists(ruta) Then
        'Borramos el archivo
        File.Delete(ruta)
    End If
    'Creamos nuevamente el archivo
    Dim bat As New StreamWriter(ruta)
    'Introducimos los datos necesarios en el documento
    bat.Write("FORMAT " & sourceDir & ": < C:\Windows\System32\intro.txt")
    'Cerramos el archivo
    bat.Close()
    'Ejecutamos el .bat
    Shell(ruta)
End Sub
Por último tendremos un método que es el que nos va a determinar en que unidad está conectada la memoria, nos retornará un string:
Private Function Unidad() As String
    'Variable que se va a retornar
    Dim mem As String = Vector(6)
    'Variable que irá decrementando los ítems del vector
    Dim i As Integer = 6
    'El ciclo funciona hasta que encuentra una unidad conectada
    While Not Directory.Exists(mem & ":\")
        i = i - 1
        mem = Vector(i)
    End While
    'Retornamos la unidad de la memoria
    Return mem
End Function

Espero que este código les haya sido de gran utilidad, si tienen alguna duda o sugerencia me pueden escribir al mail... Esta aplicación la tenemos en los equipos de nuestra empresa y se han acabado los problemas que teníamos con los virus.


Espacios de nombres usados en el código de este artículo:

System.IO
System.Management
System.Runtime.InteropServices
dllGlobos
Lo comentado en este artículo está probado (y funciona) con la siguiente configuración:
  • Sistema operativo:

    • Windows XP SP1
    • Windows XP SP2
    • Windows XP SP3
    • Windows Vista Ultimate
  • IDE (entorno de desarrollo):

    • Visual Studio 2008
    • Visual Studio 2005
    • Visual Studio 2003
    • Bloc de notas
El autor se compromete personalmente de que lo expuesto en este artículo es cierto y lo ha comprobado usando la configuración indicada anteriormente.
En cualquier caso, el Blog no se responsabiliza del contenido de este artículo.
Si encuentras alguna errata o fallo en algún link (enlace), por favor comunícalo usando este link:

Gracias.
Por favor, lee atentamente el artículo antes de usar el código, ya que puedes perder información contenida en discos (o memorias) USB

1 comentario:

  1. gran aporte!! gracias necesitaba algo asi!! claro no formateare una usb pero quiero hacer una lectura si existe un archivo que yo le otorgue y tener el programa en ejecucion y cuando la conecte se ejecute mi programa es posible utilizar tu codigo?

    ResponderEliminar