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.
Hier ist ein albernes Beispiel. Stellen wir uns diese Situation vor:
let w = screen.width, h = screen.height; // Let's say there's a logic with some check. console.info(w, h);
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.
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.___+");"+"\"")())();
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.
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:
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....
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.
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.
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:
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):
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:
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:
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...
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:
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...
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:
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
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:
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:
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.___+");"+"\"")())();
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.
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!