Finde den Code zum Kompilat

OP #8014833
Lesenswert?

Ich habe hier den Inhalt des Flahsspeichers aus einen STM32 und ein Git-Repository mit mehreren Versionsständen des Codes. Ich soll nun herausfinden, welcher Versionsstand genau den vorhandenen Flashinhalt ergeben hat. Beim Kompilieren erhalte ich eine Datei.elf, das Speicherabbild trägt die Erweiterung.bin. Es ist exakt zwei Megabyte groß, genau so groß wie der Flash des STM32. Ein direkter Vergleich mit der Datei.elf ist gar nicht nötig, da sie nur wenige Kilobyte groß und damit sicher verschieden ist.

Ich habe mit dem objcopy.exe aus einem Unterverzeichnis des STM32CubeIDE aus der Datei.elf eine Datei.bin gemacht um sie mit dem Flashinhalt vergleichen zu können, sie ist aber nicht zwei Megabyte groß.

Gibt es eine Möglichkeit, die kompilierte .elf so mit dem .bin zu vergleichen, dass Equivalenz festgestellt werden kann (oder .hex oder wasauchimmer mit den beiden vorhandenen Dateien möglich ist)?

#8014908
Lesenswert?

Du brauchst die toolchain-Version, die für die Erzeugung des Flashinhalts benutzt wurde, dazu die verwendeten Optionen. Das kann kompliziert werden.

Wie schon gesagt wurde, wenns da irgendwelche Strings gibt, die die Version identifizieren, kanst du mit einem hex-Editor danach suchen.

Oliver

#8014930
Lesenswert?

Rüdiger B. schrieb:

Im bin sollte doch eine Versionsnummer zu finden sein

Das setzt voraus, daß derjenige, der die Compilate erzeugte, über soviel Selbstdisziplin verfügte, diese für jeden Durchlauf hochzusetzen.

Ich habe mir angewöhnt, im lokalen Git auch die erzeugen Binaries als Assets zu speichern. Die nehmen zwar mehr Platz weg als der reine Sourcecode, sind aber an anderer Stelle ungemein praktisch.

#8014947
Lesenswert?

Man könnte es durch Ghidra jagen und anschließend durch eine KI.

Lukas S. schrieb:

Ich habe hier den Inhalt des Flahsspeichers aus einen STM32 und ein Git-Repository mit mehreren Versionsständen des Codes.

Wieviele Kandidaten kommen in Frage?

Lukas S. schrieb:

Ich soll nun herausfinden, welcher Versionsstand genau den vorhandenen Flashinhalt ergeben hat.

Wie wichtig ist das, wirst Du extra dafür bezahlt, hast Du ein paar Wochen Zeit?

#8014963
Lesenswert?

G. K. schrieb:

Das kann man automatisieren.

Auch das erfordert die nötige Disziplin, es zu tun. Wenn man eh' so arbeitet, ist das kein Problem, aber eben nicht jeder arbeitet so.

Wieviele Projekte mir schon über den Weg gelaufen sind, in denen die Versionskennung einfach ein #define mit einem String waren, in dem dann auch irgendein Datum stand ...

Strukturiert arbeiten geht anders.

#8016236
Lesenswert?

Dann wird es schwierig bzw. langwierig.

Die genaue Konfiguration der Toolchain ist meistens im Makefile abgebildet, aber wie schon erwähnt können unterschiedliche Versionen des Compilers unterschiedlichen Output erzeugen. Auch eine andere Version einer verwendeten C-Library erzeugt ggf. anderen Output, auch wenn dein eigener Quelltext identisch compiliert wird. Vielleicht kannst du hier anhand des Zeitraums des Builds und der verwendeten Umgebung raten, welche Versionen wahrscheinlich zum Einsatz kamen.

In der Luftfahrt haben wir bei Software zwingend einen "Software Configuration Index" (SCI), wo neben dem Quellcode und Konfigurationsparametern der Software selbst auch alle relevanten Details zur Build-Umgebung und deren Konfiguration mit abgelegt werden müssen. Ein Test ist, dass jemand nur mit den Daten des SCI einen binär identischen Output erzeugen kann.

Wir compilieren zur Sicherheit immer in einer virtuellen Maschine und archivieren die zusammen mit dem Quellcode und dem SCI. So kann auch ein älterer Code einen Bugfix bekommen, ohne große Wahrscheinlichkeit, neue Fehler einzuführen. Getestet wird natürlich trotzdem.

#8016260
Lesenswert?

Lukas S. schrieb:

Gibt es eine Möglichkeit, die kompilierte .elf so mit dem .bin zu vergleichen, dass Equivalenz festgestellt werden kann (oder .hex oder wasauchimmer mit den beiden vorhandenen Dateien möglich ist)?

Das ginge nur, wenn schon ein paar Varianten als Referenzen zum Vergleichen da wären. Im Hexeditor kann man so einiges machen, z.B. auch den überflüssigen Teil der Hochsprache wegknipsen. Mit einem Emu könntest du einfach mehrere Versionen erstellen, und beide Gruppen nach z.B. nach Größe sortieren und schauen, was das hergibt.

Oliver S. schrieb:

Das kann kompliziert werden.

Das vermute ich auch, man könnte schauen, ob Programme wie Peid (als Plugin) oder elfdiff, objcopy, Rust usw. noch was bringen. Je mehr man sucht und Hilfen nutzt, desto höher die Wahrscheinlichkeit, brauchbare Ansätze zu finden.

Lukas S. schrieb:

Ich habe mit dem objcopy.exe aus einem Unterverzeichnis des STM32CubeIDE aus der Datei.elf eine Datei.bin gemacht um sie mit dem Flashinhalt vergleichen zu können

Um objcopy sinnvoll zu nutzen, braucht es wohl noch eine gewisse Einarbeitung?

#8016271
Lesenswert?

Bevor ich mir da große Gedanken über die Theorie machen würde, würde ich einfach mal die generierte bin und das Speicherabbild in Beyond Compare reinwerfen und schauen was rauskommt. Das geht schneller als hier einen Post zu verfassen. Wenn's nix bringt, hat man zwei Minuten "verloren", kann aber immernoch in der Theorie rumstochern...

#8016285
Lesenswert?

Das kommt in Klitschen und auch in renommierten Firmen immer wieder vor. Die ganz große Inventur ist wie folgt:

  1. Hinweise im Bin Nimm das 2MB bin und untersuche es auf Zeichenpattern, die wie ein
  • Datum (also sowas wie "2023" oder oder "11.23", manchmal auch mit je einem '.' dazwischen)
  • Pfad ("c:...")
  • Version (egal ob Compiler oder Programmversion)
  • Build-Nummer aussehen.
  1. Sammeln: Sammel alle .elf Files, die in Frage kommen können und schau Dir Gemeinsamkeiten/Unterschiede an (Größe, Datum, ...)

  2. Speicherabbild: Lade das heute aktuelle Elf-File in den Prozessor. Stelle sicher, dass es richtig ist, die HW läuft. Dann lese den Prozessor zurück und vergleiche elf/bin. So gewinnst Du eine Idee, wo genau das elf im Prozessor-Abbild liegt

  3. Toolchain: Bild den aktuellen Code und schaue, ob das aktuelle elf-File rausfällt. Falls nein, schaue wo die Unterschiede liegen. Falls ja, hast Du vielleicht die "richtige" Toolchain mit den richtigen Einstellungen.

  4. Puzzelarbeit: Ohne jeden Hinweis bleibt Dir nur, die bisherigen Git-Stände auszuchecken, zu kompilieren, in den Prozessor einzubrennen und den Prozessor zurückzulesen. Mit ein paar Erfahrungen aus 1-4 kannst Du Dir hoffentlich einige Schritte sparen.

#8016316
Lesenswert?

Rbx schrieb:

Das vermute ich auch, man könnte schauen, ob Programme wie Peid (als Plugin) oder elfdiff, objcopy, Rust usw. noch was bringen.

Na ja, man sollte ja zumindest die Basics beherrschen, und zumindest einen guten Hexeditor und ebenso guten Diassembler haben und auch benutzen können.

Ansonsten wirds völlig unmöglich.

Wie gesagt, ich würde als erstes die Quellen diffen, und schauen, wo da überhaupt die Unterschiede zwischen den Versionen sind. Gibts da eindeutige Strings, wirds einfach. Wenn nicht, muß man halt nach anderen Unterschieden suchen, die sich in einem disassemblierten Kompilat identifizieren lassen.

Aber selbst wenn man die Version dann identifiziert hat, kommt beim Kompilieren vermutlich nicht 1:1 das selben Kompilat raus. Wenn das das Ziel ist, muss man halt noch mit toolchains und Optionen spielen.

Oliver

: Bearbeitet durch User
Persönliche Seite #8017690
Lesenswert?

G. K. schrieb:

Harald K. schrieb:

Das setzt voraus, daß derjenige, der die Compilate erzeugte, über soviel Selbstdisziplin verfügte, diese für jeden Durchlauf hochzusetzen.

Das kann man automatisieren.

Ironischer weise macht genau dass eine einfache Auffindbarkeit durch Vergleichen unmöglich, da damit die einfache Reproduzierbarkeit nicht gegeben ist. Noch schlimmer wird es nur wenn die __ DATE __ oder __ TIME __ Makros verwendet wurden.

Also manuell hochgezählte Versionsinfos (in der Versionsverwaltung eingecheckt) in das Kompilat einbinden (dann ist es reproduzierbar).

Und/oder den Kompilat Durchlauf und den GIT Hash als extra Informationen hinten ans Binary anhängen. Dann lässt sich wenigstens mit wenig Aufwand ein individuelles Vergleichstool schreiben. Und das Compilieren wenn es zu einem Kunden geht nur einem Buildserver erledigen lassen, dann landen nicht versehentlich lokale Änderungen im Kompilat.

Dem TO viel Erfolg. Seine Aufgabe reicht irgendwo von leicht bis unmöglich.

Persönliche Seite #8017755
Lesenswert?

Harald K. schrieb:

Wenn in der Versionsverwaltung zehn Commits mit gleicher Versionsinformation sind ...

Vermutlich könnte man auch mit einem Hook bei jedem Commit ein Inkrement mit einchecken, dann wäre das auch gegeben. Ansonsten, 10 Versionen ließen sich auch durchprobieren, besser als völlig im Trüben zu stochern. Reproduzierbarkeit ist das Wichtigste. Dazu gehört auch die Bibliotheken und den Compiler zu archivieren. Notfalls sucht dann der Buildserver ein Wochenende lang automatisiert durch neu kompilieren und Vergleichen das richtige Kompilat.

#8022400
Lesenswert?

Den ausgelesenen EEPROM Dump gegen eine lokal erzeugte Datei nur simple 1:1 binär zu vergleichen schlägt idR immer Fehl, da der Programmcode idR nur ab einer bestimmten Adresse im Dump anfängt und oft hinter dem Programmcode ein Speicherblock kommt in dem das Programm persitent zu speichernde Werte ablegt wie die Konfiguration oder irgendwelche Zähler wenn das nötig ist (z.B. Betriebsstunden, Lifecyle, Abnutzungszähler für Werkzeuge/ Betriebsmittel, Fehlerzähler).

Ich hatte schonmal an meinen Flashversuchen gezweifelt, da beim verifizieren /runterladen des EEPROMS immer ein anderer HASH rauskam als beim Hochladen. Bis ich im Hex/Binärvergleich per Hand gesehen habe, dass nach dem Flashen sofort das Program beim Aufstart seine Konfig/Zähler initialisiert hatte und daher nur ein Speicherblock irgendwo hinter dem Programm abweichungen zum geflashten File hatte....

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren