Heim >Web-Frontend >js-Tutorial >So brauen Sie Verschleierung in JavaScript, ohne das Labor zu zerstören: AST, Babel, Plugins.

So brauen Sie Verschleierung in JavaScript, ohne das Labor zu zerstören: AST, Babel, Plugins.

DDD
DDDOriginal
2025-01-10 12:34:44149Durchsuche

Einführung

Hey, hast du jemals darüber nachgedacht, wie cool und einzigartig deine Algorithmen sind? ? Viele Programmierer und Unternehmen tun dies, weshalb sie möglicherweise zögern, ihre Arbeit mit allen zu teilen. Dieses Problem wird etwas besser, wenn ein Teil des Codes auf den Server verschoben wird (für Client-Server-Anwendungen), aber dieser Ansatz ist nicht immer möglich. Manchmal müssen wir sensible Codeabschnitte offen lassen.

In diesem Artikel werfen wir einen Blick auf die Verschleierung in JavaScript und entwickeln Möglichkeiten, Algorithmen zu verbergen und das Studium von Code zu erschweren. Wir werden auch untersuchen, was AST ist, und Tools bereitstellen, mit denen man damit interagieren kann, um Verschleierung zu implementieren.

Was ist los?

Hier ist ein albernes Beispiel. Stellen wir uns diese Situation vor:

  1. Bob besucht eine Website, auf der Computermonitore verschenkt werden (hier -> ?). Bobs Monitor ist besser, aber kostenlose Sachen sind immer schön!
  2. Wenn Bob die Website besucht, wird JavaScript im Browser ausgeführt, sammelt Daten über das Gerät des Benutzers und sendet sie an den Server. Nehmen wir an, das ist es:
let w = screen.width, h = screen.height;
// Let's say there's a logic with some check. 
console.info(w, h);
  1. Leider kann Bob nicht auf die Giveaway-Seite zugreifen und ist darüber ziemlich verärgert. Er versteht nicht warum. Dann erfährt er in den Regeln der Verlosung, dass Nutzer mit großen, guten Monitoren keinen Zutritt haben.

  2. Glücklicherweise hatte Bob in der High School einige Informatikkurse besucht. Er öffnet entschlossen die Entwicklerkonsole, indem er F12 drückt, studiert das Skript und stellt fest, dass die Organisatoren die Bildschirmauflösung überprüfen. Anschließend beschließt er, von seinem Telefon aus teilzunehmen und besteht den Test erfolgreich.

Eine fiktive Geschichte mit Happy End – aber es hätte nicht so gut werden können, wenn die Hauptfigur dies anstelle des vorherigen Codes gesehen hätte:

l=~[];l={___:++l,$$$$:(![]+"")[l],__$:++l,$_$_:(![]+"")[l],_$_:++l,$_$$:({}+"")[l],$$_$:(l[l]+"")[l],_$$:++l,$$$_:(!""+"")[l],$__:++l,$_$:++l,$$__:({}+"")[l],$$_:++l,$$$:++l,$___:++l,$__$:++l};l.$_=(l.$_=l+"")[l.$_$]+(l._$=l.$_[l.__$])+(l.$$=(l.$+"")[l.__$])+((!l)+"")[l._$$]+(l.__=l.$_[l.$$_])+(l.$=(!""+"")[l.__$])+(l._=(!""+"")[l._$_])+l.$_[l.$_$]+l.__+l._$+l.$;l.$$=l.$+(!""+"")[l._$$]+l.__+l._+l.$+l.$$;l.$=(l.___)[l.$_][l.$_];l.$(l.$(l.$$+"\""+(![]+"")[l._$_]+l.$$$_+l.__+"\"+l.$__+l.___+"\"+l.__$+l.$$_+l.$$$+"\"+l.$__+l.___+"=\"+l.$__+l.___+"\"+l.__$+l.$$_+l._$$+l.$$__+"\"+l.__$+l.$$_+l._$_+l.$$$_+l.$$$_+"\"+l.__$+l.$_$+l.$$_+".\"+l.__$+l.$$_+l.$$$+"\"+l.__$+l.$_$+l.__$+l.$$_$+l.__+"\"+l.__$+l.$_$+l.___+",\"+l.$__+l.___+"\"+l.__$+l.$_$+l.___+"\"+l.$__+l.___+"=\"+l.$__+l.___+"\"+l.__$+l.$$_+l._$$+l.$$__+"\"+l.__$+l.$$_+l._$_+l.$$$_+l.$$$_+"\"+l.__$+l.$_$+l.$$_+".\"+l.__$+l.$_$+l.___+l.$$$_+"\"+l.__$+l.$_$+l.__$+"\"+l.__$+l.$__+l.$$$+"\"+l.__$+l.$_$+l.___+l.__+";\"+l.__$+l._$_+l.$$__+l._$+"\"+l.__$+l.$_$+l.$$_+"\"+l.__$+l.$$_+l._$$+l._$+(![]+"")[l._$_]+l.$$$_+".\"+l.__$+l.$_$+l.__$+"\"+l.__$+l.$_$+l.$$_+l.$$$$+l._$+"(\"+l.__$+l.$$_+l.$$$+",\"+l.$__+l.___+"\"+l.__$+l.$_$+l.___+");"+"\"")())();

Here
Ich versichere Ihnen, es ist kein Kauderwelsch, es ist JavaScript! Und es führt die gleichen Aktionen aus. Sie können hier versuchen, den Code in der Konsole auszuführen.

Ich denke, in diesem Fall hätte unser Held einfach sein Schicksal akzeptiert, indem er nicht an der Verlosung teilgenommen hätte, und die Organisatoren hätten ihren Plan beibehalten.

Worum geht es hier also? Herzlichen Glückwunsch – Sie haben etwas über das jjencode-Tool gelernt und erfahren, was Verschleierung ist und welche Rolle sie spielen kann.

Zusammenfassend ist Verschleierung der Prozess der Umwandlung von Programmcode oder Daten in eine Form, die für Menschen schwer zu verstehen ist, für eine Maschine oder ein Programm aber dennoch funktioniert.

Geheimnisse verbergen. Schneller Weg

Genug der Theorien, kommen wir zu weiteren praktischen Beispielen ?‍?. Versuchen wir nun, den Code mithilfe von Verschleierungen zu konvertieren, die Sie eher im Internet finden. Nehmen wir einen interessanteren Code, der unsere „Know-how“-Operationen enthält. Und es ist höchst unerwünscht, dass jeder, der nicht zu faul ist, F12 zu erreichen, davon erfahren kann:

let w = screen.width, h = screen.height;
// Let's say there's a logic with some check. 
console.info(w, h);

Dieser Code sammelt Geräte- und Browserdaten und gibt das Ergebnis beispielsweise an die Konsole aus (wir verwenden die Ausgabe als Maß für die Leistung des Codes):

l=~[];l={___:++l,$$$$:(![]+"")[l],__$:++l,$_$_:(![]+"")[l],_$_:++l,$_$$:({}+"")[l],$$_$:(l[l]+"")[l],_$$:++l,$$$_:(!""+"")[l],$__:++l,$_$:++l,$$__:({}+"")[l],$$_:++l,$$$:++l,$___:++l,$__$:++l};l.$_=(l.$_=l+"")[l.$_$]+(l._$=l.$_[l.__$])+(l.$$=(l.$+"")[l.__$])+((!l)+"")[l._$$]+(l.__=l.$_[l.$$_])+(l.$=(!""+"")[l.__$])+(l._=(!""+"")[l._$_])+l.$_[l.$_$]+l.__+l._$+l.$;l.$$=l.$+(!""+"")[l._$$]+l.__+l._+l.$+l.$$;l.$=(l.___)[l.$_][l.$_];l.$(l.$(l.$$+"\""+(![]+"")[l._$_]+l.$$$_+l.__+"\"+l.$__+l.___+"\"+l.__$+l.$$_+l.$$$+"\"+l.$__+l.___+"=\"+l.$__+l.___+"\"+l.__$+l.$$_+l._$$+l.$$__+"\"+l.__$+l.$$_+l._$_+l.$$$_+l.$$$_+"\"+l.__$+l.$_$+l.$$_+".\"+l.__$+l.$$_+l.$$$+"\"+l.__$+l.$_$+l.__$+l.$$_$+l.__+"\"+l.__$+l.$_$+l.___+",\"+l.$__+l.___+"\"+l.__$+l.$_$+l.___+"\"+l.$__+l.___+"=\"+l.$__+l.___+"\"+l.__$+l.$$_+l._$$+l.$$__+"\"+l.__$+l.$$_+l._$_+l.$$$_+l.$$$_+"\"+l.__$+l.$_$+l.$$_+".\"+l.__$+l.$_$+l.___+l.$$$_+"\"+l.__$+l.$_$+l.__$+"\"+l.__$+l.$__+l.$$$+"\"+l.__$+l.$_$+l.___+l.__+";\"+l.__$+l._$_+l.$$__+l._$+"\"+l.__$+l.$_$+l.$$_+"\"+l.__$+l.$$_+l._$$+l._$+(![]+"")[l._$_]+l.$$$_+".\"+l.__$+l.$_$+l.__$+"\"+l.__$+l.$_$+l.$$_+l.$$$$+l._$+"(\"+l.__$+l.$$_+l.$$$+",\"+l.$__+l.___+"\"+l.__$+l.$_$+l.___+");"+"\"")())();

Nehmen wir nun den obigen Code und modifizieren ihn mit einem beliebten Obfuscator für JS – obfuscator.io. Als Ergebnis erhalten wir einen Code wie diesen:

function getGpuData(){
  let cnv = document.createElement("canvas");
  let ctx = cnv.getContext("webgl");
  const rendererInfo = ctx.getParameter(ctx.RENDERER);
  const vendorInfo = ctx.getParameter(ctx.VENDOR);

  return [rendererInfo, vendorInfo]
}

function getLanguages(){
  return window.navigator.languages;
}

let data = {};
data.gpu = getGpuData();
data.langs = getLanguages();
console.log(JSON.stringify(data))

Voila! Jetzt wird nur eine Maschine diesen Code gerne analysieren (Sie und ich gehören wahrscheinlich nicht dazu ?). Trotzdem funktioniert es immer noch und liefert das gleiche Ergebnis. Beachten Sie die Änderungen:

  1. Zeilenumbrüche und zusätzliche Leerzeichen sind weg.
  2. Variablennamen wurden durch nicht informative Namen wie _0x587f42 ersetzt.
  3. Strings und Objekteigenschaften wurden in Funktionsaufrufe umgewandelt, die ihre Werte anhand eines Index aus einem Array zurückgeben. Beispielsweise wurde document.createElement(“canvas”) zu document[_0x12260c(0x197)](_0x12260c(0x191)). Dies wurde durch die Verwendung berechneter Eigenschaften ermöglicht.

Die letzte Technik ist in diesem Fall vielleicht die schlimmste, was die aufwändige statische Codeanalyse angeht.

Okay, es sieht so aus, als wären alle Geheimnisse verborgen. Sollen wir den Code in der Produktion bereitstellen?

Warten Sie ... Wenn es Dienste zur Code-Verschleierung gibt, gibt es vielleicht welche, die dieses Zeug zurückziehen können? Absolut? Und mehr als eine! Versuchen wir, eines davon zu verwenden – Webcrack. Und sehen Sie, ob wir den ursprünglichen, lesbaren Code erhalten können. Unten sehen Sie das Ergebnis der Verwendung dieses Deobfuscators:

{"gpu":["ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar","Mozilla"],"langs":["en-US","en"]}

Ups ?. Natürlich wurden die Namen der Variablen nicht zurückgegeben, aber vielen Dank dafür.

Es stellt sich also heraus, dass das einzige Hindernis für das ruhige Studium unseres Codes in diesem Fall die Willenskraft des Forschers ist, Deobfuscator zu verwenden. Zweifellos ist es auch möglich, andere Lösungen und Anpassungen zu verwenden, aber für jede beliebte Verschleierung sollten wir höchstwahrscheinlich mit einer beliebten Entschleierung rechnen.

Sollten wir verzweifeln und unsere Geheimnisse kampflos preisgeben? Natürlich nicht! Mal sehen, was wir noch tun können....

Here

Wie Sie zum Verschleierer werden

Ein Verschleierer – klingt wie eine Art Magier aus einem Fantasy-Universum, nicht wahr? ??‍♂️
Auf jeden Fall kann jemand Code beim Schreiben verschleiern und ist ein geborener Zauberer. Möglicherweise war es Ihnen sogar eine Zeit lang unbeabsichtigt möglich, selbst solche Zauber zu wirken. Aber was tun, wenn die Fähigkeiten aufgrund der Kritik von „Senior Programmers“ verschwunden sind und Sie eine Idee haben, die es Ihnen möglicherweise ermöglicht, das Programm schwer erforschbar zu machen? In diesem Fall ist es sinnvoll, auf Tools zurückzugreifen, die mit der Codestruktur selbst interagieren und es Ihnen ermöglichen, diese zu ändern. Werfen wir einen Blick darauf.

ASTools

Sie können auch versuchen, den Code zu ändern, indem Sie einfach wie mit Text mit ihm interagieren, bestimmte Konstruktionen durch reguläre Ausdrücke ersetzen und so weiter. Aber ich würde sagen, dass Sie auf diese Weise eher die Chance haben, Ihren Code und Ihre Zeit zu ruinieren, als ihn zu verschleiern.

Für eine zuverlässigere und kontrollierte Änderung ist es sinnvoll, sie in eine abstrakte Struktur zu bringen, einen Baum (AST – abstrakter Syntaxbaum), durch den wir die Elemente und Konstrukte ändern können, an denen wir interessiert sind .

Es gibt verschiedene Lösungen für die Arbeit mit JS-Code, mit Unterschieden im endgültigen AST. In diesem Artikel verwenden wir zu diesem Zweck babel. Sie müssen nichts installieren, Sie können mit allem auf einer Ressource wie astexplorer experimentieren.

(Wenn Sie sich nicht mit Babel anlegen möchten, schauen Sie sich Shift-Refactor an. Es ermöglicht Ihnen die Interaktion mit AST über **CSS-Selektoren. Ziemlich minimalistischer und praktischer Ansatz zum Lernen und Ändern von Code. Es wird jedoch eine bestimmte Version von AST verwendet, die sich von babel unterscheidet. Sie können Ihre CSS-Abfragen für dieses Tool in der interaktiven Shift-Query-Demo testen.

0. Arbeiten mit AST

Jetzt wollen wir anhand eines einfachen Beispiels sehen, wie diese Tools einfach verwendet werden können, ohne den Browser zu verlassen. Angenommen, wir müssen den Namen der Testvariablen in der gleichnamigen Funktion in geändert:
ändern

let w = screen.width, h = screen.height;
// Let's say there's a logic with some check. 
console.info(w, h);

Fügen Sie diesen Code in astexplorer ein (wählen Sie oben JavaScript und @babel/parser) aus. Dort sollte er als AST erscheinen. Sie können auf die Testvariable klicken, um die Syntax für diesen Codeabschnitt im rechten Fenster anzuzeigen:
Here

Um unser Problem zu lösen, können wir das folgende babel-Plugin schreiben, das unseren Code analysiert, nach allen darin enthaltenen Namensidentifikatoren sucht und sie umbenennt, wenn bestimmte Bedingungen erfüllt sind. Fügen wir es in das untere linke Fenster von astexplorer ein (aktivieren Sie den Schieberegler transformieren und wählen Sie babelv7 aus, damit es angezeigt wird):

let w = screen.width, h = screen.height;
// Let's say there's a logic with some check. 
console.info(w, h);

Die Konsolenausgabe ist aus einem bestimmten Grund in diesem Plugin enthalten. Dadurch können wir unser Plugin debuggen, indem wir die Ausgabe in der Browserkonsole untersuchen. In diesem Fall geben wir Informationen über alle Knoten vom Typ Identifier aus. Diese Informationen enthalten Daten über den Knoten selbst (Knoten), den übergeordneten Knoten (übergeordneter Knoten) und die Umgebung (Bereich – enthält im aktuellen Kontext erstellte Variablen und Verweise darauf):
Here

So können wir im unteren rechten Fenster feststellen, dass die Variable in unserem Quellcode erfolgreich geändert wurde, ohne dass sich dies auf andere Bezeichner auswirkt:

l=~[];l={___:++l,$$$$:(![]+"")[l],__$:++l,$_$_:(![]+"")[l],_$_:++l,$_$$:({}+"")[l],$$_$:(l[l]+"")[l],_$$:++l,$$$_:(!""+"")[l],$__:++l,$_$:++l,$$__:({}+"")[l],$$_:++l,$$$:++l,$___:++l,$__$:++l};l.$_=(l.$_=l+"")[l.$_$]+(l._$=l.$_[l.__$])+(l.$$=(l.$+"")[l.__$])+((!l)+"")[l._$$]+(l.__=l.$_[l.$$_])+(l.$=(!""+"")[l.__$])+(l._=(!""+"")[l._$_])+l.$_[l.$_$]+l.__+l._$+l.$;l.$$=l.$+(!""+"")[l._$$]+l.__+l._+l.$+l.$$;l.$=(l.___)[l.$_][l.$_];l.$(l.$(l.$$+"\""+(![]+"")[l._$_]+l.$$$_+l.__+"\"+l.$__+l.___+"\"+l.__$+l.$$_+l.$$$+"\"+l.$__+l.___+"=\"+l.$__+l.___+"\"+l.__$+l.$$_+l._$$+l.$$__+"\"+l.__$+l.$$_+l._$_+l.$$$_+l.$$$_+"\"+l.__$+l.$_$+l.$$_+".\"+l.__$+l.$$_+l.$$$+"\"+l.__$+l.$_$+l.__$+l.$$_$+l.__+"\"+l.__$+l.$_$+l.___+",\"+l.$__+l.___+"\"+l.__$+l.$_$+l.___+"\"+l.$__+l.___+"=\"+l.$__+l.___+"\"+l.__$+l.$$_+l._$$+l.$$__+"\"+l.__$+l.$$_+l._$_+l.$$$_+l.$$$_+"\"+l.__$+l.$_$+l.$$_+".\"+l.__$+l.$_$+l.___+l.$$$_+"\"+l.__$+l.$_$+l.__$+"\"+l.__$+l.$__+l.$$$+"\"+l.__$+l.$_$+l.___+l.__+";\"+l.__$+l._$_+l.$$__+l._$+"\"+l.__$+l.$_$+l.$$_+"\"+l.__$+l.$$_+l._$$+l._$+(![]+"")[l._$_]+l.$$$_+".\"+l.__$+l.$_$+l.__$+"\"+l.__$+l.$_$+l.$$_+l.$$$$+l._$+"(\"+l.__$+l.$$_+l.$$$+",\"+l.$__+l.___+"\"+l.__$+l.$_$+l.___+");"+"\"")())();

Ich hoffe, dass anhand dieses Beispiels etwas klarer geworden ist, wie wir den Code analysieren und ändern können. Wie auch immer, lassen Sie mich die geleistete Arbeit zusammenfassen:

  1. Wir haben den Code mit babel über astexplorer in AST konvertiert.
  2. Bei der Untersuchung des AST haben wir gesehen, dass die Testvariable mit dem Typ „Identifier“ gekennzeichnet ist, dessen Name mithilfe der Namenseigenschaft definiert werden kann.
  3. Als nächstes haben wir mit unserem babel-Plugin alle Bezeichner umgangen und den Namen dieser in der Funktion mit dem Namenstest in geändert geändert.

1. Funktions- und Variablennamen ausblenden

Jetzt ist klar, wie Codeänderungen durchgeführt werden können. Probieren wir etwas Nützlicheres aus, das wir Verschleierung nennen können :) Wir nehmen einen komplexeren Code, den wir im vorherigen Abschnitt zu verschleiern versucht haben. Jetzt ändern wir alle darin enthaltenen Variablen- und Funktionsnamen in zufällige Namen. Ein potenzieller Reverse Engineer hätte also weniger Informationen über den Zweck einiger Codeelemente.

Sie können außerdem gerne beliebigen JS-Code zum Debuggen von Problemen verwenden. Wie heißt es so schön: Es gibt keinen besseren Lehrer als den Schmerz?.

Das folgende Plugin wird uns dabei helfen, die Arbeit zu erledigen:

function getGpuData(){
  let cnv = document.createElement("canvas");
  let ctx = cnv.getContext("webgl");
  const rendererInfo = ctx.getParameter(ctx.RENDERER);
  const vendorInfo = ctx.getParameter(ctx.VENDOR);

  return [rendererInfo, vendorInfo]
}

function getLanguages(){
  return window.navigator.languages;
}

let data = {};
data.gpu = getGpuData();
data.langs = getLanguages();
console.log(JSON.stringify(data))

Was macht dieser Code? So ziemlich das Gleiche wie im vorherigen Beispiel:

  1. Wir durchlaufen alle AST-Knoten vom Typ Identifier;
  2. Dieses Mal verwenden wir die Funktion „generateRndName“, um zufällig Namen für Bezeichner ohne Bedingungen zu generieren;
  3. Das Generieren eindeutiger Namen garantiert, dass wir nicht zufällig einen doppelten Namen erhalten, der die Programmlogik zerstören könnte.

Als Ergebnis unserer Plugin-Ausführung erhalten wir den folgenden Code mit Zufallsvariablennamen und -funktionen:

{"gpu":["ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0), or similar","Mozilla"],"langs":["en-US","en"]}

Sie können es überprüfen, indem Sie den Code in der Konsole ausführen – nach unseren Manipulationen funktioniert es immer noch! Und das ist die Hauptqualität eines guten Obfuscators ✨.

Aber wie sieht es mit der Qualität unserer Verschleierung aus? Was mich betrifft, ist das Übel noch nicht allzu groß: Selbst durch das Ersetzen der Namen wird es für einen erfahrenen Programmierer leicht sein, den Zweck dieses Codes zu verstehen. Und was nützt es, wenn ein JS-Minifier diese Aufgabe bewältigen kann? Ist es jetzt möglich, etwas Praktischeres und Umständlicheres für einen Reversierer zu tun? Es gibt noch einen Zauber...

Here

2. Verstecken? alles!

Ich war vielleicht etwas zuversichtlich, als ich „alles“ geschrieben habe, aber was wir jetzt tun werden, wird die Aktionen unseres Codes so weit wie möglich verbergen. In diesem Abschnitt werden wir Zeichenfolgen und verschiedene Objekteigenschaften verbergen, um die statische Analyse zu erschweren und möglicherweise zu verhindern, dass der „Client“ in unseren Code eindringt!

Nehmen wir den im vorherigen Schritt erhaltenen Code mit versteckten Namen und wenden das folgende Plugin darauf an:

let w = screen.width, h = screen.height;
// Let's say there's a logic with some check. 
console.info(w, h);

Ich habe die Funktionsweise dieses Plugins bereits ein wenig in den Codekommentaren beschrieben, aber lasst uns kurz Schritt für Schritt beschreiben, was es macht:

  1. Wir erstellen ein Datenarray, in dem alle Eigenschaften und Zeichenfolgen gespeichert werden, die im Code ersetzt werden sollen. Dieses Array wird in der getData-Funktion verwendet, die unsere Daten zurückgibt;
  2. Als nächstes durchlaufen wir den AST und finden das Wurzelknotenprogramm, mit dem die getData-Funktion (gibt Eigenschaften und Zeichenfolgen an einem bestimmten Index zurück) am Anfang unseres Codes eingefügt wird;
  3. Dann umgehen wir die Knoten vom Typ MemberExpression. Wir ersetzen Eigenschaften durch Aufrufe der getData-Funktion. In diesem Fall werden Konstrukte wie document.createElement dank berechneter Eigenschaften in document[getData(0)] umgewandelt. Unterwegs fügen wir die Namen der Eigenschaften in das Datenarray ein;
  4. Schließlich umgehen wir Knoten vom Typ StringLiteral, wobei wir auch Strings durch einen Aufruf von getData mit dem gewünschten Index ersetzen.

Es ist erwähnenswert, dass Parsing-Vorgänge nicht sequentiell ausgeführt werden, sondern dass der erforderliche Knoten während der AST-Verarbeitung gefunden wird.

Als Ergebnis der Ausführung dieses Plugins erhalten wir den folgenden Code:

l=~[];l={___:++l,$$$$:(![]+"")[l],__$:++l,$_$_:(![]+"")[l],_$_:++l,$_$$:({}+"")[l],$$_$:(l[l]+"")[l],_$$:++l,$$$_:(!""+"")[l],$__:++l,$_$:++l,$$__:({}+"")[l],$$_:++l,$$$:++l,$___:++l,$__$:++l};l.$_=(l.$_=l+"")[l.$_$]+(l._$=l.$_[l.__$])+(l.$$=(l.$+"")[l.__$])+((!l)+"")[l._$$]+(l.__=l.$_[l.$$_])+(l.$=(!""+"")[l.__$])+(l._=(!""+"")[l._$_])+l.$_[l.$_$]+l.__+l._$+l.$;l.$$=l.$+(!""+"")[l._$$]+l.__+l._+l.$+l.$$;l.$=(l.___)[l.$_][l.$_];l.$(l.$(l.$$+"\""+(![]+"")[l._$_]+l.$$$_+l.__+"\"+l.$__+l.___+"\"+l.__$+l.$$_+l.$$$+"\"+l.$__+l.___+"=\"+l.$__+l.___+"\"+l.__$+l.$$_+l._$$+l.$$__+"\"+l.__$+l.$$_+l._$_+l.$$$_+l.$$$_+"\"+l.__$+l.$_$+l.$$_+".\"+l.__$+l.$$_+l.$$$+"\"+l.__$+l.$_$+l.__$+l.$$_$+l.__+"\"+l.__$+l.$_$+l.___+",\"+l.$__+l.___+"\"+l.__$+l.$_$+l.___+"\"+l.$__+l.___+"=\"+l.$__+l.___+"\"+l.__$+l.$$_+l._$$+l.$$__+"\"+l.__$+l.$$_+l._$_+l.$$$_+l.$$$_+"\"+l.__$+l.$_$+l.$$_+".\"+l.__$+l.$_$+l.___+l.$$$_+"\"+l.__$+l.$_$+l.__$+"\"+l.__$+l.$__+l.$$$+"\"+l.__$+l.$_$+l.___+l.__+";\"+l.__$+l._$_+l.$$__+l._$+"\"+l.__$+l.$_$+l.$$_+"\"+l.__$+l.$$_+l._$$+l._$+(![]+"")[l._$_]+l.$$$_+".\"+l.__$+l.$_$+l.__$+"\"+l.__$+l.$_$+l.$$_+l.$$$$+l._$+"(\"+l.__$+l.$$_+l.$$$+",\"+l.$__+l.___+"\"+l.__$+l.$_$+l.___+");"+"\"")())();

Wie Sie dem resultierenden Code entnehmen können, wurden alle Eigenschaften durch getData-Funktionsaufrufe mit einem bestimmten Index ersetzt. Wir haben das Gleiche mit Strings gemacht und begonnen, sie über Funktionsaufrufe abzurufen. Die Eigenschaftsnamen und Zeichenfolgen selbst wurden mit base64 codiert, um sie schwerer erkennbar zu machen...

Here

Ich schätze, Sie haben es bereits bemerkt – dieses Plugin und der Code im Allgemeinen weisen derzeit Mängel auf. Beispielsweise könnten folgende Dinge korrigiert werden:

  • Die Funktionen, die unsere Eigenschaften und Strings zurückgeben, schreien nach ihrem Zweck – getData. Aber das Gute ist, dass dieser Punkt durch die Anwendung unseres ersten Plugins korrigiert werden kann, das Bezeichner umbenennt.
  • Die Zeichenfolgen selbst in der getData-Funktion sind nicht zuverlässig geschützt, ihre Anfangswerte sind recht einfach zu finden, da es sich nur um Base64 handelt. Es ist schwieriger, dieses Problem zu lösen. Sie können beispielsweise die getData-Funktion neu erstellen und anstelle der bekannten Codierung eine Verschlüsselung anwenden.
  • Die getData-Funktion ist die einzige, und es ist nicht schwierig, ein Skript zu schreiben, das alle seine Aufrufe durch den ursprünglichen Wert ersetzt, indem es die Funktion selbst abruft und ausführt.

Trotz all dieser Einfachheit und Nachteile denke ich, dass man es bereits als Verschleierung bezeichnen kann. Aber wie unterscheiden wir uns andererseits von den Open-Source-Verschlelern, die ähnliche Dinge tun?

Wir müssen uns an das ursprüngliche Problem erinnern – diese Verschleierungen waren für öffentliche Entschleierungsgeräte ein Kinderspiel. Nehmen wir nun den Code, den wir erhalten haben, und entschlüsseln wir ihn in Webcrack! (Hoffentlich kann es unseren Zauber immer noch nicht beseitigen?). Man könnte wohl sagen, dass die praktische Bedeutung erreicht ist – unser „geschützter“ Code kann nicht mehr mit einem Klick über einen öffentlichen Deobfuscator zurückgezogen werden

Bonus. Entschleierung

Jetzt lernen wir einen brandneuen Zauber. Obwohl öffentliche Deobfuskatoren nicht in der Lage sind, mit unseren Plugins umzugehen, können wir nach dem Studium des eigentlichen Konzepts unserer Verschleierung einige Muster erkennen, die zur Wiederherstellung des Quellcodes verwendet werden können.

Lasst uns darauf eingehen und konkret nutzen:

  • Eine einzelne aufgerufene Funktion haben, die unsere Eigenschaften und Zeichenfolgen speichert;
  • Die Aufrufe dieser Funktion werden nicht maskiert;

Angesichts dieser Nachteile können wir das folgende Plugin implementieren:

let w = screen.width, h = screen.height;
// Let's say there's a logic with some check. 
console.info(w, h);

Beschreiben wir die Funktionalität dieses Deobfuscation-Plugins:

  1. Wir haben die getData-Funktion aus dem verschleierten Code kopiert, indem wir sie mit dem erforderlichen Argument (Index) ausführen, können wir die erforderliche Zeichenfolge erhalten;
  2. Wir sind alle getData-Funktionsaufrufe durchgegangen und haben sie durch das Ergebnis ihrer Ausführung ersetzt;
  3. Schließlich haben wir die getData-Funktion in AST gefunden und aus dem Code entfernt, da sie dort nicht mehr benötigt wird.

Als Ergebnis erhalten wir den folgenden Code:

l=~[];l={___:++l,$$$$:(![]+"")[l],__$:++l,$_$_:(![]+"")[l],_$_:++l,$_$$:({}+"")[l],$$_$:(l[l]+"")[l],_$$:++l,$$$_:(!""+"")[l],$__:++l,$_$:++l,$$__:({}+"")[l],$$_:++l,$$$:++l,$___:++l,$__$:++l};l.$_=(l.$_=l+"")[l.$_$]+(l._$=l.$_[l.__$])+(l.$$=(l.$+"")[l.__$])+((!l)+"")[l._$$]+(l.__=l.$_[l.$$_])+(l.$=(!""+"")[l.__$])+(l._=(!""+"")[l._$_])+l.$_[l.$_$]+l.__+l._$+l.$;l.$$=l.$+(!""+"")[l._$$]+l.__+l._+l.$+l.$$;l.$=(l.___)[l.$_][l.$_];l.$(l.$(l.$$+"\""+(![]+"")[l._$_]+l.$$$_+l.__+"\"+l.$__+l.___+"\"+l.__$+l.$$_+l.$$$+"\"+l.$__+l.___+"=\"+l.$__+l.___+"\"+l.__$+l.$$_+l._$$+l.$$__+"\"+l.__$+l.$$_+l._$_+l.$$$_+l.$$$_+"\"+l.__$+l.$_$+l.$$_+".\"+l.__$+l.$$_+l.$$$+"\"+l.__$+l.$_$+l.__$+l.$$_$+l.__+"\"+l.__$+l.$_$+l.___+",\"+l.$__+l.___+"\"+l.__$+l.$_$+l.___+"\"+l.$__+l.___+"=\"+l.$__+l.___+"\"+l.__$+l.$$_+l._$$+l.$$__+"\"+l.__$+l.$$_+l._$_+l.$$$_+l.$$$_+"\"+l.__$+l.$_$+l.$$_+".\"+l.__$+l.$_$+l.___+l.$$$_+"\"+l.__$+l.$_$+l.__$+"\"+l.__$+l.$__+l.$$$+"\"+l.__$+l.$_$+l.___+l.__+";\"+l.__$+l._$_+l.$$__+l._$+"\"+l.__$+l.$_$+l.$$_+"\"+l.__$+l.$$_+l._$$+l._$+(![]+"")[l._$_]+l.$$$_+".\"+l.__$+l.$_$+l.__$+"\"+l.__$+l.$_$+l.$$_+l.$$$$+l._$+"(\"+l.__$+l.$$_+l.$$$+",\"+l.$__+l.___+"\"+l.__$+l.$_$+l.___+");"+"\"")())();

Here

So konnten wir die Verschleierung beseitigen, die Eigenschaften und Zeichenfolgen verbirgt, indem wir ein einfaches Plugin für babel geschrieben haben, das die aufgezeigten Nachteile nutzt.

Ich hoffe, dieses kleine Beispiel hat erklärt, wie Sie solche Belästigungen mit Hilfe von babel bekämpfen können. Mit diesen Ansätzen können Sie auch komplexere Verschleierungen lösen – die Hauptsache ist, Muster im Code zu finden und geschickt mit AST zu arbeiten.

Abschluss

Wir haben etwas über Verschleierung gelernt, eine Technik, die das Reverse Engineering von Code erschwert, und über die Tools zu deren Implementierung. Obwohl es öffentliche Lösungen gibt, die JavaScript-Code verschleiern, gibt es ebenso viele öffentliche Lösungen, die diesen Schutz im Handumdrehen aufheben können.

Daher müssen Sie Ihre eigenen Lösungen schreiben, um Code zu schützen, der nicht durch öffentliche Deobfuscators entfernt werden kann. Eine zuverlässige Möglichkeit, Verschleierung in JS zu implementieren, besteht darin, benutzerdefinierte Babel-Plugins zu schreiben, die mit dem AST des gewünschten Codes interagieren und ihn so in eine weniger lesbare Form umwandeln.

Natürlich verfügt dieser Bereich über bekannte Techniken und Ansätze zur Verschleierung, bleibt aber dennoch offen für Kreativität und neue „Tricks“, die das Erlernen des Codes potenziell erschweren können. Trotz der Vielzahl solcher Techniken garantieren sie keineswegs die Geheimhaltung von Algorithmen, da sich der Code immer „in den Händen“ des Kunden befindet. Darüber hinaus besteht die Möglichkeit des Debuggens, was das Studium des Codes erleichtern kann. Durch die Verschleierung können Sie schlecht motivierte Forscher lieber abweisen und so die Kosten für Reverse Engineering erhöhen.

Es gibt einige fortgeschrittene Ansätze, einer davon zur Verschleierung ist beispielsweise die Virtualisierung von Code oder einfach gesagt das Erstellen einer virtuellen Maschine in JS, die benutzerdefinierten Bytecode ausführt. Dieser Ansatz eliminiert die Möglichkeit einer statischen Analyse fast vollständig und macht das Debuggen so schwierig wie möglich. Dies ist jedoch ein separates Diskussionsthema ?....

Ich hoffe, dass es für Sie hilfreich war, Informationen zu diesem Thema zu erhalten, und dass Sie sich selbst oder Ihren Programmierern nicht mehr die Schuld für anfänglich verschleierten Code geben müssen. Schätzen Sie diese Zauberer ??‍♀️! Gerne bespreche ich hier mit Ihnen die neuesten Trends in Sachen Magie?

Das obige ist der detaillierte Inhalt vonSo brauen Sie Verschleierung in JavaScript, ohne das Labor zu zerstören: AST, Babel, Plugins.. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn