Biblioteca Online : ¡La Suscripción ENI por 9,90 € el primer mes!, con el código PRIMER9. Pulse aquí
¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
  1. Libros
  2. Seguridad informática y Malwares
  3. Técnicas de ofuscación
Extrait - Seguridad informática y Malwares Análisis de amenazas e implementación de contramedidas (3ª edición)
Extractos del libro
Seguridad informática y Malwares Análisis de amenazas e implementación de contramedidas (3ª edición) Volver a la página de compra del libro

Técnicas de ofuscación

Introducción

En el dominio del desarrollo informático, la ofuscación consiste en transformar un programa de manera que, aunque se mantiene su comportamiento, se dificulta su comprensión. La idea es hacer que el código del programa sea lo menos intuitivo posible, de modo que su lectura resulte compleja. Esta práctica puede parecer sorprendente para los desarrolladores. En efecto, por lo general un buen programa posee un código perfectamente legible para facilitar su mantenimiento, que otras personas puedan modificarlo; corregirlo o mejorarlo.

La ofuscación de código se utiliza en tres casos representativos:

  • Proteger la propiedad intelectual: ciertas empresas no desean que sus competidores puedan copiar su conocimiento técnico o que sus productos puedan copiarse y utilizarse de manera ilegal (sin pagar una licencia). 

  • Ralentizar los análisis en caso del análisis de malware; cuanto más tiempo lleve el análisis, más tiempo estará funcional el malware.

  • Hacer que los antivirus sean menos eficaces: tras la ofuscación, el archivo binario puede parecer diferente y no corresponderá con una firma existente.

Existen muchas formas de hacer que un código sea muy complicado de leer. En el análisis de malwares, un método utilizado con frecuencia es la ofuscación de las cadenas de caracteres. Aquí, el desarrollador...

Ofuscar cadenas de caracteres

1. Introducción

Esta sección aborda las técnicas que permiten ocultar cadenas de caracteres presentes en un archivo binario. Sin cadenas de caracteres legibles, el análisis de un binario puede complicarse: se hace imposible leer los nombres de los archivos abiertos, las claves de registro a las que se accede o los sitios de Internet con los que se ha contactado… Veremos cinco procedimientos que permiten ocultar cadenas de caracteres. Estas técnicas se han clasificado desde la más simple a la más complicada de comprender.

  • Usar ROT13

  • Usar la función XOR con una clave estática

  • Usar XOR con una clave dinámica

  • Usar funciones criptográficas

  • Usar funciones personalizadas

2. Usar ROT13

El ROT13 es un algoritmo simple de cifrado de texto. Consiste en desplazar 13 caracteres cada letra del alfabeto (cifrado César). He aquí la tabla de conversión:

A

B

C

D

E

F

G

H

I

J

K

L

M

N

O

P

Q

R

S

T

U

V

W

X

Y

Z

N

O

P

Q

R

S

T

U

V

W

X

Y

Z

A

B

C

D

E

F

G

H

I

J

K

L

M

La primera fila de la tabla corresponde a la letra inicial y la segunda, a la nueva letra tras aplicar la función ROT13. Según esta tabla, la dirección http://www.google.es se convertiría en uggc://jjj.tbbtyr.rf. Es posible adivinar que la cadena de caracteres corresponde a una URL. El malware HerpesNet (hash md5 del archivo que lo identifica inequívocamente: db6779d497cb5e22697106e26eebfaa8) utiliza este tipo de codificación para almacenar sus cadenas de caracteres.

He aquí la salida del comando strings sobre este malware:

rootbsd@lab:~/$ strings herpesnet.exe 
[...] 
tcerfhygy 
uggc://qq.mrebkpbqr.arg/urecarg/ 
74978o6rpp6p19836n17n3p2pq0840o0 
uggc://jjj.mrebkpbqr.arg/urecarg/ 
sgc.mrebkpbqr.arg 
uggc://sex7.zvar.ah/urecarg/ 
hcybnq@mrebkpbqr.arg 
hccvg 
ujsdsdbbngfgjhhuugfgfujd 
rffggghooo 
Ashfurncsmx 
[...] 

Podemos identificar cadenas de caracteres que empiezan por «uggc». Este tipo de información puede indicar el uso de la función ROT13. En Linux, existe un comando que permite realizar un ROT13:

rootbsd@lab:~$ strings herpesnet.exe | rot13 
[...] 
gpresultl 
http://dd.zeroxcode.net/herpnet/ 
74978b6ecc6c19836a17a3c2cd0840b0 
http://www.zeroxcode.net/herpnet/ 
ftp.zeroxcode.net 
http://frk7.mine.nu/herpnet/ 
upload@zeroxcode.net 
uppit 
hwfqfqooatstwuuhhtstshwq 
esstttubbb 
Nfusheapfzk 
[...] 

Veremos aparecer las URL del servidor web o del servidor FTP.

Este tipo de codificación es fácil de identificar viendo el resultado, pero su implementación en ensamblador puede resultar muy compleja. He aquí el código en ensamblador de la función ROT13 del malware HerpesNet. El valor que se ha de decodificar se encuentra en el registro ECX:

00403034 ; ===== S U B R O U T I N E ======================= 
00403034 
00403034 
00403034 decode  proc near    ; CODE XREF: initVariable+2A#p 
00403034                      ; initVariable+34#p ... 
00403034                 cmp     byte ptr [ecx], 0 
00403037                 push    esi 
00403038                 mov     esi, ecx 
0040303A                 jz      short LAB_403078 
0040303C                 push    edi 
0040303D 
0040303D LAB_40303D:          ; CODE XREF: decode+41#j 
0040303D                 mov     al, [ecx] 
0040303F                 cmp     al, 61h 
00403041                 jl      short LAB_403058 
00403043                 cmp     al, 7Ah 
00403045                 jg      short LAB_403058 
00403047                 movsx   eax, al ...

Ofuscar el uso de la API de Windows

1. Introducción

Las llamadas a la API de Windows también se pueden ocultar. En este caso, el analista no podrá leer el nombre de una función invocada por el programa. Existen varias formas de ocultar los usos de la API: una de ellas consiste en crear nuestra propia función GetProcAddress(). Esta función, provista por Microsoft, permite conocer la dirección de memoria de una función en particular. He aquí el prototipo de esta función:

FARPROC WINAPI GetProcAddress( 
 _In_   HMODULE hModule, 
 _In_   LPCSTR lpProcName 
); 

El primer argumento contiene la biblioteca que debe consultarse, y el segundo, el nombre de la función. Esta función devuelve la dirección de la función que se pasa como segundo argumento.

He aquí un ejemplo sencillo de uso de esta biblioteca:

 PGNSI pGNSI; 
 pGNSI = (PGNSI) GetProcAddress( 
   GetModuleHandle(TEXT("kernel32.dll")), 
   "CreateProcessW"); 

Es fácil comprender que GetProcAddress() devuelve la dirección de la función CreateProcessW() disponible en el archivo kernel32.dll.

Una de las técnicas más extendidas para ocultar las llamadas a las bibliotecas es crear nuestra propia función GetProcAddress(), que recibirá como argumento no el nombre de la función, sino un identificador (un hash, una palabra clave…). Se devuelve, entonces, la dirección de la función y el call (llamada) se hará directamente a esta dirección.

En el caso de un análisis dinámico, los depuradores mostrarán el nombre de las funciones completas con todas sus letras, ya que estos nombres se resolverán necesariamente cuando se ejecute la función call.

En el caso de un análisis estático, habrá que realizar un trabajo previo que permita obtener una matriz de correspondencias entre el identificador utilizado por la falsa función GetProcAddress() y el verdadero nombre de la función final. 

A modo de ejemplo, estudiaremos la ofuscación de la API realizada por el malware Duqu.

2. Estudio del caso de Duqu

En el malware Duqu, la función importante correspondiente a la ofuscación de la API es FUN_4017E2. Esta función recibe cinco argumentos. He aquí el uso de la función en IDA Pro:

00401E34                 push    eax 
00401E35                 push    5FC5AD65h 
00401E3A                 push    [ebp+viewonNTDLL] 
00401E3D                 push    [ebp+NTDLLmodhdl] 
00401E40                 push    [ebp+imports] 
00401E43                 call    FUN_4017E2 

El primer argumento interesante es 5FC5AD65, que corresponde al identificador de la función que se va a ejecutar. El otro argumento interesante es ebp+viewonNTDLL. Este argumento es un puntero a la biblioteca en memoria. En nuestro ejemplo, es un puntero hacia ntdll.dll. Ambos argumentos se pasan, a continuación, a la función: FUN_401485.

004017F8                 push    [ebp+function_hash] 
004017FB                 push    [ebp+viewonNTDLL] 
004017FE                 call    FUN_401485 

Esta función recorrerá toda la biblioteca en memoria y hará un hash de cada una de las funciones disponibles. Cuando el hash corresponda con el que se pasa como argumento...

Empaquetadores

1. Introducción

Una de las técnicas más utilizadas para complicar los análisis de malwares consiste en utilizar un compresor o empaquetador (packers). Un packer es una aplicación que permite comprimir, codificar e incluso cifrar un archivo binario sin alterar su funcionamiento. Existe una multitud de packers; entre los más conocidos podríamos citar Armadillo, ASPack, ASProtect, Themida, UPX... Algunos packers tienen como objetivo hacer que la ingeniería inversa resulte más complicada y otros simplemente buscan comprimir el binario para que ocupe menos espacio y sea más fácil de distribuir. Existen packers de código abierto, así como comerciales.

La técnica que permite analizar malwares ofuscados por packers consiste en encontrar o restaurar el archivo binario original. Esta operación se denomina unpack (o «desempaquetar» un malware). Es posible que ciertos malwares utilicen varias capas de packers, en cuyo caso hay que desempaquetar el malware capa por capa hasta obtener el binario inicial, que podremos analizar.

Cada packer tiene su propio funcionamiento, pero en la mayoría de los casos el binario inicial se cargará en memoria (completa o parcialmente). El objetivo del análisis es encontrar este binario en memoria y extraerlo. En el caso de los packers que utilizan el montículo (o heap) para almacenar el binario original tras descomprimirlo, el binario inicial se podrá utilizar directamente tras haberlo extraído de la memoria. Para aquellos casos en que el packer use la pila (o stack) para almacenar el binario original, será necesario aplicar correcciones a este binario extraído de la memoria para hacerlo utilizable. En cuanto a los packers extremadamente complejos que utilizan máquinas virtuales para descifrar el malware y que hacen muy difícil el trabajo del analista, estos no serán presentados en este libro.

Para identificar un packer, se puede utilizar YARA con la lista de firmas disponible en la siguiente dirección: https://github.com/MalwareLu/malware-lu/blob/master/tools/yara/packer.yara

He aquí un ejemplo de uso para identificar un packer UPX:

rootbsd@lab:~$ yara yara/packer.yara code_upx.exe 
UPXv20MarkusLaszloReiser code_upx.exe 
UPXV200V290MarkusOberhumerLaszloMolnarJohnReiser code_upx.exe 
UPX20030XMarkusOberhumerLaszloMolnarJohnReiser code_upx.exe 
UPX290LZMAMarkusOberhumerLaszloMolnarJohnReiser code_upx.exe 

YARA reconoce que el binario corresponde a cuatro firmas UPX. Tenga cuidado, algunos malwares que recurren a packers no públicos no dudan en presentar las mismas firmas que packers conocidos para confundir a las herramientas automáticas.

2. Empaquetadores que utilizan la pila

El primer ejemplo de packer que estudiaremos es un packer que recurre a la pila (o stack). El más conocido de ellos es UPX. UPX (de Ultimate Packer for eXecutables) es un packer de código abierto cuyo objetivo es, simplemente, comprimir un archivo binario. Para realizar esto, usa el algoritmo de compresión UCL. Este packer puede utilizarse tanto para binarios de Windows como de Linux. Por otro lado, se puede utilizar el comando upx para empaquetar y desempaquetar un binario:

rootbsd@lab:~$ upx 
                      Ultimate Packer for eXecutables 
                         Copyright (C) 1996 - 2023 
UPX 4.0.2        Markus Oberhumer, Laszlo Molnar & John Reiser 
Jan 30th 2023 
 
Usage: upx [-123456789dlthVL] [-qvfk] [-o file] file.. 
 
Commands: 
 -1     compress faster              -9    compress better 
 -d     decompress                   -l    list compressed file 
 -t     test compressed file         -V    display version number 
 -h     give more help               -L    display software license 
Options: 
 -q     be quiet              ...

Otras técnicas

1. Anti-VM

Una técnica cada vez más utilizada es la detección de máquinas virtuales. Dado que los analistas trabajan con frecuencia sobre máquinas virtuales, los desarrolladores de malwares tratan de identificarlas para detener la ejecución del binario e impedir su análisis mediante herramientas tales como sandboxes. Existen muchísimas maneras de comprobar si un binario se ejecuta sobre una máquina virtual: el malware puede controlar el hardware o los drivers, puede verificar si hay aplicaciones adicionales instaladas para controlar la máquina virtual… Por este motivo, es importante configurar la máquina virtual tal y como se ha descrito en el capítulo Ingeniería inversa.

Además de realizar un control, algunos malwares pueden utilizar bugs a nivel de la herramienta de virtualización. Es el caso de VirtualBox y la vulnerabilidad CVE-2012-3221 descubierta en noviembre de 2011. Se encontró un bug (fallo, error) en esta herramienta de virtualización: en caso de que una máquina virtual ejecutara una interrupción 0x8, la máquina fallaba. Los malwares podían, entonces, hacer fallar fácilmente la máquina que se utilizaba para el análisis agregando el siguiente código:

int crash() { 
 asm ( 
   "int $0x8;" 
   : // output: none 
   : // input: none 
   :"%eax", "%ebx", "%ecx", "%edx"   // clobbered register 
 ); 
 return(0); 

Por ello, es extremadamente importante actualizar las soluciones de virtualización empleadas en el laboratorio de análisis.

Otro método utilizado cada vez con mayor frecuencia consiste en usar WMI (Windows Management Instrumentation) para recuperar la información correspondiente a la máquina que ejecuta el binario y verificar que es una máquina física. WMI es una interfaz presente desde Windows 7, creada para poder interrogar a una máquina acerca de su estado. WMI se utiliza particularmente para supervisar los sistemas. He aquí algunos ejemplos de uso por parte de los malwares:

C:\Windows\System32>wmic /NAMESPACE:\\root\SecurityCenter2 PATH 
AntiVirusProduct 
GET /value | find "displayName" 
displayName=ESET Endpoint Antivirus 5.0 

Mostrar los antivirus instalados:

C:\Windows\System32>wmic /NAMESPACE:\\root\SecurityCenter2 PATH 
AntiVirusProduct GET /value | find "displayName" 
displayName=ESET Endpoint Antivirus 5.0 

Mostrar la memoria instalada en la máquina:

C:\Users\prasc>wmic PATH Win32_ComputerSystem GET 
TotalPhysicalMemory 
TotalPhysicalMemory 
4215230464 

Mostrar el número de núcleos...

Resumen

Los desarrolladores de malwares tienen una gran cantidad de técnicas a su disposición para hacer que el análisis de sus malwares resulte muy complicado. Demuestran una gran imaginación y disponen de un bagaje técnico cada vez mayor. No cabe duda de que en los próximos años se desarrollarán y descubrirán nuevas técnicas.