Forum: Mikrocontroller und Digitale Elektronik Erkennung Programiersprache


von Willi L. (wilials)


Lesenswert?

Hallo,

kann man an einem Hexcode erkennen, in welcher Programiersprache das 
Programm geschrieben wurde und wenn ja, an was?

Gruß

wilials

von holger (Gast)


Lesenswert?

Nein, wozu auch.

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

Kannst Du knicken. Das ist Maschinencode und der kann aus sämtlichen 
Sprachen generiert worden sein. Du könntest mit verschiedenen Hex-Files 
Geschwindigkeitsmessungen am Controller machen. Der am schnellsten 
laufende Code könnte mal von einem guten Programmierer in Assembler 
geschrieben worden sein. Muss aber nicht...

von Ralf (Gast)


Lesenswert?

> kann man an einem Hexcode erkennen, in welcher Programiersprache das
> Programm geschrieben wurde und wenn ja, an was?
Das geht nur bedingt, und zwar dann, wenn du detailiert weisst, wie ein 
Compiler übersetzt. Man kann evtl. daran, wie Parameter gehandhabt 
werden schon rausfinden, welcher Compiler es war, der Startup-Code 
dürfte ebenfalls ein guter Ansatzpunkt sein.
Aber dazu müsstest du eben die entsprechenden Compiler zur Hand haben, 
um vergleichen zu können.

Ralf

von incocknito (Gast)


Lesenswert?

mit etwas erfahrung geht das recht aufwendig.

zuerst schaut man ob strings vorkommen. (enden diese mit 0x00 würde ich 
sofort auf c als sprache tippen.)

dann schaut man ob man erkennt ob 8, 16, oder 32bit architektur.

prozessor herrausfinden kann man mit suche nach JMP, RET, PUSH und POP, 
das könnte zeitaufwendig sein.

wenn man den prozessor weiss, kann man den hex-code relativ einfach in 
assembler umwandeln.

an den PUSH und POP erkennt man dann später eventuell die 
programmiersprache - gcc hat da zB eine eigene signatur.

von holger (Gast)


Lesenswert?

>prozessor herrausfinden kann man mit suche nach JMP, RET, PUSH und POP,

In einer HEX Datei stehen keine JMP, RET,...
Das steht 05890AEF67BC oder sowas.
Hexadezimale Zahlen eben.

von Willi L. (wilials)


Lesenswert?

Ralf schrieb:
> der Startup-Code
> dürfte ebenfalls ein guter Ansatzpunkt sein.

Danke, das war ein Tipp, mit dem ich etwas anfangen kann. Ursprünglich 
dachte ich an ein paar charakteristische Bits am Anfang oder am Ende des 
Codes, die Auskunft darüber geben. Der Startup-Code zeigt einen Weg.

Gruß

wilials

von troll (Gast)


Lesenswert?

incocknito schrieb:
> zuerst schaut man ob strings vorkommen. (enden diese mit 0x00 würde ich
> sofort auf c als sprache tippen.)
???
Wenn ich Assembler programmiere enden meine Strings auch mit 0 und das 
mache nicht nur ich so...

von Hmm (Gast)


Lesenswert?

Unser Holgi mal wieder. Lol.

von avr (Gast)


Lesenswert?

holger schrieb:
> In einer HEX Datei stehen keine JMP, RET,...
> Das steht 05890AEF67BC oder sowas.
> Hexadezimale Zahlen eben.

Der Ansatz ist schon richtig. Man sucht halt nach dessen Opcodes und 
nach sinnvollen Konstruktionen. Zwei ijmp oder 2 gleiche Vergleiche 
hintereinander sind beispielsweise Unsinn. push sollte ähnlich oft wie 
pop vorkommen.

von Willi L. (wilials)


Lesenswert?

incocknito schrieb:
> zuerst schaut man ob strings vorkommen. (enden diese mit 0x00 würde ich
> sofort auf c als sprache tippen.)
>
> dann schaut man ob man erkennt ob 8, 16, oder 32bit architektur.
>
> prozessor herrausfinden kann man mit suche nach JMP, RET, PUSH und POP,
> das könnte zeitaufwendig sein.
>
> wenn man den prozessor weiss, kann man den hex-code relativ einfach in
> assembler umwandeln.
>
> an den PUSH und POP erkennt man dann später eventuell die
> programmiersprache - gcc hat da zB eine eigene signatur.

Danke, auch das ist eine wertvolle Hilfe für mich

Gruß

wilials

von holger (Gast)


Lesenswert?

>Unser Holgi mal wieder. Lol.

Wieso Lol? Ich hab noch nie ein JMP im Klartext in
einer HEX Datei gesehen. Weder J, noch M noch P
sind hexadezimale Zahlen;) ROFL.

von holger (Gast)


Lesenswert?

>Der Ansatz ist schon richtig. Man sucht halt nach dessen Opcodes und
>nach sinnvollen Konstruktionen.

Dazu muss man aber schon wissen um welchen Controller es geht.
Und solche Opcodes kommen auch in Bitmaps oder Fonts vor die
das Programm evtl. benutzt.

Und wenn der TO denkt das er aus einer Hex Datei wieder ein
Programm in C oder Bascom oder sonstwas bekommen kann, dann
liegt er falsch. Das einzige was man bekommen kann ist ein
wertloses undokumentiertes Assemblerlisting.

von avr (Gast)


Lesenswert?

holger schrieb:
> Dazu muss man aber schon wissen um welchen Controller es geht.

Man kann den Controller damit finden. Ein Arm-Programm in Avr-Assembler 
disassembliert sieht sicher überhaupt nicht sinnvoll aus. Einfach ist 
das ganze nicht - aber auch Datenblöcke kann man erkennen (viele 
aufeinanderfolge unsinnige Instruktionen, abschließende 0...). Am Ende 
scheint für das Programm eine Architektur am sinnvollsten zu sein.

von adsf (Gast)


Lesenswert?

holger schrieb:
> Und wenn der TO denkt das er aus einer Hex Datei wieder ein
> Programm in C oder Bascom oder sonstwas bekommen kann, dann
> liegt er falsch.  Das einzige was man bekommen kann ist ein
> wertloses undokumentiertes Assemblerlisting.
Sehr schöne Verallgemeinerung, also haben alle Leute die 
reverse-engineering von Programmen machen ein schönes Hobby? Weil 
bezahlen wird ja keiner für das produzieren und auswerten von wertlosen 
Listings?

von Praktiker (Gast)


Lesenswert?

holger schrieb:
> Dazu muss man aber schon wissen um welchen Controller es geht.

Da kann man das Pferd auch andersrum aufzäumen und der Reihe nach 
gucken, ob die OP-Codes des verdächtigen µC an passender Stelle 
vorkommen.

von holger (Gast)


Lesenswert?

>Sehr schöne Verallgemeinerung, also haben alle Leute die
>reverse-engineering von Programmen machen ein schönes Hobby?

Oder zu viel Zeit?

Vieleicht verrät uns der TO ja noch mal warum
er wissen will womit seine HEX Datei erzeugt wurde.

von c-hater (Gast)


Lesenswert?

Willi Lich schrieb:

> kann man an einem Hexcode erkennen, in welcher Programiersprache das
> Programm geschrieben wurde

Um es am Hexcode selber zu erkennen, wird wohl zumindest etwas Übung 
erforderlich sein. Das würde ich mir im Moment nicht zutrauen. Aber ich 
würde es mir zutrauen, auch das zu lernen. Wenn ich es für nützlich 
halten würde.

Was allerdings ziemlich sicher geht, ist (nach ReAssemblierung des 
Codes) die Unterscheidung am generierten Asm-Quelltext, ob es sich um 
liebevoll und kompetent handoptimierten Assemblercode oder das 
maschinelle, trostlose, phantasielose und ineffiziente Produkt eines 
Compilers handelt.

In aller Regel kann man sogar auch noch recht problemlos herausfinden, 
welcher Compiler diesen ineffezienten Mist verbrochen hat und sogar, mit 
welchen "Optimierungsoptionen" dieses Machwerk seinen Mist produziert 
hat. Man findet sogar die längeren Asm-Inlines aus den Libs mit einem 
Blick, weil sie sich so wohltuend von ihrer Umgebung unterscheiden...

Nunja, nachdem der Compiler enttarnt ist, fällt der Rückschluß auf die 
für diesen Müll verwendete Sprache dann nicht sehr schwer...

> wenn ja, an was?

An den Mustern, die die Compiler produzieren. Der Mensch ist ein wahres 
Wunder bei der Mustererkennung. Man braucht bloß ein wenig Training. Man 
muß dabei noch nichtmal unbedingt die zur Darstellung der Muster 
verwendete Sprache verstehen. Man könnte den Kram genausogut auch als 
bunte Klötzchen darstellen. Für die Musterkennung ist das sogar 
günstiger als z.B. ein Disassemblat.

Übrigens: Allein die Tatsache, daß überhaupt so reichlich einfach 
erkennbare Muster vorhanden sind, zeigt schon, daß die Compiler massiv 
suboptimale Encoder sein müssen. Aber mit so einem Stück 
Informatik-Weisheit darfst du natürlich keinem C-Fetischisten kommen. Da 
vergißt der natürlich sofort sein gesamtes Studium zugunsten seines 
geliebten Kauderwelschs, nur um nicht in Argumentationsnotstand zu 
geraten...

von cppler (Gast)


Lesenswert?

Welche Programmiersprache der Ausgang war ist kaum sicher zu erkennen, 
jemand könnte UML genommen habe und das dann automatisch in EIFFEL 
übersetzen lassen welches dann vom EIFFEL-Compiler in reinen C-Code 
übersetzt wurde der dann vom extra optimierenden VLIW Compiler des 
Herstellers XYZ in den Opcode = HEX-File übersetzt wurde.
Die genannten Ansätze funktionieren daher nur bedingt und lassen viel 
Spielraum.
Daher gibt es auch keine mir bekannten "Disscler" oder "DisEIFFELler" 
:-P
(Ausnahme bildet JAVA aber da weiß man ja gleich was so eine .class 
Datei erstellt hat)

von Karl H. (kbuchegg)


Lesenswert?

c-hater schrieb:

> Übrigens: Allein die Tatsache, daß überhaupt so reichlich einfach
> erkennbare Muster vorhanden sind, zeigt schon, daß die Compiler massiv
> suboptimale Encoder sein müssen. Aber mit so einem Stück
> Informatik-Weisheit darfst du natürlich keinem C-Fetischisten kommen.

Mit deinem Scheiss brauchst du dafür industriell nicht auftricksen.
Da hast du dir noch gar keine Registerbelegung überlegt, bin ich in C 
schon wieder fertig. Mit einem Hochsprachenoverhead, der sich im kleinen 
einstelligen Prozentbereich bewegt und völlig uninteressant ist.

Industrielles Entwickeln ist eine Geldfrage. Deine paar Prozent, die 
dein Assemblerprogramm (abgesehen von Ausnahmefällen, wenn eine ISR 
wirklich taktgenau schnell sein muss) schneller ist, interessieren 
keinen. Aber es interessiert ob du an einem Vormittag oder in einer 
Woche fertig bist. Denn das wirkt sich für den Kunden in Geldeinheiten 
aus.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

c-hater schrieb:
> Allein die Tatsache, daß überhaupt so reichlich einfach
> erkennbare Muster vorhanden sind, zeigt schon

… dass du schon lange keinen compilergenerierten Code mehr
angesehen hast.  Vermutlich das letzte Mal zu Zeiten der PDP-11.

So ziemlich das einzige, woran man den Compiler sehr sicher erkennt,
ist das Durchziehen gleichmäßiger Aufrufkonventionen von Funktionen
bzw. Unterprogrammen.  Allerdings könnte es passieren, dass geübte
Assemblerprogrammierer diese Technik ebenfalls beherrschen. ;-)

von adsf (Gast)


Lesenswert?

Jörg Wunsch schrieb:
> So ziemlich das einzige, woran man den Compiler sehr sicher erkennt,
> ist das Durchziehen gleichmäßiger Aufrufkonventionen von Funktionen
> bzw. Unterprogrammen.

Mir würde bei x86-Familie noch das ziemlich "zufällige" verwenden von 
SSE-Erweiterungen oder so einfallen. Ein Mensch findet selten in einem 
Programm ein paar wenige Stellen wo die irgendwie nützlich sind, sondern 
verwendet sie entweder gezielt oder garnicht.

von holger (Gast)


Lesenswert?

>Um es am Hexcode selber zu erkennen, wird wohl zumindest etwas Übung
>erforderlich sein. Das würde ich mir im Moment nicht zutrauen. Aber ich
>würde es mir zutrauen, auch das zu lernen. Wenn ich es für nützlich
>halten würde.

Dann bist du der letzte der hier Tips geben kann.

>Nunja, nachdem der Compiler enttarnt ist, fällt der Rückschluß auf die
>für diesen Müll verwendete Sprache dann nicht sehr schwer...

Dieser Rückschluss nützt aber niemandem.
Aus einem Hamburger kann man keine lebende Kuh mehr machen.

Ich nehme den vom Compiler erzeugten Müll gerne in Kauf.
Wenn ich ein C Projekt auf eine andere uC Architektur
umsetzen muss kann ich bestimmt 80% mitnehmen und muss nur 20%
neu machen.

Der Assemblerprogrammierer muss 100% neu machen.
Falls er sich überhaupt mal aus seinem Nest rauswagt.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Ein Disassembly des Codes gibt schon recht gut Aufschluss über die
verwendete Sprache und den Compiler. Ist der Prozessortyp nicht bekannt,
probiert man einfach mehrere Disassembler aus und schaut nach, wo
zumindest streckenweise sinnvoller Coder herauskommt.

Hier sind ein paar (teilweise schon genannte) Kriterien, die
entsprechende Hinweise geben:

Startup- und Exit-Code: Bspw. wird in einem C++-Programm eine
aufwendigere Initialisierung statischer Variablen durchgeführt (wegen
der Konstruktoren) als in einem C-Programm.

Formate bestimmter Datentypen: Bspw. sehen Strings in C anders als in
Basic oder Pascal aus.

Unterprogrammaufrufkonventionen: Bspw. unterscheiden sich C, Pascal und
Basic recht deutlich in der Argumentübergabe (verwendete Register,
Stacknutzung), dem Anlegen von lokalen Variablen auf dem Stack (z.B.
Frame-Pointer in C) und dem Aufräumen des Stacks nach der Rückkehr aus
dem Unterprogramm.

Verwendete Untermenge des Prozessorbefehlssatzes: Die meisten Compiler
verwenden nicht alle zur Verfügung stehenden Befehle. Dadurch kann die
Suche etwas eingeschränkt werden.

Speziell genutzte Register: Bspw. ist beim AVR-GCC das R1-Register für
den Wert 0 reserviert und wird nach jeder Multiplikation (die dieses
Register überschreibt) mit 0 nachgeladen.

Bibliotheksfunktionen: Man kann versuchen, einfache Funktionen, wie
bspw. die _delay_[um]s-Funktion der AVR-Libc wiederzuerkennen. Auch
arithmetische Funktionen wie die Integerdivision werden je nach
verwendeter Tool-Chain unterschiedlich aussehen.

Besonders bei nichtimperativen Sprachen sieht der compilierte Code meist
sehr charakteristisch aus, da sie ein ganz anderes Ablaufschema haben:
Bspw. generiert ein Haskell-Compiler einen riesengroßen Spaghetti-Code,
der kaum Unterprogrammaufrufe enthält. Ein Prolog-Programm sieht
nochmals ganz anders aus.

Generell kann gesagt werden: Je höher die verwendete Programmiersprache,
umso mehr weicht der erzeugte Code von einem in Assembler programmierten
Programm ab.

Theoretisch kann natürlich jedes Assemblerprogramm so aussehen, als wäre
es von einem Compiler generiert worden. Wenn aber gleich mehrere der
o.g. Kriterien auf die gleiche Programmiersprache oder gar den gleichen
bestimmten Compiler hinweisen, ist der Wahrscheinlichkeit schon sehr
groß, dass man damit einen Treffer gelandet hat.

Bei der Analyse muss man aber immer auch berücksichtigen, dass Teile des
Programms (insbesondere Bibliotheksfunktionen) unabhängig von der sonst
verwendeten Programmiersprache in Assembler geschrieben sein können. Auf
diese Teile sind natürlich die meisten der genannten Kriterien nicht
anwendbar.

Eine große Hilfe ist es, wenn man möglichst alle der in Frage kommenden
Compiler verfügbar hat, um im Zweifelsfall mittels kleiner Testprogramme
nachschauen zu können, was deren Charakteristika bei der Übersetzung
sind.

von Spess53 (Gast)


Lesenswert?

Hi

Also ich kann mich noch erinnern, das sich einige Compiler bei 
PC-Programmen im Klartext in der .exe verewigt haben.

MfG Spess

von adsf (Gast)


Lesenswert?

holger schrieb:
> Dieser Rückschluss nützt aber niemandem.
> Aus einem Hamburger kann man keine lebende Kuh mehr machen.

Ist richtig, aber es hat ja auch keiner behauptet, dass man irgendwas 
mit der Information anfangen kann, oder?

von Reinhard Kern (Gast)


Lesenswert?

Hallo,

bevor man sich da lange alles mögliche abbricht: bei mir steht im 
Binärcode normalerweise ein Copyright-Vermerk drin, das machen auch 
viele andere programmierer so - weniger aus Eitelkeit sondern weil man 
beim Programmieren oder EPROM-Tauschen gleich sieht, welches Programm 
und welche Version. Und wenn man den Programmierer weiss kann man den ja 
fragen.

Auch Libraries sind oft gekennzeichnet, und bei PC-Programmen stehen 
soviel DLL-Aufrufe drin, dass man leicht feststellen kann womit sie 
erzeugt wurden, z.B. wenn VBRUN oder MSVC files angefordert werden.

Gruss Reinhard

von holger (Gast)


Lesenswert?

>> Dieser Rückschluss nützt aber niemandem.
>> Aus einem Hamburger kann man keine lebende Kuh mehr machen.

>Ist richtig, aber es hat ja auch keiner behauptet, dass man irgendwas
>mit der Information anfangen kann, oder?

Auch richtig, dann ist es aber auch sinnlos hier weiter zu posten.
Wozu braucht man das dann? Es ist nicht verwertbar. Zeitverschwendung.
Ich könnte mal ein paar Hex Dateien posten und ihr ratet wo
die herkommen. Dabei werde ich natürlich schummeln;)

Der TO meldet sich nicht mehr. Wahrscheinlich hab ich ihn verjagt.

von avr (Gast)


Lesenswert?

Jörg Wunsch schrieb:
> … dass du schon lange keinen compilergenerierten Code mehr
> angesehen hast.  Vermutlich das letzte Mal zu Zeiten der PDP-11.

Achja? Dann scheint avrgcc 4.7.2 auch aus der Zeit zu stammen. 
Jedenfalls finden ich viel zu oft einfache Optimierungsmöglichkeiten, 
die in meinem Assemblercode enthalten wären. avrgcc gegen asm dürfte ich 
zu 99%+ erkennen (sofern der Assemblerprogrammierer es nicht darauf 
anlegt, den C-Compiler zu imitieren). Selbst viele einfache 
Optimierungen sind teilweise nicht enthalten (Ob sie inzwischen 
implementiert sind, kann ich nicht garantieren):

-subi+sbci durch sbiw/adiw ersetzen
-rcall+ret durch rjmp ersetzen
-dauerndes überschreiben des Pointerregisters mit der selben Variable,
 statt einmal kopieren und st Z+ nutzen
-1<<x mit Schleife, statt 14 Takte Funktion oder 7 Takte inline
 (wäre eine Option für O2; ja das geht wirklich in nur 7 Takten).

Und der Overhead ist nicht klein, wenn man ein bisschen Assembler 
programmieren kann. Wenn ich in C programmiere, sollte ich gar nicht 
mehr ins listing schauen, sonst rege ich mich wieder unnötig über den 
Compiler auf.

von BöserFisch (Gast)


Lesenswert?

Interessant, wie breitbandig das Fachwissen bzw Unkenntnis sich hier 
reflektiert...
Ich habe hier Tools, welche genau sowas machen, nämlich Architektur 
eines Binaries erkennen (Format, CPU-Architektur, Programmstruktur, 
Einsprungsanalyse), zudem können für einige Architekturen Compiler 
ermittelt werden (von GCC über Keil bis exotische Pascal-Compiler).
Bevor nun wer fragt, wo man diese Software kriegen kann: Sind 
in-house-Tools für Reverse-Engineering, und werden auch in-house 
bleiben.
Kurze Antwort also: Ja, man kann.

von Proxxon (Gast)


Lesenswert?

Spess53 (Gast) schrieb:

> Hi

> Also ich kann mich noch erinnern, das sich einige Compiler bei
> PC-Programmen im Klartext in der .exe verewigt haben.

> MfG Spess

Teilweise ist das so, je nach dem ob Exe-Packer oder Protecter SW 
eingesetzt wurde und man nicht vorsätzlich eine falsche Fährte legen 
wollte.

Beispiele:

eagle v6: Microsoft Visual C++ 8; QT als Framework

Sprint Layout 6: Borland Delphi 4.0

Diptrace: Delphi (Delphi 5)

LTSpice: MS Visual C++ 6, Framework MFC

DosBOX v0.74: MingWin32 C++ 4.x

7-zip: MS Visual C++

XnView: Microsoft Visual C++ 6; kaum Hinweise auf MFC

PDFCreator: MS Visual BASIC 5/6

von Willi L. (wilials)


Lesenswert?

Vielen Dank an alle, die sich an diesem Thema beteiligt haben.
Ich empfand die Beiträge als sehr informativ, womit auch mein Grund für 
das Thema definiert ist.

Es war nicht meine Absicht, Codes zu "knacken". Weiterhin bin ich der 
Ansicht, daß Wissen nicht schadet, auch wenn man damit kein direktes 
Ziel verfolgt.

Nochmals vielen Dank für die Beiträge. Mein Ergebnis lautet: Man kann!

Gruß

wilials

von Erich (Gast)


Lesenswert?

>Mein Ergebnis lautet: Man kann!

Hmmm, ja gut; schön.
Mein Glückwunsch.
Aber was willste mit der Erkenntnis jetzt anfrangen?
Für'n Nobelpreis wird's nicht reichen.

Gruss

von Bronco (Gast)


Lesenswert?

BöserFisch schrieb:
> Sind in-house-Tools für Reverse-Engineering,

Jetzt wüßte ich schon gerne, was für ein house das ist...

von Andreas B. (andreas_b77)


Lesenswert?

avr schrieb:
[Thema was der avr-gcc 4.7.2 alles nicht kann]
> -rcall+ret durch rjmp ersetzen

Na, dachte ich mir, probier ich das gleich mal mit dem avr-gcc 4.7.2 
aus:
1
int ext_f(int x);
2
3
int f(int x)
4
{
5
  return ext_f(x * 2);
6
}

Ergebnis mit -Os:
1
Disassembly of section .text:
2
3
00000000 <f>:
4
   0:  88 0f         add  r24, r24
5
   2:  99 1f         adc  r25, r25
6
   4:  00 c0         rjmp  .+0        ; 0x6 <__zero_reg__+0x5>

Die anderen Sachen habe ich jetzt auf die Schnelle nicht getestet.

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.