65 votes

Comment fonctionne ce code JavaScript magique ?

Il s'agit d'un petit morceau de code JavaScript qui alerte "Hello world" :

=/´~//*´*/['_'];o=()=_=3;c=()=()-();()=()=(o^_^o)/(o^_^o);()={:'_',:((==3)+'_')[],:(+'_')[o^_^o-()],:((==3)+'_')[]};()[]=((==3)+'_')[c^_^o];()['c']=(()+'_')[()+()-()];()['o']=(()+'_')[];(o)=()['c']+()['o']+(+'_')[]+((==3)+'_')[]+(()+'_')[()+()]+((==3)+'_')[]+((==3)+'_')[()-()]+()['c']+(()+'_')[()+()]+()['o']+((==3)+'_')[];()['_']=(o^_^o)[o][o];()=((==3)+'_')[]+().+(()+'_')[()+()]+((==3)+'_')[o^_^o-]+((==3)+'_')[]+(+'_')[];()+=();()[]='\\';().=(+)[o^_^o-()];(oo)=(+'_')[c^_^o];()[o]='\"';()['_'](()['_'](+()[o]+()[]+()+()+()+()[]+()+(()+())+()+()[]+()+()+(()+())+()[]+()+((o^_^o)+(o^_^o))+((o^_^o)-())+()[]+()+((o^_^o)+(o^_^o))+()+()[]+(()+())+(c^_^o)+()[]+()+((o^_^o)-())+()[]+()+()+(c^_^o)+()[]+()+()+(()+())+()[]+()+(()+())+()+()[]+()+(()+())+()+()[]+()+(()+())+(()+(o^_^o))+()[]+()+(c^_^o)+()[]+()+((o^_^o)-())+(()+(o^_^o))+()[]+()+(()+())+(()+(o^_^o))+()[]+()+((o^_^o)+(o^_^o))+((o^_^o)-())+()[]+()+(()+())+()+()[]+()+()+()+()[]+()+((o^_^o)-())+()[]+(()+())+()+()[o])())('_');

Une version qui a de l'allure :

 = /´~//*´*/['_'];
o = () = _ = 3;
c = () = () - ();
() = () = (o^_^o)/(o^_^o);
() = {
  :  '_',
  : ((==3)+'_')[],
  : (+'_')[o^_^o-()],
  : ((==3)+'_')[]
};
()[] = ((==3)+'_')[c^_^o];
()['c'] = (()+'_')[()+()-()];
()['o'] = (()+'_')[];
(o)=()['c'] + ()['o'] + ( + '_')[] + ((==3) + '_')[] + (() + '_')[() + ()] + ((==3) + '_')[] + ((==3) + '_')[() - ()] + ()['c'] + (() + '_')[() + ()] + ()['o'] + ((==3) + '_')[];
()['_'] = (o^_^o)[o][o];
() = ((==3) + '_')[] + (). + (() + '_')[() + ()] + ((==3) + '_')[o^_^o-] + ((==3) + '_')[] + (+'_')[];
() += ();
()[] = '\\';
(). = (+)[o^_^o-()];
(oo) = (+'_')[c^_^o];
()[o] = '\"';
()['_'](()['_'](+()[o]+()[]+()+()+()+()[]+()+(()+())+()+()[]+()+()+(()+())+()[]+()+((o^_^o)+(o^_^o))+((o^_^o)-())+()[]+()+((o^_^o)+(o^_^o))+()+()[]+(()+())+(c^_^o)+()[]+()+((o^_^o)-())+()[]+()+()+(c^_^o)+()[]+()+()+(()+())+()[]+()+(()+())+()+()[]+()+(()+())+()+()[]+()+(()+())+(()+(o^_^o))+()[]+()+(c^_^o)+()[]+()+((o^_^o)-())+(()+(o^_^o))+()[]+()+(()+())+(()+(o^_^o))+()[]+()+((o^_^o)+(o^_^o))+((o^_^o)-())+()[]+()+(()+())+()+()[]+()+()+()+()[]+()+((o^_^o)-())+()[]+(()+())+()+()[o])())('_');

JSFiddle

Elle est tirée d'ici : https://codegolf.stackexchange.com/questions/23975/obfuscation-challenge/24041#24041

Comment cela fonctionne-t-il ? Je ne vois même pas le alert dans ce code.

13 votes

Il y a une brève explication dans le troisième commentaire à codegolf.stackexchange.com/questions/307/obfuscated-hello-world/

1 votes

@NPE oui, j'ai lu cela, mais l'auteur ne donne qu'un petit indice. Je n'ai toujours aucune idée de comment cela fonctionne...

1 votes

La réponse à laquelle vous avez renvoyé contient un lien supplémentaire vers la source originale de la réponse. Dans les commentaires qui suivent, une explication est donnée - il s'agit d'utiliser RegEx parmi d'autres outils. Par ailleurs : votre "belle version" est incorrecte - j'ai repéré ='\"'; dans la dernière ligne, il peut y avoir d'autres erreurs.

112voto

Gumbo Points 279147

Avant de regarder le code de plus près, il faut savoir que depuis JavaScript 1.5 identifiants peuvent contenir non seulement des caractères ASCII, mais aussi des caractères Unicode.

Dans ce cas, beaucoup de ces séquences amusantes ne sont que des identifiants. Après avoir remplacé ces identificateurs par des identificateurs plus simples et supprimé les commentaires et parenthèses inutiles, le code se présente comme suit :

a = /´~/['_'];
o = b = _ = 3;
c = d = b-b;
e = d = o^_^o/o^_^o;
e = {
  d: '_',
  a: ((a==3)+'_')[d],
  h: (a+'_')[o^_^o-d],
  i: ((b==3)+'_')[b]
};
e[d]   = ((a==3)+'_')[c^_^o];
e['c'] = (e+'_')[b+b-d];
e['o'] = (e+'_')[d];
f      = e['c']+e['o']+(a+'_')[d]+((a==3)+'_')[b]+(e+'_')[b+b]+((b==3)+'_')[d]+((b==3)+'_')[b-d]+e['c']+(e+'_')[b+b]+e['o']+((b==3)+'_')[d];
e['_'] = (o^_^o)[f][f];
g      = ((b==3)+'_')[d]+e.i+(e+'_')[b+b]+((b==3)+'_')[o^_^o-d]+((b==3)+'_')[d]+(a+'_')[d];
b      += d;
e[g]   = '\\';
e.j    = (e+b)[o^_^o-d];
obo    = (a+'_')[c^_^o];
e[f]   = '\"';
e['_'](e['_'](g+e[f]+e[g]+d+b+d+e[g]+d+(b+d)+b+e[g]+d+b+(b+d)+e[g]+d+((o^_^o)+(o^_^o))+((o^_^o)-d)+e[g]+d+((o^_^o)+(o^_^o))+b+e[g]+(b+d)+(c^_^o)+e[g]+b+((o^_^o)-d)+e[g]+d+d+(c^_^o)+e[g]+d+b+(b+d)+e[g]+d+(b+d)+b+e[g]+d+(b+d)+b+e[g]+d+(b+d)+(b+(o^_^o))+e[g]+b+(c^_^o)+e[g]+d+((o^_^o)-d)+(b+(o^_^o))+e[g]+d+(b+d)+(b+(o^_^o))+e[g]+d+((o^_^o)+(o^_^o))+((o^_^o)-d)+e[g]+d+(b+d)+b+e[g]+d+b+b+e[g]+b+((o^_^o)-d)+e[g]+(b+d)+d+e[f])(d))('_');

Nous sommes maintenant en mesure d'évaluer chaque déclaration à la fois :

  • a = /´~/['_'] s'évalue à a = undefined
  • o = b = _ = 3 attribue o , b y _ le nombre entier 3
  • c = d = b-b attribue c y d le nombre entier 0
  • e = d = o^_^o/o^_^o attribue e y d le nombre entier 1 ( o^_^o s'évalue à 3 XOR 3 XOR 3, ce qui donne 3)
  • e = { d: '_', a: ((a==3)+'_')[d], h: (a+'_')[o^_^o-d], i: ((b==3)+'_')[b] } attribue e l'objet { d: '_', a: 'a', h: 'd', i: 'e' }
  • e[d] = ((a==3)+'_')[c^_^o] attribue e[1] la chaîne 'f'
  • e['c'] = (e+'_')[b+b-d] attribue e['c'] la chaîne 'c'
  • e['o'] = (e+'_')[d] attribue e['o'] la chaîne 'o'

Il ne s'agit que de l'installation et les variables suivantes sont définies :

a = undefined
b = 3
c = 0
d = 1
e = {
    1: "f",
    a: "a",
    c: "c",
    d: "_",
    h: "d",
    i: "e",
    o: "o"
}

La déclaration suivante est la première à construire quelque chose :

f = e['c'] +             // => "c"
    e['o'] +             // => "o"
    (a+'_')[d] +         // => "undefined_"[1] = "n"
    ((a==3)+'_')[b] +    // => "false_"[3]     = "s"
    (e+'_')[b+b] +       // => "object_"[6]    = "t"
    ((b==3)+'_')[d] +    // => "true_"[1]      = "r"
    ((b==3)+'_')[b-d] +  // => "true_"[2]      = "s"
    e['c'] +             // => "c"
    (e+'_')[b+b] +       // => "object_"[6]    = "t"
    e['o'] +             // => "o"
    ((b==3)+'_')[d];     // => "true"[1]       = "r"

Donc f = "constructor" . Dans la déclaration suivante, cette "constructor" est utilisé pour récupérer une fonction :

e['_'] = (o^_^o)[f][f]

Cela équivaut à (3).constructor.constructor ce qui permet d'obtenir l'équation fonction Function , donc :

e['_'] = Function

Le présent Function est particulière car elle permet de construire des fonctions de manière dynamique en lui passant le code du corps de la fonction en paramètre :

f = Function("alert(1)")
// equivalent to
f = function() { alert(1) }

Je vais sauter les quelques instructions suivantes et me contenter d'écrire les variables et les valeurs qui en résultent :

a = undefined
b = 4
c = 0
d = 1
e = {
    1: "f",
    _: Function,
    a: "a",
    c: "c",
    constructor: "\"",
    d: "_",
    h: "d",
    i: "e",
    j: "b",
    o: "o",
    return: "\\"
}
f = "constructor"
obo = "u"

La dernière déclaration fait le travail final :

e['_'](e['_'](g+e[f]+e[g]+d+b+d+e[g]+d+(b+d)+b+e[g]+d+b+(b+d)+e[g]+d+((o^_^o)+(o^_^o))+((o^_^o)-d)+e[g]+d+((o^_^o)+(o^_^o))+b+e[g]+(b+d)+(c^_^o)+e[g]+b+((o^_^o)-d)+e[g]+d+d+(c^_^o)+e[g]+d+b+(b+d)+e[g]+d+(b+d)+b+e[g]+d+(b+d)+b+e[g]+d+(b+d)+(b+(o^_^o))+e[g]+b+(c^_^o)+e[g]+d+((o^_^o)-d)+(b+(o^_^o))+e[g]+d+(b+d)+(b+(o^_^o))+e[g]+d+((o^_^o)+(o^_^o))+((o^_^o)-d)+e[g]+d+(b+d)+b+e[g]+d+b+b+e[g]+b+((o^_^o)-d)+e[g]+(b+d)+d+e[f])(d))('_');

Cela équivaut à :

Function(Function( … )(1))('_')

L'expression longue construit la chaîne suivante :

return"\141\154\145\162\164\50\42\110\145\154\154\157\40\127\157\162\154\144\42\51"

La chaîne échappée est évaluée :

alert("Hello World")

Le présent return est transmis à Function ce qui crée une fonction anonyme comme :

function anonymous() {
    return"\141\154\145\162\164\50\42\110\145\154\154\157\40\127\157\162\154\144\42\51";
}

Ce qui, nous le savons, équivaut à :

function anonymous() {
    return"alert(\"Hello World\")";
}

Cette fonction est ensuite exécutée avec 1 en tant que paramètre, ce qui renvoie la chaîne résultante :

alert("Hello World")

Elle est ensuite transmise à Function ce qui crée une nouvelle fonction anonyme :

function anonymous() {
    alert("Hello World");
}

Enfin, cette fonction est également invoquée avec '_' comme paramètre.

2 votes

Merci, j'attendais cette réponse. Le gars qui a écrit ce truc est tout simplement brillant, j'ai appris beaucoup de choses grâce à cette réponse et son blog ici .

1 votes

"JavaScript 1.5" n'existe pas vraiment. Si vous voulez citer une spécification, vous devriez consulter la spécification ES3 ou ES5. Excellente réponse, d'ailleurs.

16voto

sabof Points 4628

Il y a beaucoup de choses ici. Les parenthèses autour des variables ne sont pas fonctionnelles.

En fait, il construit cette chaîne :

return"\141\154\145\162\164\50\42\110\145\154\154\157\40\127\157\162\154\144\42\51"

qui est une version échappée de

return "alert(\"Hello World\")"

Et c'est finalement ce qu'il fait :

Function(Function('return "alert(\\"Hello World\\")"')())()

Le double Function semble être une chose arbitraire, mais ce n'est pas le cas. Function() interprète les barres obliques inverses de la chaîne comme des caractères d'échappement. Ainsi, le premier appel décode et le second exécute.

Function("return '\\110\\145\\154\\154\\157'")()
// => "Hello"

Voici le même code, mieux formaté et avec des noms de variables "normaux" ;

var1=/´~//*´*/['_'];
three=(threeThenFour)=_=3;
c=(one)=(threeThenFour)-(threeThenFour);
(anObject)=(one)=(three)/(three);
(anObject)={
  one:'_',
  var1:((var1==3)+'_')[one],
  var2:(var1+'_')[three-(one)],
  var4:((threeThenFour==3)+'_')[threeThenFour]
};
(anObject)[one]=((var1==3)+'_')[c ^ _ ^ three];
(anObject)['c']=((anObject)+'_')[(threeThenFour)+(threeThenFour)-(one)];
(anObject)['three']=((anObject)+'_')[one];
(theConstructor)=(anObject)['c']+
  (anObject)['three']+
  (var1+'_')[one]+
  ((var1==3)+'_')[threeThenFour]+
  ((anObject)+'_')[(threeThenFour)+(threeThenFour)]+
  ((threeThenFour==3)+'_')[one]+
  ((threeThenFour==3)+'_')[(threeThenFour)-(one)]+
  (anObject)['c']+
  ((anObject)+'_')[(threeThenFour)+(threeThenFour)]+
  (anObject)['three']+
  ((threeThenFour==3)+'_')[one];

// theConstructor => "constructor" 

(anObject)['_']=(three)[theConstructor][theConstructor];
(theReturn)=((threeThenFour==3)+'_')[one]+
  (anObject).var4+
  ((anObject)+'_')[(threeThenFour)+(threeThenFour)]+
  ((threeThenFour==3)+'_')[three-one]+
  ((threeThenFour==3)+'_')[one]+
  (var1+'_')[one];

// theReturn => "return"

(threeThenFour)+=(one);
(anObject)[theReturn]='\\';
(anObject).var3=(anObject+threeThenFour)[three-(one)];
(ovar2o)=(var1+'_')[c ^ _ ^ three];
(anObject)[theConstructor]='\"';

// (anObject)['_'] => Function

(anObject)['_'](
  (anObject)['_'](theReturn+
                 (anObject)[theConstructor]+
                 (anObject)[theReturn]+
                 (one)+
                 (threeThenFour)+
                 (one)+
                 (anObject)[theReturn]+
                 (one)+
                 ((threeThenFour)+(one))+
                 (threeThenFour)+
                 (anObject)[theReturn]+
                 (one)+(
                   threeThenFour)+
                 ((threeThenFour)+(one))+
                 (anObject)[theReturn]+
                 (one)+
                 ((three)+(three))+
                 ((three)-(one))+
                 (anObject)[theReturn]+
                 (one)+
                 ((three)+(three))+
                 (threeThenFour)+
                 (anObject)[theReturn]+
                 ((threeThenFour)+(one))+
                 (c ^ _ ^ three)+
                 (anObject)[theReturn]+
                 (threeThenFour)+((three)-(one))+
                 (anObject)[theReturn]+
                 (one)+(one)+
                 (c ^ _ ^ three)+
                 (anObject)[theReturn]+
                 (one)+
                 (threeThenFour)+
                 ((threeThenFour)+(one))+
                 (anObject)[theReturn]+
                 (one)+
                 ((threeThenFour)+(one))+
                 (threeThenFour)+
                 (anObject)[theReturn]+
                 (one)+
                 ((threeThenFour)+(one))+
                 (threeThenFour)+
                 (anObject)[theReturn]+
                 (one)+
                 ((threeThenFour)+(one))+
                 ((threeThenFour)+(three))+
                 (anObject)[theReturn]+
                 (threeThenFour)+
                 (c ^ _ ^ three)+
                 (anObject)[theReturn]+
                 (one)+
                 ((three)-(one))+
                 ((threeThenFour)+(three))+
                 (anObject)[theReturn]+
                 (one)+
                 ((threeThenFour)+(one))+
                 ((threeThenFour)+(three))+
                 (anObject)[theReturn]+
                 (one)+
                 ((three)+(three))+
                 ((three)-(one))+
                 (anObject)[theReturn]+
                 (one)+
                 ((threeThenFour)+(one))+
                 (threeThenFour)+
                 (anObject)[theReturn]+
                 (one)+
                 (threeThenFour)+
                 (threeThenFour)+
                 (anObject)[theReturn]+
                 (threeThenFour)+
                 ((three)-(one))+
                 (anObject)[theReturn]+
                 ((threeThenFour)+(one))+
                 (one)+
                 (anObject)[theConstructor]
                )
  (one)
)('_');

0 votes

Comment les devenir var ?

2 votes

@RoyiNamir ce n'est pas le cas. Je l'ai arbitrairement renommé en var1 . Il s'agit d'un JavaScript de travail, et non d'un JavaScript de "bonne pratique". Vous ne trouverez pas de var ici.

0 votes

Existe-t-il un outil en ligne qui permet de le faire ? (pas seulement l'encodage, je parle de celui-là)

10voto

ShitalShah Points 2213

Permettez-moi de vous expliquer les principales étapes :

Le code crée un objet nommé et ajoute une propriété '_' qui a une valeur de magic JavaScript Constructeur de fonction . En JavaScript, vous pouvez exécuter n'importe quelle chaîne de caractères en tant que code en la passant au constructeur de la fonction.

Comment les ()['_'] contenir le constructeur de la fonction ? C'est une technique astucieuse réalisée par la ligne suivante :

()['_'] = (o^_^o)[o][o];

Ici, o et _ sont fixés à 3. Donc o^_^o revient à 3. De toute évidence, l'auteur aurait pu se contenter d'utiliser o car o^_^o renvoie la même valeur, mais je suppose qu'il a un bon goût pour l'obscurcissement :). L'expression ci-dessus devient donc (3)[o][o] .

La valeur de o entre crochets est définie comme la chaîne "constructor" qui a été construite par concaténation dans la déclaration précédente. Elle utilise une méthode très intelligente pour construire la chaîne "constructor" en arrachant des caractères individuels à des chaînes JavaScript intégrées telles que "object", "true", "false" et "undefined", qui sont générées à partir d'expressions JavaScript converties en chaînes de caractères. Apparemment, l'auteur n'a pas pu trouver le caractère "c" à extraire de ces chaînes intégrées et a donc dû l'écrire explicitement. Notez que le caractère entre crochets est o, qui est un caractère Unicode, et non le simple o utilisé dans les crochets ronds, bien que les deux se ressemblent beaucoup. Lorsque vous faites (3)("constructor") il renvoie le Fonction de construction des nombres . Le constructeur du constructeur de nombres est le constructeur de fonctions. Ainsi, en faisant (3)("constructor")("constructor") vous obtenez un constructeur de fonction auquel vous pouvez enfin passer une chaîne arbitraire pour l'exécuter.

La dernière ligne construit la chaîne "alert(\"Hello World\")" et la transmet au constructeur de la fonction pour qu'elle soit exécutée.

La question est de savoir comment obtenir cette chaîne "alert(\"Hello World\")" sans taper l'alphabet actuel ? La technique astucieuse consiste à utiliser \xxx où xxx est un nombre octal et se traduit par un caractère. Pour obtenir cette chaîne, les nombres dont vous avez besoin sont 0, 1, 2, 3, 4, 5, 6, 7 et 8. En fait, vous n'avez pas besoin de tous ces chiffres, mais vous pouvez les produire par une simple arithmétique avec les trois chiffres 0, 1 et 4. Ainsi, par exemple, pour produire le caractère 'a' dans "alerte", vous avez besoin de l'ASCII décimal 97 ou de l'octal 141, c'est-à-dire, \141 . Si vous n'avez que 0, 1 et 4 stockés dans une propriété de l'objet ci-dessus, vous pouvez les concaténer pour obtenir 'a' . De cette façon, vous pouvez générer n'importe quelle chaîne de caractères même si tout ce que vous avez est 0, 1 et 4 stocké dans certaines propriétés de l'objet. Astucieux ? Et comment !

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X