
BARF : Ein plattformübergreifendes Open-Source-Framework für Binäranalyse und Reverse Engineering
Die Analyse von Binärcode ist eine entscheidende Tätigkeit in vielen Bereichen der Informatik und des Software-Engineerings, die von Softwaresicherheit und Programmanalyse bis hin zu Reverse Engineering reicht. Manuelle Binäranalyse ist eine schwierige und zeitaufwändige Aufgabe, und es gibt Softwaretools, die versuchen, menschliche Analysten zu automatisieren oder zu unterstützen. Die meisten dieser Tools unterliegen jedoch mehreren technischen und kommerziellen Einschränkungen, die den Zugang und die Nutzung durch einen großen Teil der akademischen und praktischen Gemeinschaften einschränken. BARF ist ein Open-Source-Framework für Binäranalyse, das eine breite Palette von Binärcode-Analyseaufgaben unterstützen soll, die in der Disziplin der Informationssicherheit üblich sind. Es ist eine skriptbare Plattform, die das Anheben von Anweisungen aus mehreren Architekturen, die binäre Übersetzung in eine Zwischendarstellung, ein erweiterbares Framework für Code-Analyse-Plugins und die Interoperation mit externen Tools wie Debuggern, SMT-Lösern und Instrumentierungswerkzeugen unterstützt. Das Framework ist in erster Linie für die menschlich unterstützte Analyse konzipiert, kann aber vollständig automatisiert werden.
Das BARF-Projekt umfasst BARF und zugehörige Tools und Pakete. Bisher besteht das Projekt aus den folgenden Elementen:
Für weitere Informationen siehe:
Aktueller Status:
| Neueste Version | v0.6.0 |
|---|---|
| URL | https://github.com/programa-stic/barf-project/releases/tag/v0.6.0 |
| Änderungsprotokoll | https://github.com/programa-stic/barf-project/blob/v0.6.0/CHANGELOG.md |
Alle Pakete wurden auf Ubuntu 16.04 (x86_64) getestet.
BARF ist ein Python-Paket für Binäranalyse und Reverse Engineering. Es kann:
ELF, PE, usw.),Es befindet sich derzeit in der Entwicklung.
BARF hängt von den folgenden SMT-Lösern ab:
Der folgende Befehl installiert BARF auf Ihrem System:
$ sudo python setup.py install
Sie können es auch lokal installieren:
$ sudo python setup.py install --user
sudo pip install pyasmjitsudo apt-get install graphvizDies ist ein sehr einfaches Beispiel, das zeigt, wie man eine Binärdatei öffnet und jede Anweisung mit ihrer Übersetzung in die Zwischensprache (REIL) ausgibt.
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))
Wir können auch den CFG wiederherstellen und in einer .dot-Datei speichern.
# Recover CFG.
cfg = barf.recover_cfg()
# Save CFG to a .dot file.
cfg.save("branch4.x86_cfg")
Wir können Einschränkungen im Code mit einem SMT-Löser überprüfen. Angenommen, Sie haben den folgenden Code:
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
Und Sie möchten wissen, welche Werte Sie den Speicherstellen ebp-0x4, ebp-0x8 und ebp-0xc zuweisen müssen, um nach Ausführung des Codes einen bestimmten Wert im eax-Register zu erhalten.
Zuerst fügen wir die Anweisungen zur Analyzer-Komponente hinzu.
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)
Dann generieren wir Ausdrücke für jede interessierende Variable und fügen die gewünschten Einschränkungen hinzu.
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)
Schließlich prüfen wir, ob die festgelegten Einschränkungen gelöst werden können.
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!")
Weitere Beispiele finden Sie im examples-Verzeichnis.
Das Framework ist in drei Hauptkomponenten unterteilt: core, arch und analysis.
Diese Komponente enthält wesentliche Module: