Post on 14-Oct-2018
Ingeniería Inversa Práctica BásicaJoxean Koret
Introducción
¿Qué es la automatización? Extraído de Wikipedia: ”La automatización es la utilización de sistemas de
control y tecnologías de la información para reducir la necesidad de trabajos humanos [manuales] para la realización de una tarea”
Si bien todos los trabajos se podrían realizar manualmente, esto puede resultar muy tedioso o, en la práctica, imposible.
La automatización es fundamental en el análisis de software.
¿Qué vamos a ver?
Introducción a IDA Python (muy rápida) Introducción a la ingeniería inversa de
firmwares (dispositivos empotrados) Descubrimiento del formato, extracción de la
imagen, etc... Descubrimiento del procesador, funciones,
nombres, etc...
Análisis de malware Automatización del análisis de malware
(desempaquetado, comportamiento, etc...)
Introducción a IDAPython
IDA Python
IDA Python es un plugin para IDA Pro que permite la utilización de Python para interactuar con dicha herramienta.
Creado por Gergely Erdelyi. Nos da toda la potencia de un lenguaje de
prototipado rápido (Python) para poder realizar las tareas de automatización que deseemos de un modo fácil y rápido.
”Hola mundo” en IDA Python
Hagamos el primer script básico en IDA Python Creamos un fichero con extensión *.py. Escribimos el siguiente texto:
Warning(”Hello world!”) Guardamos y vamos al menú (en IDA) File->Python
File. Seleccionamos nuestro archivo .py. Se mostrará un cuadro de diálogo con el texto
”Hello world”.
IDA Python: Funciones
Otro sencillo ejemplo: Abrimos notepad.exe en IDA. Vamos al menú File->Python command. Escribimos el siguiente texto:
for f in Functions():
print hex(f), GetFunctionName(f)
Este script nos imprimirá la dirección y nombre de todas las funciones en el binario actual.
IDA Python: Segmentos
Seguimos con notepad.exe Vamos a File->Python comand y escribimos el
siguiente texto:
for s in Segments():
print hex(SegStart(s)), \
hex(SegEnd(s)), \
SegName(s)
IDA Python: Instrucciones Seguimos con notepad.exe.
Esta vez, creamos un script y escribimos el siguiente texto:
IDA Python: Instrucciones
En este script hemos visto algunas funciones nuevas: get_func: Obtiene un objeto con los datos de una
función dada una dirección de dicha función. Heads: Devuelve una lista de instrucciones entre 2
direcciones (startEA y endEA). GetDisasm: Obtiene el desensamblado de una
instrucción dada su dirección.
IDA Python: XRefs
¿Cómo sacamos las referencias de código a todas las funciones de un binario? Escribimos el siguiente texto:
IDA Python: XRefs
En este script hemos visto una función nueva: CodeRefsTo: Devuelve un generador (lista) con
todas las direcciones desde las que se llama a esta función.
Al igual que CodeRefsTo tenemos CodeRefsFrom, que devuelve la lista de direcciones llamadas desde una dirección dada.
Una misma dirección puede tener referencias de código a varias direcciones a la vez.
Ejercicio 01
Escribir un script IDA Python que muestre todas las funciones llamadas en la función actual.
Sabemos como sacar la dirección actual (here), como iterar las instrucciones de una función y como sacar las funciones llamadas desde una dirección así que tenemos todo lo que necesitamos.
Solución
Ejercicio 02
Histograma de mnemónicos. Sacar los 10 mnemónicos más utilizados y los 10
menos utilizados en un programa para todas sus funciones.
Para sacar el mnemónico de una instrucción utilizaremos la función GetMnem.
Ejemplo: print GetMnem(here()) Podemos, por ejemplo, guardar la lista de
mnemónicos en un diccionario Python: my_dict = {} my_dict[”mov”] = 3
Solución
Tenéis la solución a este ejercicio en c:\curso\mnems.py.
¿Para qué nos podría valer sacar el histograma de mnemónicos de un ejecutable? Para determinar si está empaquetado y/o ofuscado,
por ejemplo. Análisis de malware.
IDAPython: Bloques Básicos
Ejemplo para iterar bloques básicos:
No funciona en vuestra versión (5.5) :(
IDAPython: Bloques básicos
Este script imprime la dirección de inicio y final de cada bloque básico.
Además, imprime también con que bloques básicos se relaciona: Qué bloques básicos conectan con el bloque
básico actual. Qué bloques básicos conectan desde el bloque
actual.
IDAPython: Bloques Básicos
Como ya he dicho, en vuestra versión de IDA no funciona el script :( Se necesita justo la siguiente versión de IDAPython
Sin embargo, tenéis un script llamado bblocks.py en el directorio c:\curso.
Este script nos permite sacar los bloques básicos de una función.
Cuando comencemos con análisis de malware lo utilizaremos. Para hacer un unpacker sencillito.
Bloques Básicos: Explicación
El bloque básico 1 comunica con los bloques básicos 2 y 3.
El bloque básico 3, es referenciado por 2 y 1.
A su vez, el bloque básico 3 comunica con el 4 y el 5.
1
2
3
4
5
IDAPython
Hemos llegado al final de la introducción a IDAPython: Preguntas?
Ingeniería Inversa de firmwares(dispositivos empotrados)
Firmware
¿Qué es un firmware? Extraído de Wikipedia: ”firmware is a term often used to denote the fixed,
usually rather small, programs and/or data structures that internally control various electronic devices. Typical examples of devices containing firmware range from end-user products such as remote controls or calculators, through computer parts and devices like hard disks, keyboards, TFT screens or memory cards, all the way to scientific instrumentation and industrial robotics.”
Un ejemplo: el software de un router, de un móvil, de un lector de libros, etc...
Fase 0: Obtener el firmware
En este curso no entraremos en ese tema. Solo ese ”simple” tema podría ser todo un curso
completo. Hay muchos modos diferentes: Firmware updates,
puerto de serie, JTAG, Flash chip dumping, bytes del firmware envíados como pulsos de luz, … y un muy largo etc.
Recomendado: ”Intro to Embedded Reverse Engineering for PC reversers” - Igor Skochinsky
Nosotros supondremos que ya tenemos acceso al firmware.
Fase 1: Formato del firmware
En esta fase todo son dudas y más dudas: ¿En qué formato está el firmware (sea como sea
que lo hayamos obtenido)? ¿Es una imagen en crudo, volcado de memoria,
etc...? ¿Está comprimido?
¿Con qué compresor? ¿Está cifrado?
¿Con qué algoritmo? ¿Se puede sacar la clave?
Fase 2: Formato del firmware
En nuestro caso vamos a ver un firmware bastante sencillo.
Pasos a seguir: Ver el formato de la imagen. Ver el formato de los archivos, si los hubiera. Ver si están comprimidos y/o cifrados los mismos. Extraerlos. Analizarlos.
Fase 2: Formato del firmware
Herramientas básicas: file: Intentar sacar el formato del binario leyendo la
cabecera. strings: Intentar dilucidar ”algo” leyendo las
cadenas (si las hay). objdump: Intentar desensamblar en crudo el fichero
con las arquitecturas que se nos ocurran (o todas). binwalk: Utilizar una herramienta que busca
archivos dentro de archivos. Esta herramienta es casi específica para firmwares.
Generalmente, los 3 primeros comandos, no sirven de gran ayuda.
Strings
Strings
¿Qué sacamos en claro -como mínimo- con lo salida del comando strings? Tic-tac, tic-tac, tic-tac...
Strings
El hardware en el que se ejecuta es de 32 bits: Bueno, ”eso parece”:
%d Time:%8lx INT%d %8lx → 8 bytes
El procesador parece ser ARM: Registros: r0, r1, r2, (…), sp, lr, pc Una rápida búsqueda en Google de los registros es
más que suficiente.
Probemos a abrir el archivo en IDA con procesador ARM.
Strings No parece ARM :(
Fase 1: Procesador del firmware
No se puede confiar a ciegas en lo que os encontréis con un strings/file/etc... Cadenas que se utilizan para varias plataformas y
que no están IFDEF-ed en el código. Cadenas para liar. Nombres de dispositivos que quieren soportar y no
se soportan actualmente. Porciones de código copiadas y pegadas de
terceros sitios. ...
Fase 1: Formato del firmware
En este caso, este firmware, es MIPS. El modo de averiguarlo:
Intentar desensamblar con los procesadores más habituales hasta que con uno el código desensamblado por IDA tenga sentido.
Los más habituales son x86, ARM, MIPS y PPC. Abrir el archivo, elegir procesador, pulsar ”C” en los
primeros bytes del archivo y... esperar.
Lo dicho: no podemos fiarnos a ciegas de aquello que el comando ”strings” nos muestre...
Fase 1: Formato del firmware
Ahora que ya sabemos, como sea que lo hayamos averiguado, el procesador de la imagen: Cargamos en IDA el binario eligiendo dicho
procesador. Intentamos desensamblar porciones de código en
los primeros bytes.
Veamos que es lo que nos encontramos...
Carga del binario en IDA
Fase 2: Carga del binario
Inicialmente, IDA no encuentra nada. Tendremos que buscar zona que parezcan código
y crear funciones para que IDA empiece a hacer su trabajo.
Se puede ir pulsando ”C” en los primeros bytes del binario para probar suerte.
Ver si el código tiene sentido. Si IDA encuentra funciones. Etc...
Carga del binario en IDA
Carga del binario en IDA
¿Qué hemos encontrado? Un DWORD en los primeros 4 bytes. No sabemos
su uso. Una cadena ”SIG”. Tampoco sabemos su uso. Algunas instrucciones que ”parecen” válidas.
¿Qué tenemos que encontrar? La dirección base de la imagen. Los segmentos. Las funciones. En definitiva, aún tenemos que encontrar todo...
Imagen base
Para encontrar la dirección base de la imagen se pueden utilizar múltiples trucos: En este firmware, el primer DWORD indica la
imagen base. Muy fácil. Sin embargo, rara vez la vamos a encontrar así. ¿Cómo encontrarla?
Direccionamientos. Segmento BSS. …
Intentemos encontrarla de otros modos...
Carga del binario en IDA
Carga del binario en IDA
Desde el offset 0x80 encontramos instrucciones interesantes: Carga en $gp el valor 0x80E23870. Carga en $sp el valor 0x80FFFEFC. Carga en otros registros valores con una dirección
similar: 0x80E?????
El redondeo a 0 de las direcciones más bajas suele ser un modo de encontrar la dirección base.
Direcciones 0x80E23870, 0x80FFFEFC, 0x80E1F8F8...
¿Podría ser 0x80E00000 la dirección base? Probemos...
Carga del binario en IDA
Vamos al menú Edit->Segments->Rebase Program.
Introducimos el valor 0x80E00000 y pulsamos OK.
IDA cambiará la dirección base de la imagen en todo el fichero cargado.
Y, además, encontrará un par de funciones... La dirección base parece correcta!
Carga del binario en IDA
Carga del binario en IDA
El hecho de que IDA encuentre más funciones tras rebasear la imagen es indicador de que la dirección base parece correcta. Pero puede no serlo.
Se puede verificar mirando que las referencias a cadenas (data xrefs) sean correctas.
Sin embargo, aún no tenemos nada más que unas cuantas instrucciones desensambladas al inicio y un par de funciones.
Hay que buscar más código y más funciones.
Carga del binario en IDA
Un truco no muy ”elegante”: Seleccionamos en IDA desde el primer byte hasta
el último byte: Vamos al inicio (pulsad INICIO varias veces), y
después pulsamos 3 veces SHIFT+FIN. Pulsamos la tecla ”C” para crear código. IDA nos preguntará si queremos analizar la parte
seleccionada, forzar la creación de código o cancelar la operación.
Responderemos ”analizar”. IDA encontrará mucho código y muchas funciones.
Carga del binario en IDA
Código Datos
Funciones
Código
Carga del binario en IDA
De este modo, tan poco elegante pero funcional, hemos encontrado 2 partes importantes: Una zona de código (color granate). Una zona de datos (la parte grande en gris).
Analicemos que hay justo donde comienza la sección de datos identificada por IDA.
Carga del binario en IDA
Carga del binario en IDA
Las cadenas que aparecen nos resultan familiares ¿Verdad?
Las referencias a datos (a cadenas) parece que son correctas: No lo son del todo, pero luego comento porque.
Sin embargo, tenemos aún varios problemas: Los datos en rojo son código no asociado a
funciones. Aún no tenemos segmentos creados.
Carga del binario en IDA
Así pues, tenemos que hacer las siguientes tareas: Encontrar los segmentos del binario que hemos
cargado. Encontrar las funciones.
Segmentos: Al menos 2 segmentos son claros ¿No es así?
El de código y el de datos. Creémoslos.
Carga del binario en IDA
Edit->Segments->Create Segment:
Carga del binario en IDA
¿Cómo podemos encontrar más segmentos?
Carga del binario en IDA
¿Cómo podemos encontrar más segmentos?
Segmento
Carga del binario en IDA
El segmento más simple de encontrar: .bss. ¿Véis el código donde ejecuta la siguiente instrucción?
sw $0, 0($t7);
Está inicializando a ”0” una zona de memoria. Esta zona es el segmento .bss. Sus límites los encontramos en las instrucciones
anteriores: Inicio: 0x80e23868 Final: 0x80e25470
Creemos este segmento.
Carga del binario en IDA
Ya tenemos al menos 3 segmentos. Ahora nos resta, de momento, encontrar
funciones. ¿Cómo podemos hacerlo? Buscando prólogos a función, por ejemplo. Ejemplo de prólogo de función típico:
Ejercicio: Búsqueda de funciones
Este curso es de automatización, ¿No? Hagamos un script que busque en el seg ROM:
Instrucciones en ensamblador similares a: addiu $sp, -???
O bien, su opcode: 27 BD FF ??
Podemos utilizar una de estas 2 funciones: GetDisasm FindBinary
NOTA: En MIPS 32 una dirección válida tiene que estar alineada a 4.
Solución 1
Solución 2
Carga del binario en IDA
Aún no está muy bien, ¿Verdad?
Las zonas en rojo son código no asociado a funciones.
¿Cómo podemos encontrar más funciones? Creando funciones al final de funciones existentes.
Ejercicio
Creemos un script que cree funciones al final de funciones existentes, ya encontradas.
Podemos utilizar la función get_func Para obtener un objecto func_t, donde tenemos el
inicio y el final de la función. Con func_obj.endEA tenemos el final de dicha
función, solo hay que crear una función en ese punto.
Tras encontrar nuevas funciones, es interesante volver a relanzarlo desde el inicio.
Hasta que no encontremos nuevas funciones.
Solución
Carga del binario en IDA
Ahora está mucho mejor, ¿No es así?
Queda alguna zona que no ha sido asociada a función, pero es tan poco que se puede hacer manualmente.
Solo nos queda hacer una cosa: Un script que haga todo lo que hemos hecho nosotros.
Ejercicio
Hagamos un loader para este firmware que: Rebasee la imagen al primer dword del fichero. Cree código desde el offset 0x30. Cree los 2 segmentos que conocemos (sabemos
sus offsets). Función SegCreate.
Busque funciones: Por prólogo y tras el final de cada función
encontrada. Después, reanalice toda la imagen.
No es un loader exactamente, pero bueno...
Notas
¿Os acordáis de las primeras instrucciones en ensamblador que nos dieron una idea de la imagen base? la $gp, 0x80E23870
El valor 0x80E23870 se carga en $gp. Este registro, $gp, se utiliza para
direccionamiento: Por ejemplo: $gp+0x100
Digámosle a IDA cuál es el valor de $gp: Option->General->Analysis->Specific processor...
Valor de $gp
Solución
Tenéis la solución en el archivo siguiente: C:\curso\ldr360.py
Ejercicio
Tenéis un archivo llamado ”boot”. Encontrad la dirección base, sus segmentos, sus
funciones y hacer un script de carga. Ya habéis hecho uno antes, no será muy difícil ;)
Es solo adaptarlo. Después, continuaremos con los siguientes pasos:
Búsqueda de símbolos.
Tablas de símbolos
Tenemos el código de nuestro boot loader. Pero no tenemos símbolos:
Solo tenemos funciones tipo sub_XXXXXX.
Necesitamos encontrar nombres de funciones ¿Cómo? Tablas de símbolos. Cadenas.
Empecemos por el mejor modo. Desgraciadamente, no siempre disponibe.
Firmware boot
En el firmware que estamos analizando ahora mismo (el boot loader) tenemos ”algo”, que IDA no ha analizado correctamente. Mirad en el offset 0x80008738
Tabla de símbolos
Tenemos una XREF a ese offset, pero no parece que sea a una cadena como IDA cree. Marcamos la zona como ”unknown”:
Seleccionamos y presionamos ”u”. Y pulsamos la tecla ”d” 3 veces: sorpresa!
Aparece una cadena (el comando ”AT”). Si hacemos lo mismo con las siguientes
direcciones: Aparecen funciones y más cadenas.
Tabla de símbolos
Tabla de símbolos
En nuestro caso, hemos tenido mucha suerte y hemos encontrado una tabla de símbolos: Tenemos un nombre de función (por ej, ”AT”). Tenemos la función que se llamará (0x800024FC) Un valor que desconocemos (el ”0”). La ayuda de la función.
¿Qué nos queda por hacer? Un script que nos cree la tabla de símbolos en
IDA :)
Ejercicio
Hacer un script que: Renombre las funciones a su correspondiente
nombre interno. Agregue un comentario a cada una de ellas con su
respectiva ayuda. SetFunctionCmt(addr, text, repeat)
Podéis utilizar SelStart y SelEnd para hacerlo sobre una selección en IDA. Es el modo más fácil.
Solución
Más firmwares
Abrir el firmware llamado ”image”. Es muy similar al anterior (boot), verdad?
Lancemos nuestro script anterior. ¿Ha funcionado? Debiera, si no, algo hemos hecho mal.
Una vez corregidos los errores... ¿Cómo sacamos en esta imagen los nombres de
función? En este caso no tenemos tabla de símbolos :(
O yo no la he encontrado...
Símbolos
¿Otro medio? A partir de las cadenas: Veamos algunas cadenas interesantes...
Parece que algunos nombres podremos sacar, verdad? Solo hay que buscar desde donde se referencia
dicha cadena.
Ejercicio
Buscar cadenas del estilo ”nombre(): algo”. Extraer el ”nombre” y cambiar el nombre a la
función que referencie dicha cadena. Os daré un pequeño código para sacar solo las
cadenas referenciadas. En nuevas versiones de IDA, ya viene por defecto.
Solución
Tenéis el script completo en la carpeta c:\curso. Esto está mucho mejor así, ¿Verdad? :)
Firmwares
Hemos acabado con el análisis de firmwares. Preguntas?
Análisis de malware automatizado
Automatización del análisis
¿Porqué automatizar el análisis de malware? Porque el volumen de malware que se genera
diariamente es humanamente imposible de analizar manualmente.
Varios cientos de miles de archivos diarios...
¿Qué tareas podemos automatizar? Desempaquetado/descifrado. Análisis de comportamiento. Análisis de baterías.
Empecemos...
Desempaquetado y descifrado
La práctica totalidad del malware que se encuentra hoy en día está empaquetado y/o cifrado: UPX, ASPack, Themida, etc...
Podemos hacer unpackers para cada packer existente... Lo cuál es horrible (aunque necesario a veces).
O escribir un unpacker genérico. Posiblemente, basándonos en alguno ya existente.
Universal Unpacker
IDA trae por defecto un sencillo plugin para desempaquetado: Universal PE Unpacker.
Este plugin nos permite desempaquetar algunos packers sencillos (si bien, muy utilizados): UPX o ASPack, por ejemplo.
Veamos como funciona: Abrid en IDA c:\curso\03\notepad_upx.exe
Packer UPX
Se ve claramente que está empaquetado, ¿No es así?
Packer UPX
Veamos como desempaquetarlo con el Universal PE Unpacker... Seleccionamos el debugger:
Local Win32 Debugger o Bochs Debugger Para malware, luego, utilizad Bochs.
Y vamos a Edit → Plugins → Universal PE Unpacker.
El resto es poco más que ”seguir el asistente”.
Universal PE Unpacker
Cuando acaba, IDA está tal que así:
Universal PE Unpacker
Vemos una referencia de código, pero no hay código.
Pulsamos ”p”. IDA ha encontrado de este modo un montón de
funciones nuevas. Analicemos el binario al completo para ver si
encuentra más: AnalyzeArea(MinEA(), MaxEA())
Veremos que IDA encuentra muchas funciones más.
¿Cómo funciona?
Este plugin de IDA funciona de este modo: Se pone a tracear el código hasta que encuentra
una llamada a GetProcAddress. Utilizada para resolver funciones de librería.
Entonces, sabe que se está reconstruyendo la Import Address Table.
Después, cuando encuentra un salto a una zona de datos, sabe que ese es el Entry Point.
Este funcionamiento tiene muchos problemas. Hagamos nosotros otro unpacker.
Unpacker sencillo Hagamos un unpacker basado en el grafo de función:
1.Poner un breakpoint en cada exit point del punto de entrada.
2.Cuando se llega al breapoint, avanzamos una instrucción.
3.Si la instrucción es perteneciente a la función en la que estábamos (donde se ha ejecutado el bpt) continuamos la ejecución.
4.De lo contrario, creamos una función en ese punto, y volvemos al punto 1.
5.Si el número de instrucciones FF 15 es 'grande', damos por desempaquetado el software (FF 15 → API Calls).
6.Creamos el entry point en esa última función.
Unpacker sencillo
Es más fácil de lo que parece ;) Pero aún necesitamos saber una cosa
importante: ¿Cómo funciona la API de debug de IDA? Hagamos un script que ejecute unas cuantas
instrucciones y pare para aprender.
Script de debug basico
Iniciamos el debugger
Esperamosel evento
Avanzamos una instrucción
Ponemos un breakpointal inicio
API de debug
La mayoría de llamadas a la API de debug requieren que se llame a GetDebuggerEvent. Para que IDA procese el evento.
El evento devuelto debe ser verificado. Posibles eventos:
EXCEPTION STEP BREAKPOINT etc...
Unpacker Ahora ya sabemos lo básico como para empezar.
Comencemos, entre todos, el unpacker:
1.Sacamos los bloques básicos de la función de inicio y ponemos un breakpoint en cada punto de salida.
2.Ejecutamos hasta que se llegue a un breakpoint.
Unpacker Creamos un script que se llame unpacker.py.
Importamos el script externo que vamos a necesitar:
from bblocks import CFuncBlocks
Declaramos una clase, CGenericUnpacker:
class CGenericUnpacker:
def __init__(self):
pass
Y agregamos el código típico:
def main():
pass
if __name__ == ”__main__”:
main()
Unpacker
Comencemos sacando los puntos de salida:
Si la instrucción final no tiene referencias de código, es un punto de salida.
Unpacker
En cada uno de los puntos de salida, ponemos un breakpoint:
Agregamos el código para seleccionar y ejecutar el debugger (Bochs):
Unpacker
Vayamos juntando las piezas. Creemos un método ”unpack”:
Después de ejecutar el debugger, nos queda gestionar los eventos de depuración. La gestión de los breakpoints que hemos puesto.
Unpacker
Agreguemos un método handle_events y una llamada a dicho método después de ejecutar el debugger:
Unpacker
Tenemos el código inicial para ejecutar hasta un breakpoint.
Agregamos el siguiente código a main y ejecutamos el script por 1ª vez:
Si todo ha ido bien, el debugger se parará en algún breakpoint.
¿Hasta ahora todo bien?
Unpacker sencillo Pues ahora os toca a vosotr@s ;) Recordamos como:
1.Poner un breakpoint en cada exit point del punto de entrada (o función actual).
2.Cuando se llega al breapoint, avanzamos una instrucción.
3.Si la instrucción es perteneciente a la función en la que estábamos (donde se ha ejecutado el bpt) continuamos la ejecución.
4.De lo contrario, creamos una función en ese punto, y volvemos al punto 1.
5.Si el número de instrucciones FF 15 es 'grande', damos por desempaquetado el software.
6.Creamos el entry point en esa última función.
Unpacker sencillo
Tenéis el script al completo en la carpeta c:\curso. Pero no hagáis trampa ;) Intentadlo antes.
Sandbox
Desde IDA 5.5 se soporta la comunicación con el emulador de x86 y x86_64 Bochs. Ya lo hemos utilizado anteriormente :)
Este emulador se puede utilizar para crear una sandbox sencilla.
El plugin para Bochs de IDA intenta emular un sistema windows 'real'.
Veamos como funciona.
Plugin Bochs
En el directorio $IDA/plugins/bochs está el código de emulación de DLLs:
Emulación DLL
Se puede emular una DLL via IDC o via IDAPython. IDC: Es un lenguaje de scripting similar a C específico
de IDA. Nosotros escribiremos nuestro código en IDAPython.
Debemos agregar la siguiente línea al final del archivo $IDA_DIR/python/init.py: idaapi.enable_extlang_python(True)
Ahora ya podemos escribir código para emulación de DLLs en Python.
Por defecto, se escribe el código en IDC. Se tiene que definir un stub para dicha DLL a emular.
Bochs Plugin
Abrimos el archivo siguiente: $IDA_DIR/plugins/bochs/startup.py
Bochs Plugin
Indicamos a IDA que queremos emular una librería poniendo un comentario al estilo de: #/// stub libreria.dll
Después, necesitaremos crear un archivo llamado: api_libreria.py
Abramos un archivo para ver como funciona: $IDA_DIR/plugins/bochs/api_user32.dll
Emulacion Librerias
Ejemplo de emulación de MessageBoxA:
Indicamos la función, nombre local y tamaño de pila a restaurar:
///func=MessageBoxA entry=messagebox purge=0x10 Declaramos la función local y hacemos lo que
querramos.
Primer Paso
Hagamos un sencillo script que nos saque: Las funciones de librería que se resuelven
dinámicamente: GetProcAddress
Primero, abrimos kernel32.dll en IDA y buscamos la función GetProcAddress. Salvo que sepáis de memoria cuanto espacio
restaura de pila...
Funciones kerne32.dll
Para GetProcAddress, restauramos 8 bytes:
Agreguemos el prototipo de función ahora que ya sabemos lo que necesitamos...
Prototipo de función
El prototipo: ///func=GetProcAddress entry=k32_getprocaddress
purge=0x8
Pero... hay un problema: Esta función ya está siendo usada:
Funcionamiento de IDA Bochs
Necesitamos borrar (*comentar*) la definición de esa función.
En nuestro código, haremos lo que deseemos y después llamaremos a la función real BochsGetProcAddress
Ejercicio Sandbox
Hagamos una Sandbox que consiga, al menos, emular las siguientes funciones: CreateFileA DeleteFileA WinExec
De este modo sabremos que archivos crea, borra y qué ejecuta.
Podéis probar con el archivo siguiente: c:\curso\nomalware.exe
Espero que os haya gustado el curso!
E-Mail: admin@joxeankoret.com