Konferenz DEFCON 18. Troll Reverse Engineering mit Hilfe der Mathematik

Ursprünglicher Autor: frank ^ 2
  • Übersetzung
Trolling mit Mathe ist das, worüber ich sprechen werde. Dies ist kein modischer Hacker-Kram, sondern ein künstlerischer Ausdruck, eine witzige intelligente Technologie, bei der die Leute Sie für einen Trottel halten. Jetzt prüfe ich, ob mein Bericht zur Anzeige auf dem Bildschirm bereit ist. Es scheint, dass alles gut läuft, so dass ich mich vorstellen kann.



Mein Name ist Frank Tu, es wird auf ^ ^ und @Franksquared auf Twitter geschrieben, weil Twitter auch eine Art Spammer namens "Frank 2" hat. Ich habe versucht, Social Engineering auf sie anzuwenden, damit sie sein Konto löschen, weil es sich technisch um Spam handelt und ich das Recht habe, es als Klon zu entfernen. Aber anscheinend, wenn Sie ehrlich mit ihnen sind, werden Sie nicht erwidert, denn trotz meiner Bitte, das Spam-Konto zu löschen, haben sie nichts damit zu tun, also habe ich dieses verdammte Twitter zur Hölle geschickt.

Viele Leute erkennen mich an meiner Mütze. Ich arbeite in regionalen Gruppen DefCon DC949 und DC310. Ich arbeite auch mit Rapid7, aber ich kann hier nicht ohne Obszönitäten davon sprechen, und mein Manager möchte nicht, dass ich schwöre. Also habe ich diesen Gig für DefCon vorbereitet und werde mich in 15 Minuten treffen, obwohl dies ein ziemlich schwieriges Thema ist. Im Wesentlichen ist dies eine Standardpräsentation, die sich mit Reverse Engineering und verwandten Dingen beschäftigt.

Bei der Diskussion dieses Themas auf Twitter wurden zwei Lager gebildet. Ein Typ sagte: "Ich habe keine Ahnung, worüber dieser verdammte Frank spricht, aber es ist großartig!" Der zweite von Reddit sah meine Folien und war verärgert über die Verweise auf Dinge, die für das Thema nicht relevant waren. Er wurde wütend, dass ein derart ernstes Thema nicht vollständig behandelt wurde. Daher wünschte ich mir, dass es in meiner Präsentation „mehr Inhalt und weniger Müll“ gibt.



Deshalb möchte ich mich auf dieses Zitat konzentrieren. Nichts Persönliches, Alter von Reddit - ich sage das nicht nur für den Fall, dass er in diesem Raum anwesend ist, sondern auch, weil es eine faire Kritik war. Denn eine Konversation, die nicht genügend nützliche Inhalte enthält, ist nur eine leere Konversation.

Das Thema meines Gesprächs stellt eine Standardroutine für Hacker dar, aber es scheint mir, dass die Sprecher normalerweise nicht versuchen, ihre Informationen auf unterhaltsame Weise darzustellen, selbst wenn dies möglich ist, wobei trockene, verwässerte Schlussfolgerungen bevorzugt werden. "Hier ist die IP, hier ist das ESP, so können Sie den Exploit ausführen, hier ist mein" Zero Day ", jetzt klatschen!" - und alle klatschen in die Hände.

Danke für den Applaus, ich weiß es zu schätzen! Es scheint mir, dass es in meinem Material viele interessante Punkte gibt, so dass es verdient ist, auf etwas unterhaltsame Weise dargestellt zu werden, was ich versuchen werde.

Sie werden eine äußerst oberflächliche Einstellung gegenüber der Informatik und einen völlig kindlichen Humor sehen. Ich hoffe, Sie schätzen, was ich hier zeigen werde. Es tut mir sehr leid, dass Sie hierher gekommen sind und nach einem ernsthaften Gespräch gesucht haben.

Auf der Folie sehen Sie eine wissenschaftliche Analyse meines letzten Berichts, in der der Anteil eines streng wissenschaftlichen Ansatzes mit dem Anteil der "Medizin" verglichen wird, der Computersicherheit bietet.



Sie sehen, die "Medikamente" sind viel mehr, aber machen Sie sich keine Sorgen, jetzt ist der Anteil der Wissenschaft leicht gestiegen.



Vor einiger Zeit schrieb mein Freund Merlin, der in der ersten Reihe sitzt, einen erstaunlichen Bot, der auf dem IRC-Python-Skript basiert, das nur eine Zeile belegt.

Dies ist wirklich eine großartige Übung für das Erlernen der funktionalen Programmierung, was sehr viel Spaß macht. Sie können einfach eine Funktion nach der anderen hinzufügen und Kombinationen aller möglichen unterschiedlichen Funktionen erhalten, und all dies wird als Regenbogenwelle auf dem Bildschirm dargestellt. Im Allgemeinen ist dies eines der dümmsten Dinge, die Sie tun können.



Ich dachte, was wäre, wenn ich dieses Prinzip auf Binärdateien anwenden würde? Ich weiß nicht, wo ich auf diese Idee gekommen bin, aber es ist großartig geworden! Ich möchte jedoch einige grundlegende Konzepte erläutern.

Es ist möglich, dass Ihr Mathematiklehrer diese Funktionen viel schwieriger eingeführt hat, als sie wirklich sind.



Die Formel f (x) hat also eine sehr einfache Bedeutung und funktioniert wie normale Funktionen. Sie haben X, Sie haben Eingaben, und dann erhalten Sie X 7-mal, und dies entspricht Ihrem Wert. In Python können Sie eine Funktion erstellen (Lambda x: x * 7). Wenn Sie mit Java arbeiten möchten - tut mir leid, ich hoffe, dass Sie es niemals tun möchten - Sie können Folgendes tun:

public static int multiplyBySevenAndReturn(Integer x)
{ return x * 7; }

Wissen Sie, mathematische Funktionen können sogar viel komplizierter sein, aber das ist alles, was wir im Moment über sie wissen müssen.

Wenn wir den Code zusammenstellen, können wir feststellen, dass die JMP- und CALL-Anweisungen nicht an bestimmte Werte gebunden sind. Sie arbeiten mit einem Offset. Wenn Sie einen Debugger verwenden, können Sie feststellen, dass der JMP00401000 eher der Anweisung "Mehrere Bytes überspringen" ähnelt als einer bestimmten Anweisung, um 5 oder 10 Bytes zu überspringen. Dasselbe gilt für die CALL-Funktion, außer dass sie eine ganze Reihe von Dingen in Ihren Stack schiebt. Die Ausnahme ist der Fall, wenn Sie die Adresse in das Register „einfügen“, dh auf eine bestimmte Adresse verweisen. Hier ist alles völlig anders. Nachdem Sie eine Adresse an ein Register angehängt haben und etwas wie CALL EAX ausführen, greift die Funktion auf einen bestimmten Wert in EAX zu. Dasselbe gilt für CALL [EAX] oder JMP [EAX] - es wird nur EAX derefiziert und geht an diese Adresse. Wenn Sie einen Debugger verwenden, können Sie möglicherweise nicht feststellen, auf welche Adresse sich CALL bezieht. Dies kann ein Problem sein, daher sollten Sie sich dessen bewusst sein.
Schauen wir uns die JMP SHORT-Funktion "Short Jump" an. Dies ist eine spezielle Anweisung in der x86-Architektur, mit der Sie einen Versatz von 1 Byte anstelle eines Versatzes von 4 Byte verwenden können, wodurch der verwendete Speicherplatz reduziert wird. Dies macht später einen Unterschied für alle Manipulationen, die bei einzelnen Anweisungen auftreten. Es ist wichtig zu wissen, dass JMP SHORT einen Bereich von 256 Byte hat. Es gibt jedoch keinen CALL SHORT.



Betrachten wir nun die Hexerei der Informatik. Bei der Erstellung dieser Folien habe ich festgestellt, dass Sie eine Assembly eigentlich als Nullraum definieren können, dh technisch gesehen gibt es zwischen jedem Befehl null Platz. Wenn Sie sich die einzelnen Anweisungen ansehen, werden Sie feststellen, dass jede nach der anderen Anweisung ausgeführt wird. Technisch kann dies als unbedingter Sprung zur nächsten Anweisung interpretiert werden. Dies gibt uns den Raum zwischen jeder Montageanweisung, während jede Anweisung entsprechend mit einem unbedingten Sprung verbunden ist.

Wenn Sie sich dieses Montagebeispiel anschauen, sind dies übrigens sehr einfache Dinge, die ich mit ASCII decodieren sollte. Dies ist also nur eine Reihe normaler Anweisungen.



JMP 0 zwischen den einzelnen Anweisungen sind unbedingte Sprünge, die Sie normalerweise nicht sehen. Sie folgen einander nach jeder Anweisung. Daher ist es möglich, jeden einzelnen Assemblierungsbefehl genau dann an einem beliebigen Speicherplatz abzulegen, wenn jeder einzelne Befehl von einem unbedingten Sprung zum nächsten Befehl begleitet wird. Wenn Sie die Assembly übertragen und denselben Code wie zuvor verwenden müssen, müssen Sie jeder Anweisung einen unbedingten Sprung hinzufügen.
Lass uns weiter schauen. Ein eindimensionales Array kann technisch als ein zweidimensionales Array interpretiert werden. Es erfordert nur ein wenig Mathematik, Zeilen oder ähnliches, was ich nicht sagen kann, aber es ist nicht zu kompliziert. Dies gibt uns die Möglichkeit, den Speicherort in Form eines Gitters (x, y) zu interpretieren. Kombiniert mit der Interpretation des leeren Raums zwischen Anweisungen als bedingungslose Sprünge, die miteinander verknüpft werden können, können wir Anweisungen buchstäblich zeichnen. Das ist großartig!

Um dies in die Praxis umzusetzen, sind folgende Schritte notwendig:

  • zerlegen Sie jede Anweisung, um den Code herauszufinden;
  • Weisen Sie einen Speicherplatz zu, der viel größer ist als die Größe eines Befehlssatzes. Normalerweise reserviere ich die zehnfache Speichergröße des Codes.
  • Bestimmen Sie für jeden Befehl f (x);
  • jeden Befehl auf den entsprechenden Speicherplatz (x, y) setzen;
  • fügen Sie der Anweisung einen unbedingten Sprung hinzu;
  • Markieren Sie den Speicher als ausführbar und führen Sie den Code aus.

Leider stellen sich hier viele Fragen. Es ist wie mit der Schwerkraft, die nur in der Theorie funktioniert, aber in der Praxis sehen wir eine völlig andere. Da x86 Ihre JMP-Anweisungen (CALL-Anweisungen) an die Zeile sendet, verzerrt dies Ihren selbstreferenziellen Code, einen sich selbst ändernden Code, der Iteration verwendet.



Beginnen wir mit JMP-Anweisungen. Da JMP-Anweisungen einen Versatz haben, zeigen sie an einem beliebigen Ort nicht mehr auf den Ort, an dem sie sich befinden. SHORT JMP befindet sich in einer ähnlichen Position. Sie werden zufällig von Ihrer Funktion (x, y) platziert und zeigen nicht an, worauf Sie zählen. Im Gegensatz zu "long" JMP ist "short" JMP jedoch einfacher zu beheben, insbesondere wenn es sich um ein eindimensionales Array handelt. SHORT JMP lässt sich leicht in reguläres JMP konvertieren, aber dann müssen Sie herausfinden, was aus dem neuen Offset geworden ist.

Die Arbeit mit registergestütztem JMP ist auch ein Problem, und da sie harte Verschiebungen erfordern und während der Ausführung berechnet werden können, gibt es keine einfache Möglichkeit zu wissen, wohin sie gehen. Um jedes Register automatisch zu ermitteln, müssen Sie eine Menge Wissen aus der Kompilierungstheorie verwenden. Bei der Ausführung können Funktionszeiger, Klassenzeiger und dergleichen vorhanden sein. Wenn Sie jedoch keine zusätzlichen Arbeiten ausführen möchten, um all dies zu tun, können Sie dies nicht tun. Die Funktionen f (x), die in echtem Code arbeiten, sind nicht so elegant wie auf dem Papier. Wenn Sie es richtig machen wollen, müssen Sie viel Arbeit erledigen.

Um Klassenzeiger und ähnliches zu definieren, müssen Sie mit C und C ++ beschwören. Konvertieren Sie vor dem Speichern während der Demontage Ihren SHORT JMP in einen regulären JMP, da Sie mit dem Offset umgehen müssen. Dies ist ziemlich einfach.

Der Versuch, die tatsächlichen Verschiebungen zu berechnen, ist ein großer Kopfschmerz. Alle von Ihnen gefundenen Anweisungen haben Offsets, die sich verschieben, wenn der Code verschoben wird, und müssen neu berechnet werden. Dies bedeutet, dass Sie die Anweisungen befolgen müssen und wo sie sich bewegen, wie Ziele. Es fällt mir schwer, Sie auf Folien zu erklären, aber ein Beispiel dafür ist auf der CD mit den Materialien dieser Konferenz.

Nachdem Sie alle Anweisungen eingegeben haben, ersetzen Sie die alten Offsets durch die neuen Offsets. Wenn Sie den Offset nicht beschädigen, wird alles funktionieren. Wenn Sie nun vorbereitet sind, besteht die Möglichkeit, Ideen auf höchstem Niveau zu übersetzen. Dafür brauchen Sie:

  • Anweisungen demontieren;
  • Bereiten Sie einen Speicherpuffer vor.
  • vorhandene Konstanten f (x) initialisieren;
  • iterieren Sie die Werte von f (x) und bestimmte Datenzeiger, auf die Ihr Code geschrieben wird, während Sie die verdächtigen Anweisungen verfolgen.
  • den entsprechenden erstellten Zeigern Anweisungen zuzuweisen;
  • alle bedingten Sprünge korrigieren;
  • Markieren Sie einen neuen Abschnitt des Speichers als ausführbar.
  • Code ausführen.

Wenn Sie alles an die richtigen Stellen bringen, bekommen wir seltsame Dinge - alles wird verwirrt, Anweisungen springen an fremde Orte der Erinnerung und alles sieht einfach bezaubernd aus.



Hat das alles eine praktische Bedeutung oder ist es nur eine Zirkusvorstellung? Der angewendete Wert solcher Transformationen ist wie folgt. Die Isolation der Montageanweisungen und mehrere Schritte zur Berechnung von f (x) ermöglichen es uns, diese Montageanweisungen an beliebiger Stelle im Puffer ohne Benutzerinteraktion zu platzieren. Um die Pfade der Codeausführung zu verwirren, müssen Sie lediglich Funktionen und Zeiger in einem Assembler mathematisch schreiben und sie nach dem Zufallsprinzip auswählen.

Dies vereinfacht die polymorphen Codierungsmethoden erheblich. Anstatt jedes Mal Code zu schreiben, der den Code auf eine bestimmte Weise manipuliert, können Sie eine Reihe von Funktionen schreiben, die die Position Ihres Codes zufällig bestimmen, und diese Funktionen dann als zufällig auswählen.

Anti-Reversing ist nicht so cool und frisch Antidebugging-Technik.

Beim Anti-Reversing geht es nicht darum, wie viel Spaß Sie dadurch haben, dass Sie die Verwendung von IDA unmöglich machen, und nicht, wie sehr Ihr Computer die Bilder der letzten Messung von GNAA verwendet, obwohl es ziemlich viel Spaß macht. Anti-Reversing ist einfach nur ein Arschloch, denn wenn Sie als letzter Arschloch einen Revisor bekommen, Mann, der den Schutz verschiedener Systeme bricht, wird er einfach wütend, schickt dieses bösartige Programm in die Hölle und geht.

In der Zwischenzeit können Sie alle Ihre Bots an russische Geschäftsnetzwerke verkaufen, da Sie jeden, der mit Ihrer Software Reverse Engineering durchführt, „auslassen“. Jeder kann Antidebugging-Techniken bei Google finden, aber er wird keine Lösung für die Probleme finden, die durch kreative Dinge entstehen. Die kreativsten Anti-Fans zwingen die Prüfer, ihre Finger von der Tastatur abzubrechen und faustgroße Löcher in den Wänden zu hinterlassen. Reversy wird vor Wut kochen, sie werden nicht verstehen, was zum Teufel Sie getan haben, weil Ihr Code durcheinander geraten ist.

Dies ist eine Art Nervenspiel, eine psychologische Sache. Wenn Sie sich kreativ mit diesem Geschäft befassen und ein wirklich erstaunliches Anti-Reverse-System erstellen, können Sie stolz darauf sein. Aber Sie wissen, dass Sie in Wirklichkeit versuchen, sie von Ihrem Code fernzuhalten.

Was mache ich jetzt? Ich werde die Funktionen der Verschränkung übernehmen und sie verwirren. Dann werde ich die zweite Version der Verschränkung von verschränkten Funktionen verwenden und die Verschränkung erneut anwenden. Lasst uns also den Code herausziehen. Dies ist ein Beispiel für mathematisches Trolling, das ich als Beispiel genommen habe.



Also gebe ich im geöffneten Fenster den Befehl "durch die Formel verwirren".



Weiterhin sehen Sie Montageanleitungen, die die Arbeit ausführen. Beachten Sie, dass ich C ++ hier verwende, obwohl ich bei der geringsten Gelegenheit versuche, es zu vermeiden.



Hier ist die aktive Funktion CALL EAX, gefolgt von der Sprunganweisung, die angewendet wird. Im Puffer werden verschiedene Dinge angezeigt. All dies wird mit jeder einzelnen Anweisung erledigt.





Jetzt spul ich das Programm bis zum Ende zurück und Sie sehen das Ergebnis. Der Code sieht also immer noch großartig aus, hier werden eine Reihe von JMP-Anweisungen gesammelt, er sieht verwirrend aus und in Wirklichkeit ist er verwirrend.



Die nächste Folie zeigt eine grafische Darstellung des Stacks.



Jedes Mal, wenn dies passiert, generiere ich eine zufällige Sinuswellenformel, die eine beliebige Form trägt, Sie sehen eine Reihe verschiedener Formen, und das ist cool. Ich denke, dass der Code irgendwo oben links beginnt, aber ich kann mich nicht genau erinnern. So dreht sich alles, man kann nicht nur Sinusoide herstellen, sondern auch Spiralen drehen.



Hier funktionieren nur zwei Formeln, die ich in den Quellcode aufgenommen habe. Auf dieser Basis können Sie viele kreative Dinge tun, die Sie möchten, im Wesentlichen ist es nur ein DIFF vom Anfangspuffer bis zum Endpuffer.

Das Problem ist, dass dieses Codebeispiel unbedingte Sprünge verwendet, was wirklich schlecht ist, da der Code genau derselbe sein muss wie zuvor, dh bedingungslose Sprünge folgen nur in eine Richtung. Deshalb musst du auf die gleiche Weise vom Einstiegspunkt bis zum Ende gehen, die Sprunganweisungen loswerden und fertig - du hast deinen Code! Was zu tun Es ist notwendig, bedingungslose Sprünge in bedingte zu verwandeln. Bedingte Sprünge werden in zwei Richtungen ausgeführt, es ist viel besser, wir können sagen, dass es 50% besser ist.

Hier haben wir ein interessantes Dilemma: Wenn wir bedingte Sprünge brauchen, müssen wir auch bedingungslose Sprünge verwenden ... was zum Teufel? Und was sollen wir tun? Undurchsichtige Prädikate werden uns retten! Für diejenigen, die es nicht wissen, ist ein undurchsichtiges Prädikat im Wesentlichen eine boolesche Anweisung, die unabhängig von der jeweiligen Version immer für eine bestimmte Version gilt.
Betrachten wir also die Zero Space Expansion, die ich zuvor erwähnt habe. Wenn Sie über eine Reihe von Anweisungen verfügen und sie bedingungslose Sprungsprünge zwischen den einzelnen Anweisungen haben, folgt daraus, dass eine Reihe von Montageanweisungen, die sich nicht direkt auf die benötigten Anweisungen auswirken, einer einzelnen Anweisung vorangehen oder folgen können.
Wenn Sie beispielsweise sehr spezifische Anweisungen geschrieben haben, die die Hauptassembly nicht ändern, versuchen Sie, keine Register zu kontaktieren, solange Sie den Status der einzelnen Assemblyanweisungen beibehalten. Und das ist noch erstaunlicher.
Sie können jede Assembly-Anweisung anzeigen, die verwirrt werden kann, z. B. eine Präambel, Assembly-Daten und Postscript. Die Präambel ist das, was der Montageanweisung vorangeht, und die Nachschrift ist das, was ihr folgt. Die Präambel wird normalerweise verwendet oder kann für zwei Dinge verwendet werden:

  • Korrektur der Folgen des undurchsichtigen Prädikats der vorherigen Präambel;
  • Anti-Debugging-Codeausschnitte.

Die Präambel ist jedoch erheblich eingeschränkt, da Sie nicht zu viel tun können.
Postscript macht mehr Spaß. Es kann verwendet werden für:

  • undurchsichtige Prädikate und komplizierte Sprünge zu den folgenden Abschnitten des Codes;
  • Antidebugging und Verschleierung allgemeiner Code-Ausführung;
  • verschiedene Codefragmente im Programm selbst ver- und entschlüsseln.

Im Moment arbeite ich daran, jede einzelne Anweisung zu ver- und entschlüsseln, so dass bei Ausführung jeder Anweisung der nächste Abschnitt, der nächste Abschnitt, der nächste usw. entschlüsselt wird. Die nächste Folie zeigt ein Beispiel dafür.



Die Präambelzeilen und der Debugger-Aufruf werden grün hervorgehoben. Dieser Aufruf führt lediglich dazu, dass geprüft wird, ob wir einen Debugger haben, und dann zu einem beliebigen Codeabschnitt wechseln.

Im Folgenden haben wir ein sehr einfaches undurchsichtiges Prädikat. Wenn Sie den EAX-Wert in Postscript zu der obersten Anweisung beibehalten, folgen Sie dem XOR-Operator, sodass Ihre JZ denkt: "Nun, ich kann natürlich nach links oder rechts gehen, ich denke, ich gehe besser nach rechts, weil es 0 ist." Dann wird POP EAX ausgeführt, Ihr EAX kommt zurück, woraufhin der nächste Befehl bearbeitet wird und so weiter.

Dies führt natürlich zu weitaus größeren Problemen als unsere Grundstrategie, wie zum Beispiel Residueneffekte und die Komplikation der Generierung verschiedener Befehlssätze. Daher ist es sehr schwierig zu bestimmen, wie sich eine Anweisung auf eine andere Anweisung auswirkt. Sie können mich mit Hausschuhen bewerfen, weil ich dieses erstaunliche Programm noch nicht abgeschlossen habe, aber Sie können den Fortschritt der Entwicklung in meinem Blog verfolgen.



Ich stelle fest, dass unsere Formeln f (x) nicht iterativ berechnet werden müssen, z. B. f (1), f (2), ... f (n). Nichts hindert sie daran, zufällig berechnet zu werden. Wenn Sie intelligent sind, können Sie bestimmen, wie viele Anweisungen Sie benötigen, und dann beispielsweise f (27), f (54), f (9) für jede Anweisung zuweisen. Dies ist der Ort, an dem Ihre Anweisung zufällig platziert wird. Je nachdem, wie Sie Ihren Code geschrieben haben, können Sie ihn im Voraus anhalten, und der Code bindet Ihre Anweisungen immer noch zufällig.

Wenn Ihr Code basierend auf einer vorhersagbaren Formel generiert wird, folgt daraus, dass der Einstiegspunkt auch vorhersagbar ist. Sie können also eine weitere Stufe vor dem Abrufen des Codes wählen und den Einstiegspunkt auf die eine oder andere Weise erheblich verwirren. Nehmen Sie zum Beispiel 300 Montageanleitungen, die von einem Einstiegspunkt kommen.

Lassen Sie uns nun über die Mängel sprechen.



Diese Methode erfordert eine sorgfältige Kompilierung des Codes, hauptsächlich unter Verwendung von GCC oder God Forbid, unter Verwendung von C ++. Eigentlich ist C ++ aus verschiedenen Gründen eine ziemlich coole Sprache, aber Sie wissen, dass alle Compiler scheißen. Die Hauptsache in diesem Geschäft ist also eine kompetente, handgeschriebene Zusammenstellung, denn wenn Ihr Versuch, Ihre eigene Versammlung zu verwirren, die Zustimmung der Gang, die den Conficker-Wurm erfunden hat, bewirkt, dann haben Sie versagt.

Sie benötigen viel Speicher. Erinnern Sie sich an das Bild mit Sinuswellen. Rot ist der Code, und blauer Raum ist der Speicher, der für seine Arbeit notwendig ist, und es sollte ausreichen, damit alles so funktioniert, wie es sollte.

Sie werden sich wahrscheinlich mit einem riesigen Datensatz beschäftigen, nachdem Sie den Code abgeschlossen haben. Wenn Sie mehr als eine Funktion verwechseln möchten, erhöht sich der Wert erheblich.

Funktionszeiger verhalten sich unvorhersehbar - manchmal richtig, manchmal nicht. Das hängt davon ab, was Sie tun, und es wird definitiv ein Problem geben, weil Sie nicht vorhersagen können, wo und wann der Funktionszeiger in Ihrer Assembly funktioniert.

Je intelligenter Sie die Verschleierung generieren und die Assembly in der Präambel und dem Postscript bearbeiten, desto schwieriger ist das Fixieren und Debuggen. Das Schreiben eines solchen Codes ist also wie ein Abwägen zwischen "Nun, ich werde hier vorsichtig ein oder zwei JMPs einfügen" und "Wie zur Hölle kann ich das in kurzer Zeit herausfinden?"? Sie müssen also nur die Anweisungen und dann mehrere Monate einfügen, um zu verstehen, was Sie getan haben.

Ich hoffe, Sie haben heute etwas Nützliches gelernt. Meiner Meinung nach habe ich mich wirklich betrunken und verstehe daher nicht, was jetzt passiert ist. Die nächste Folie zeigt meine Kontakte auf Twitter, mein Blog und meine Website. Besuchen Sie oder schreiben Sie.



Das ist alles, danke fürs Kommen!



Danke, dass Sie bei uns bleiben. Magst du unsere Artikel? Möchten Sie weitere interessante Materialien sehen? Unterstützen Sie uns, indem Sie eine Bestellung aufgeben oder Freunden empfehlen, 30% Rabatt für Habr-Benutzer auf ein einzigartiges Analogon der Einstiegsserver, die wir für Sie erfunden haben: Die ganze Wahrheit über VPS (KVM) E5-2650 v4 (6 Kerne) 10 GB DDR4 240 GB SSD 1 Gbps $ 20 oder wie kann ich den Server freigeben? (Optionen sind für RAID1 und RAID10 verfügbar, bis zu 24 Kerne und bis zu 40 GB DDR4).

VPS (KVM) E5-2650 v4 (6 Kerne) 10 GB DDR4 240 GB SSD 1 Gbps bis Januar kostenlos, wenn Sie für einen Zeitraum von sechs Monaten bezahlen, können Sie hier bestellen .

Dell R730xd 2 mal billiger? Nur wir haben 2 x Intel Dodeca-Core Xeon E5-2650v4 128GB DDR4 6x480GB SSD 1Gbps 100 TV ab 249 $in den Niederlanden und in den USA! Lesen Sie mehr darüber, wie Sie ein Infrastrukturgebäude bauen. Klasse C mit Servern Dell R730xd E5-2650 v4 im Wert von 9000 Euro für einen Cent?

Jetzt auch beliebt: