Welchen Nutzen hat es, Maschinensprache (Binärcode) lesen zu können?

10 Antworten

Wie Roderic und einige andere schon angemerkt haben, vermischst du hier zwei Sachen - deshalb gehe ich jetzt nicht näher auf die Zahlendarstellung in Basis 2 ein, sondern komme gleich zum Maschinencode. :)

Normalerweise kann man kompilierte Programme disassemblieren und so in eine Art "Assembler-Quelltext" umwandeln. Diesen Quelltext kann man dann - genügend Erfahrung vorausgesetzt - auch lesen, analysieren, manipulieren und sogar komplett umschreiben.

Leuten mit Erfahrung reicht oft sogar der reine Hex-Dump ... mit anderen Worten, so jemandem reicht ein Hex-Editor (und vielleicht noch einige andere kleinere Tools), um die Funktionsweise eines Programms verstehen zu können.

Die Kunst, kompilierte Software (ausführbare Formate wie EXE, ELF, usw.) oder Daten-Blobs (Firmware-Images, Memory-Dumps, etc.) analysieren zu können nennt man "Reverse Engineering" oder kurz "Reversing".

Es gibt oft den Fall, dass Firmen ihre Bibliotheken veröffentlichen, aber viele nicht-dokumentierte Funktionen (oder gar Hintertüren) in eine Software einbauen. Wenn jetzt eine Drittfirma solch eine Bibliothek kauft, und genaue Informationen über die Funktionsweise, eine "erweiterte Headerdatei", oder Bindings für andere Sprachen haben möchte, obwohl eine dynamische Bibliothek nur in kompilierter Binärform ohne Debugging-Symbole vorliegt, beauftragen sie Leute wie mich, die dann helfen können.

Darüber hinaus werde ich oft damit beauftragt Malware zu untersuchen, oder Kopierschutzsysteme auf ihre Tauglichkeit hin zu untersuchen. Außerdem kann man sich die eigene disassemblierte Software ansehen, und gucken, ob der Compiler alles richtig gemacht hat. Dieser letzte Punkt ist oft bei embedded Systemen wichtig, da die Compiler hier leider oft keine so gute Qualität haben, wie auf größeren Desktop-Plattformen.

Für all das muss man natürlich verschiedene Assembler-Dialekte für diverse Plattformen beherrschen.

Zum Üben würde ich mit Assembler für x86, x86-64 und ARM anfangen, die MSIL und Java Bytecode lesen lernen und auch mal bei Mikrocontrollern wie PICs und Atmels reinschnuppern. Danach in diversen Foren die Grundlagen des Reversings lernen, mir ein halbes Jahr Zeit nehmen um intensivst Spezifikationen, Datenblätter, Dokumentationen, RFCs, etc. zu lesen, und danach an CrackMes üben.

Irgendwann ist man dann auf einem Level angekommen, an dem man ...

E8XXXXXXXX 84C0 74XX BF01000000 E8XXXXXXXX

... liest, und das dann sofort im Kopf in folgenden C-Source übersetzen kann:

if (foo()) {
exit(1);
}

Dieses Muster existiert mindestens in ähnlicher in nahezu JEDEM Programm. (Unbekannte Adressen habe ich jetzt mal durch eine Folge von X ersetzt.) Es wird einfach der Rückgabewert einer Funktion überprüft, und das Programm im Fehlerfall sofort beendet. Ist zwar schlechter Stil, aber - wie gesagt - das gibt es leider öfter als man denkt! :)

Wie du siehst reicht für so ein einfaches Beispiel tatsächlich jeder primitive Hex-Editor und evtl. noch das Intel-Software-Developers-Manual für weniger erfahrene Reverser.

ARM Maschinencode ist übrigens noch viel leichter zu lesen als x86 oder x86-64 Code. Und MSIL bzw. Java-Class-Files sind noch mal eine Nummer leichter zu lesen. (Wobei "leicht" hier relativ ist, und in jedem Falle sehr viel Erfahrung voraussetzt!)

Also um deine Frage zu beantworten: Die Fähigkeit Maschinencode zu lesen ermöglicht die Analyse und das Verständnis von kompilierter oder geschützter Software.

PS: Normalerweise muss man aber keinen Maschinencode (in Hex-Form) lesen können, da jeder Disassembler oder Debugger auch sehr gut lesbaren und schön formatierten Assembler-Code ausspuckt.

Ich weiß nicht, wie andere darüber denken, aber die Analyse ausschließlich im Hex-Editor ist mehr oder weniger Sport für mich. Ein Crackme kann jeder mit IDA knacken ... aber wenn man keinerleich weitere Tools, sondern nur ghex zur Verfügung hat werden selbst einfachere Programme zur Herausforderung ... sinnvollerweise sollte man aber in realistischen Szenarien so viel Hilfe von so vielen Tools wie möglich annehmen! Ich glaube, die Leute die Hex-Editor-Trockenübungen machen, sind rar gesät, und oft kommt man damit wirklich nicht weiter. Aber unter Linux mal schnell nachgucken, was die Trojaner-EXE im Mailanhang so alles macht, ist damit wirklich sehr praktisch und sehr schnell möglich ... vorausgesetzt es wird keine extravagante Obfuscation benutzt ... dann kommt man um einen Debugger natürlich nicht drum rum. :)

Samengel1  22.01.2024, 17:53

Sehr sehr gut und ausführlich erklärt

0

 Die Erkennung der 16 und 32 Bit ASM Befehle war noch relativ einfach:  

16 Bit: http://sparksandflames.com/files/x86InstructionChart.html  

90     NOP (nichts tun)  
40     INC ax (Register ax=ax+1)  
00 0D  ADD al,dl (addiere Register dl zu al: al=al+dl) 
DB E3   finit (Initialisierung der FPU=Coprozessor) 

 32 Bit: 

einfach Hex-Byte 66 davor -> so konnte man schon mit dem alten Turbo Pascal 16 Bit der 386 CPU 32 Bit Befehle entlocken:   

asm 
 db 066h;INC AX 
 end;

Daraus wurde also 

 66 40 INC eax (32 Bit Register eax = eax + 1)   

Aber schon Anfang und Ende eines Befehls aus den Hex-Bytes zu erkennen, ist bei komplexeren Programmen sehr schwer und fehleranfällig!

Also wenn man schon vor einem Computer sitzt, kann man auch gleich mit der richtigen Software "Diassembler" (google mal danach und schalte auf "Bilder" um) den Hex-Code nach ASM wandeln siehe Bild. 

 Wozu: 

 - herausfinden, warum bei einer Software eine AMD-CPU trotz gleicher GHz und logischer Kerne etwa 3 mal langsamer als ein i7 von Intel ist (weil die SSE2 Befehle beim i7 weniger Takte benötigen) 

 - herausfinden, was ein Virus anstellen will 

 - herausfinden, ob Teile der Software "abkopiert" wurden 

 - herausfinden, ob der Compiler gut optimiert, oder nur einfache 0815 Befehle verwendet 

 - herausfinden, ob Software auf einer alten CPU (ohne gewisse Befehlssätze) sauber laufen wird 

 - Fehlersuche 

 - "Verstecke" finden: in deaktiven Bereichen können versteckte Daten liegen 

Diassembler - (Computer, programmieren, Programmiersprache)
hypergerd  10.07.2015, 10:46

Interessant war auch die Suche nach der Ursache, warum einige Programme nur 14 (max 15) Stellen statt 18 (max 19) Stellen genau rechnen, obwohl die FPU bei 80 Bit genau genug ist und man den Typ long double verwendet hat:  

Microsoft Compiler casten long double nach double -> nutzen bei der fpu nur 64 Bit statt die vorhandenen 80 Bit !!  

Oder http://www.gerdlamprecht.de/GrobeFPU_Fehler.htm   

unter 

§2 grobe FSIN Ungenauigkeit  

kann man vergleichen, wie unterschiedlich Browser den sin-Befehl umsetzen:  

einige schicken den Befehl direkt als fsin zur fpu, was bei großen Argumenten nicht mal 1 richtige Nachkommastelle bedeutet!!

Der Safari-Browser kennt vermutlich das Problem und rechnet das anders aus (oft 15 richtige Stellen) -> hat aber Nachteile bei der Geschwindigkeit.

1

Es geht bei Binärcode nicht nur um Maschinensprache. Auch wenn man sich für die innere Arbeitsweise der CPU nicht interessiert, kommt man als professioneller Programmierer kaum darum herum, sich mit den Einsen und Nullen zu befassen.

Ohne die einzelnen Bits anzuschauen versteht man nicht wirklich, wie die verschiedenen Zahlenformate funktionieren (Höchster und niedrigster möglicher Wert mit und ohne Vorzeichen, Mantisse, Exponent, Rundungsfehler).

Ohne Kenntnis von Binärcode versteht man kaum, wie die verschiedenen Codierungssysteme für Schriftzeichen funktionieren, wenn man über 7-Bit- ASCII hinausgeht und z.B. die Unterschiede z.B. zwischen den einzelnen ISO-8859-Zeichensätzen für Westeuropa, Mitteleuropa, Skandinavien usw. begreifen will, oder wie UTF-8 funktioniert und wie die typischen Fehler bei der UTF-8-Verarbeitung zustandekommen.

Schließlich bekommt man, ohne sich nicht mit einzelnen Bits zu befassen, auch weder einen Zugang zu den Kompressions- und Verschlüssselungsverfahren noch versteht man Netzwerkprotokolle und Dateisysteme.

Binärcode (Binärcodierung) und Maschinensprache (Assembler) ist NICHT dasselbe.

Das erste lernt jeder Mathe- oder Informatikstudent.

Letzteres erzeugt der Compiler und macht so aus den Quelltexten für den jeweiligen Prozessor ausführbare Anweisungen.

Eigentlich nicht viel, da der Binärcode sowieso umgesetzt wird ^^ Solange du jetzt nicht solche spezielle Software entwickelst, brauchst du das nicht.