Forum: Mikrocontroller und Digitale Elektronik Was darf man von Code-Analysern (Disassembler/Decompiler) erwarten?


von Noob (Gast)


Lesenswert?

Ich versuche mich am "Hacken" einer Firmware (ARM Cortex-M3) und habe 
mir IDA (7.0 Free kann kein ARM), radare2/Cutter (komplex, muss erstmal 
richtig konfiguiert werden), Binary Ninja Demo (schon ganz gut), Ghidra 
(naja) mal angesehen.

Es schwankt zwischen "erkennt Funktionen nicht richtig" und 
"[Oberfläche] unbedienbar".

Ich hatte gehofft, man könne den Programm- und Datenfluss (erfordert 
Simulation?) einigermaßen einfach verfolgen um die für einen 
interessanten Stellen zu finden und ggf. zu "hacken".

Mit komplettem Call-Graph und erklärten Instruktionen, sowie eine Kern- 
und Peripherie-Register-Map (gibt es eigentlich standardisierte Daten 
vom Hersteller oder köchelt da jeder seine eigene Suppe für die eigene 
IDE?). Ein Simulator wäre auch nett..

Kurzum: der Einstieg erfordert viel low-level Wissen (Memory Map im 
Kopf, Assembler fließend lesen, ggf. Ergebnis der automatischen Analyse 
prüfen) zu erfordern, die Tools nehmen mehr oder weniger gut einen 
kleinen Teil der Arbeit ab, und die Analyse erfordert sehr, sehr viel 
Handarbeit.

Es ist aber wohl auch ein eher spezielles Beschäftigungsfeld.

Wie sind eure Erfahrungen?

von Stefan F. (Gast)


Lesenswert?

Geht es immer noch darum, diesen Lime Roller zu hacken?

von Georg G. (df2au)


Lesenswert?

Noob schrieb:
> die Analyse erfordert sehr, sehr viel
> Handarbeit.

So ist es. Manchmal erkennt man, welcher Compiler verwendet wurde und 
welche Libs. Das hilft mächtig. Aber ansonsten ist Hirn angesagt (und 
Geduld).

von Böser Onkel (Gast)


Lesenswert?

Mit einem Assembler/Disassembler hackt man nichts, sondern man wandelt
Code nur in eine andere Darstellungsform um, also Binärsprache in
Assenmbersprache. Seit wann sind das denn Code-Analysatoren?

Um einen Algorytmus zu "hacken" wäre ein Debugger das passendere
Werkzeug, denke ich. Die haben aber ihre Grenzen, weil größere
Programme damit praktisch nicht mehr zu handeln wären.
Dafür gibts ausgefeiltere Software die hier erst vor ein paar Wochen
mal erwähnt wurden. Leider habe ich mir da nichts markiert und weiß auch 
nicht nach welchem Begriff ich da suchen müsste.

von Sebastian S. (amateur)


Lesenswert?

Da bleibt immer sehr viel Handarbeit über.

Schaut man sich beliebigen Code "von der Seite" an, so ist oft noch 
nicht mal ersichtlich, ob überhaupt etwas ausführbares vorliegt, oder ob 
es sich um Daten handelt.
Die Daten eines Textstrings oder einer Konstantenliste lassen sich oft 
auch als ausführbarer Code darstellen und umgekehrt. Ob eine (oft 
verwendet) Sprungtabelle vorliegt ist bis zu dem Zeitpunkt unklar, indem 
Du die Registerbelegung kennst.

Ein schöner Gruß an den guten, alten Sisyphos.

von Josef (Gast)


Lesenswert?


von 🍅🍅 🍅. (tomate)


Lesenswert?

So gut, das manche Leute damit schon alte N64 Spiele soweit zerlegt 
haben, damit man sie hinterher wieder binärkompatibel compilieren 
konnte....

von Joachim B. (jar)


Lesenswert?

bei alten 8-bittern war man ja noch mit fast jedem Byte per DU.

Ich habe nach 20 Jahren auch meinen alten PC1500 Code wieder 
disassembliert zu Fuss, mein Vorteil es war MEIN Programm und so 
ungefähr wusste ich noch wie und warum ich das so geschrieben hatte, ich 
wollte den Code relokatibel machen und direkten Zugriff auf den PC hatte 
ich nicht nur indirekt.
Ich habe mich aber auch nie in die vielbenutzten ROM Routinen begeben, 
das wäre dann komplizierter geworden. Ich denke auch manche ROM Routinen 
sind deswegen so unübersichtlich wegen Mehrfachnutzung (durch 
optimnierende Assembler/Compiler)und um Platz zu sparen, da wird mit 
Sicherheit nichts linear gerade runter programmiert sein.

von georg (Gast)


Lesenswert?

Noob schrieb:
> Es ist aber wohl auch ein eher spezielles Beschäftigungsfeld.

Es kommt drauf an, was man erreichen will.

Um die Funktionen einer Steuerung zu erfassen, muss man u.U. garnicht 
disassemblieren oder hacken, da kann man phänomenologisch vorgehen - 
drückt man Button X, bewegt sich die X-Achse usw. Das setzt 
funktionierende Hard- und Software voraus. So entsteht praktisch ein 
Pflichtenheft.

Das identische Programm wieder übersetzen zu können ist auch trivial, 
dafür reichen Define Bytes mit dem ROM-Inhalt. Ist nur ziemlich sinnlos.

Programmideen zu klauen ist für jemanden, der die Qualifikation zur 
Code-Analyse hat, auch uninteressant, da schreibt man den nötigen Code 
schneller selber.

Sinnvoll ist es nur, einen Sourcecode zu erzeugen und zu verstehen, um 
das vorliegende Programm an entscheidenden Stellen ändern und neu 
übersetzen zu können, das ist die Königsdisziplin. Leider setzt das viel 
Erfahrung voraus und artet trotzdem in harte Arbeit aus.

Georg

von Programmierer (Gast)


Lesenswert?

Sebastian S. schrieb:
> Schaut man sich beliebigen Code "von der Seite" an, so ist oft noch
> nicht mal ersichtlich, ob überhaupt etwas ausführbares vorliegt

Also bei ARM sieht man das ziemlich schnell. Wenn man irgendwelche Daten 
disassembliert, stellt man schnell fest dass das ziemlicher Blödsinn 
ist, z.B. wenn da 10x hintereinander die gleiche Instruktion steht. 
Vielleicht ist es ja sogar typisch RISC, dass man öfters bestimmte 
Muster hat, die man schnell erkennt. Der Klassiker sind ja 
Funktions-Anfang und -Ende.
Bei ARM A32 Code sieht man eine Menge "E" in der hexadezimalen 
Darstellung - der Condition Code "Always".

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Wie schon öfter erwähnt, muss man sowieso noch einen Plan des 
Portmappings erstellen - am besten ausgedruckt mit den Alternate 
Functions des MC, um den es geht.
Das hat mir hier sehr gut geholfen, obwohl es nie in meiner Absicht lag, 
die Firmware zu disassemblieren, sondern neue Firmware für die 
vorhandene Hardware zu entwickeln. Auf dem Ausdruck kann man dann die 
Funktionen abhaken, die schon erkannt sind und sich dann gezielt um die 
noch fehlenden kümmern. - bis alle 176 Pins zugeordnet sind...
Zusätzlich braucht man natürlich die Datenblätter etwaiger 
Peripheriechips.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Ich denke mal, es ist einfacher, mit einem LA an den IO-Pins 
mitzusniffen, was der MC macht und es dann neu zu programmieren.

von S. R. (svenska)


Lesenswert?

Rote T. schrieb:
> So gut, das manche Leute damit schon alte N64 Spiele soweit
> zerlegt haben, damit man sie hinterher wieder binärkompatibel
> compilieren konnte....

Da wusste man aber auch, welcher Compiler benutzt wurde, welche 
Bibliotheken verwendet wurden und was für Code da hinten rausgefallen 
ist.

Für eine unbekannte Cortex M3-Firmware gilt das nicht.

Noob schrieb:
> Ich hatte gehofft, man könne den Programm- und Datenfluss
> (erfordert Simulation?) einigermaßen einfach verfolgen um
> die für einen interessanten Stellen zu finden und ggf. zu "hacken".

Das geht einigermaßen gut, je nachdem, was den Code ursprünglich erzeugt 
hat (Compiler oder handgeklöppeltes Assembler), wie der Decompiler das 
versucht zu verarbeiten (welche Plugins für welche 
Compiler-Entry/Exit-Sequenzen er kennt), und welche Register bekannt 
sind.

Der Cortex M3-Kern ist gut standardisiert, daher kennst du den 
Einstiegspunkt und kannst du dich vom Reset_Handler aus durch den Code 
hangeln. Der Anfang ist normalerweise auch handgeschriebener 
Assemblercode, d.h. der ist auch im Disassembler recht einfach lesbar.

Was danach kommt, hängt vom Inhalt ab.

von Noob (Gast)


Lesenswert?

Danke für's Feedback, da lag ich ja nicht so falsch mit meiner 
Einschätzung.

Zum Resethandler bin ich schon gekommen, da wird der SP explizit nochmal 
per Software gesetzt (=schlechter Compiler bzw. Startup Code?), 
ansonsten geht es dann los mit der fehlerhaften disassembly und Analyse 
- und vielen undurchschaubaren Verzweigungen.
Mein erstes Ziel wäre, zumindest die Zugriffe auf Peripherieregister zu 
finden und Schleifen aufzuspüren.

Den Befehlssatz werde ich mir also mal durchlesen müssen...

Tipp: Cutter kann offenbar nur lokale Funktionen graphisch darstellen, 
für die Funktionszusammenhänge muss es dann radare2 sein (Download für 
Windows von appveyor, die offiziellen Downloads sind veraltet). Ebenso 
sollte man Cutter gleich in der Kommandozeile starten, sonst ist die 
Konsole nicht wirklich nutzbar.

Und zum Vergleich lässt sich Binary Ninja immer mal wieder für 15 
Minuten oder so nutzen (zeitbeschränkt).

georg schrieb:
> Sinnvoll ist es nur, einen Sourcecode zu erzeugen und zu verstehen, um
> das vorliegende Programm an entscheidenden Stellen ändern und neu
> übersetzen zu können, das ist die Königsdisziplin. Leider setzt das viel
> Erfahrung voraus und artet trotzdem in harte Arbeit aus.

Genau, "ein bisschen anpassen" wäre schön.

von S. R. (svenska)


Angehängte Dateien:

Lesenswert?

Noob schrieb:
> Zum Resethandler bin ich schon gekommen, da wird der SP explizit
> nochmal per Software gesetzt (=schlechter Compiler bzw. Startup Code?),

Das machen einige Startup-Codes so, weil man dort mit #ifdef arbeiten 
und so ein gemeinsames Linkerscript für mehrere Chips nutzen kann.

> ansonsten geht es dann los mit der fehlerhaften disassembly
> und Analyse - und vielen undurchschaubaren Verzweigungen.

Um was für einen Chip geht es denn? Wenn es was halbwegs bekanntes ist, 
dann schau dir einfach mal den Startup-Code vom Hersteller als Vergleich 
an.

Bist du dir sicher, dass dein Decompiler die korrekte Architektur 
decompiliert? Weil "Cortex-M3" ist nicht dasselbe wie "ARM", und wenn da 
eine unbekannte Instruktion steht, dann fliegt der Decompiler aus der 
Bahn.

Bedenke, dass der Startup-Code in aller Regel handgeklöppelter 
Assemblercode ist. Da kann man wunderschöne Tricks benutzen, wie z.B. 
mehrere sich überlappende Schleifen und sowas. Ein linearer Decompiler 
kommt mit sowas absolut nicht klar. ;-)

Achso, viele Sprünge sind relativ, auch zu PC oder SP. Wenn du die 
Basisadresse der Firmware nicht korrekt angegeben hast, dann kann der 
Disassembler die Zieladressen nicht korrekt berechnen und du bekommst 
Müll. Üblicherweise kannst du dem Disassembler bestimmte Registerwerte 
zu bestimmten Zeiten vorgeben, damit das funktioniert.

Auf einem Cortex-M3 gilt allgemein: Flash@0x08000000, SRAM@0x20000000 
und oft irgendein Alias oder Boot-ROM oder sowas bei 0x00000000.

> Mein erstes Ziel wäre, zumindest die Zugriffe auf
> Peripherieregister zu finden und Schleifen aufzuspüren.

Ich würde an deiner Stelle erstmal den Befehlsverlauf vom Startup-Code 
verfolgen. Der muss logisch aufgebaut sein. Ich hänge mal einen von mir 
(in C für LM3S811 im Qemu) geklöppelten Startup-Code an. Mindestens 
diese Funktionalität solltest du finden, wenn die Firmware in C oder C++ 
geschrieben wurde.

Noob schrieb:
> Den Befehlssatz werde ich mir also mal durchlesen müssen...

Das sowieso. Du musst den Assemblercode schon einigermaßen lesen können, 
sonst wird das nix. Datenblatt vom Controller ist immer gut bei der Hand 
zu haben, und wenn du das nicht hast, zumindest das Datenblatt vom 
Cortex-M3.

Nachtrag: Praktische Erfahrung hab ich maximal mit IDA Free, da hab ich 
mal angefangen, ein 80186-BIOS zu zerlegen. Also nicht unbedingt ARM 
Cortex-M3, wobei ich da auch öfter mit objdump mal Hex-Dateien zerlegt 
habe.

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.