
BARF : Un framework multiplataforma de código abierto para análisis binario e ingeniería inversa
El análisis de código binario es una actividad crucial en muchas áreas de las ciencias de la computación y disciplinas de ingeniería de software, que abarcan desde la seguridad del software y el análisis de programas hasta la ingeniería inversa. El análisis manual de binarios es una tarea difícil y que consume mucho tiempo, y existen herramientas de software que buscan automatizar o asistir a los analistas humanos. Sin embargo, la mayoría de estas herramientas tienen varias restricciones técnicas y comerciales que limitan el acceso y uso por una gran parte de las comunidades académicas y profesionales. BARF es un framework de análisis binario de código abierto que tiene como objetivo soportar una amplia gama de tareas de análisis de código binario comunes en la disciplina de seguridad informática. Es una plataforma scripteable que soporta la elevación de instrucciones de múltiples arquitecturas, la traducción binaria a una representación intermedia, un framework extensible para plugins de análisis de código y la interoperación con herramientas externas como depuradores, solvers SMT y herramientas de instrumentación. El framework está diseñado principalmente para el análisis asistido por humanos, pero puede ser completamente automatizado.
El proyecto BARF incluye BARF y herramientas y paquetes relacionados. Hasta ahora, el proyecto está compuesto por los siguientes elementos:
Para más información, consulte:
Estado actual:
| Última Versión | v0.6.0 |
|---|---|
| URL | https://github.com/programa-stic/barf-project/releases/tag/v0.6.0 |
| Registro de Cambios | https://github.com/programa-stic/barf-project/blob/v0.6.0/CHANGELOG.md |
Todos los paquetes fueron probados en Ubuntu 16.04 (x86_64).
BARF es un paquete de Python para análisis binario e ingeniería inversa. Puede:
ELF, PE, etc.),Actualmente está en desarrollo.
BARF depende de los siguientes solvers SMT:
El siguiente comando instala BARF en su sistema:
$ sudo python setup.py install
También puede instalarlo localmente:
$ sudo python setup.py install --user
sudo pip install pyasmjitsudo apt-get install graphvizEste es un ejemplo muy simple que muestra cómo abrir un archivo binario e imprimir cada instrucción con su traducción al lenguaje intermedio (REIL).
from barf import BARF
# Open binary file.
barf = BARF("examples/misc/samples/bin/branch4.x86")
# Print assembly instruction.
for addr, asm_instr, reil_instrs in barf.translate():
print("{:#x} {}".format(addr, asm_instr))
# Print REIL translation.
for reil_instr in reil_instrs:
print("\t{}".format(reil_instr))
También podemos recuperar el CFG y guardarlo en un archivo .dot.
# Recover CFG.
cfg = barf.recover_cfg()
# Save CFG to a .dot file.
cfg.save("branch4.x86_cfg")
Podemos verificar restricciones sobre el código usando un solver SMT. Por ejemplo, suponga que tiene el siguiente código:
80483ed: 55 push ebp
80483ee: 89 e5 mov ebp,esp
80483f0: 83 ec 10 sub esp,0x10
80483f3: 8b 45 f8 mov eax,DWORD PTR [ebp-0x8]
80483f6: 8b 55 f4 mov edx,DWORD PTR [ebp-0xc]
80483f9: 01 d0 add eax,edx
80483fb: 83 c0 05 add eax,0x5
80483fe: 89 45 fc mov DWORD PTR [ebp-0x4],eax
8048401: 8b 45 fc mov eax,DWORD PTR [ebp-0x4]
8048404: c9 leave
8048405: c3 ret
Y desea saber qué valores debe asignar a las ubicaciones de memoria ebp-0x4, ebp-0x8 y ebp-0xc para obtener un valor específico en el registro eax después de ejecutar el código.
Primero, agregamos las instrucciones al componente analizador.
from barf import BARF
# Open ELF file
barf = BARF("examples/misc/samples/bin/constraint1.x86")
# Add instructions to analyze.
for addr, asm_instr, reil_instrs in barf.translate(0x80483ed, 0x8048401):
for reil_instr in reil_instrs:
barf.code_analyzer.add_instruction(reil_instr)
Luego, generamos expresiones para cada variable de interés y agregamos las restricciones deseadas sobre ellas.
ebp = barf.code_analyzer.get_register_expr("ebp", mode="post")
# Preconditions: set range for variable a and b
a = barf.code_analyzer.get_memory_expr(ebp-0x8, 4, mode="pre")
b = barf.code_analyzer.get_memory_expr(ebp-0xc, 4, mode="pre")
for constr in [a >= 2, a <= 100, b >= 2, b <= 100]:
barf.code_analyzer.add_constraint(constr)
# Postconditions: set desired value for the result
c = barf.code_analyzer.get_memory_expr(ebp-0x4, 4, mode="post")
for constr in [c >= 26, c <= 28]:
barf.code_analyzer.add_constraint(constr)
Finalmente, verificamos si las restricciones que establecimos pueden ser resueltas.
if barf.code_analyzer.check() == 'sat':
print("[+] Satisfiable! Possible assignments:")
# Get concrete value for expressions
a_val = barf.code_analyzer.get_expr_value(a)
b_val = barf.code_analyzer.get_expr_value(b)
c_val = barf.code_analyzer.get_expr_value(c)
# Print values
print("- a: {0:#010x} ({0})".format(a_val))
print("- b: {0:#010x} ({0})".format(b_val))
print("- c: {0:#010x} ({0})".format(c_val))
assert a_val + b_val + 5 == c_val
else:
print("[-] Unsatisfiable!")
Puede ver estos y más ejemplos en el directorio examples.
El framework se divide en tres componentes principales: core, arch y analysis.
Este componente contiene módulos esenciales: