JavaScript: Décoder les fichiers encodés avec "dF()"

Dans la suite de mon article sur le décryptage des fichiers PHP, je ré-itère mon intervention pour décoder des scripts jQuery pauvrement protégés avec un vieux script d'encodage qui consiste à remplacer les caractère par leur code ASCII.

Si il vous plait, arrêtez de vouloir protéger vos scripts JavaScript car il y aura toujours un moyen de les décoder/décrypter... Vous allez voir comme c'est pathétique et je cite la librairie jQuery Lightbox Evolution avec sa page de démo !
Librairie vendu $14 alors qu'avec un peu de malice on peut l'avoir avec en plus une augmentation de son estime...

Procédure

Si votre script commence ainsi, alors je suis votre homme :

eval(unescape('%66%75%6E%63%74%69%6F%6E%20%64%46%28%73%29%7B%0A%76%61%72%20%73%31%3D%75%6E%65%73%63%61%70%65%28%73%2E%73%75%62%73%74%72%28%30%2C%73%2E%6C%65%6E%67%74%68%2D%31%29%29%3B%20%76%61%72%20%74%3D%27%27%3B%0A%66%6F%72%28%69%3D%30%3B%69%3C%73%31%2E%6C%65%6E%67%74%68%3B%69%2B%2B%29%74%2B%3D%53%74%72%69%6E%67%2E%66%72%6F%6D%43%68%61%72%43%6F%64%65%28%73%31%2E%63%68%61%72%43%6F%64%65%41%74%28%69%29%2D%73%2E%73%75%62%73%74%72%28%73%2E%6C%65%6E%67%74%68%2D%31%2C%31%29%29%3B%0A%72%65%74%75%72%6E%28%75%6E%65%73%63%61%70%65%28%74%29%29%3B%0A%7D'));
eval(dF('j%7Bfq*7%3Dkzshynts*7%3Du*7Hf*7Hh*7Hp*7Hj*7Hw*7%3E*%3CGj*8Ikzshynts*7%3Dh*7%3E*%3CGwjyzws*7%3Dh*8Hf*8K*7%3C*7%3C*8Fj*7%3DufwxjNsy*7%3Dh4f*7%3E*7%3E*7%3E0*7%3D*7%3Dh*8Ih*7%3Af*7%3E*8J8%3A*8KXywnsl3kwtrHmfwHtij*7%3Dh07%3E*7%3E*8Fh3ytXywnsl*7%3D8%3B*7%3E*7%3E*%3CI*8Gnk*7%3D*76*7%3C*7%3C3wjuqfhj*7%3D4*%3AJ4*7HXywnsl*7%3E*7%3E*%3CG%7Cmnqj*7%3Dh22*7%3Ew*...

Comme tout bon développeur Web, vous avez Firebug ou l'accès à une console JavaScript et donc, regardez bien comme cela est difficile, vous remplacez le premier eval() par un très bete console.log() :

console.log(unescape('%66%75%6E%63%74%69%6F%6E%20%64%46%28%73%29%7B%0A%76%61%72%20%73%31%3D%75%6E%65%73%63%61%70%65%28%73%2E%73%75%62%73%74%72%28%30%2C%73%2E%6C%65%6E%67%74%68%2D%31%29%29%3B%20%76%61%72%20%74%3D%27%27%3B%0A%66%6F%72%28%69%3D%30%3B%69%3C%73%31%2E%6C%65%6E%67%74%68%3B%69%2B%2B%29%74%2B%3D%53%74%72%69%6E%67%2E%66%72%6F%6D%43%68%61%72%43%6F%64%65%28%73%31%2E%63%68%61%72%43%6F%64%65%41%74%28%69%29%2D%73%2E%73%75%62%73%74%72%28%73%2E%6C%65%6E%67%74%68%2D%31%2C%31%29%29%3B%0A%72%65%74%75%72%6E%28%75%6E%65%73%63%61%70%65%28%74%29%29%3B%0A%7D'));

Et voici le résultat :

function dF(s){ var s1=unescape(s.substr(0,s.length-1)); var t=''; for(i=0;i<s1.length;i++)t+=String.fromCharCode(s1.charCodeAt(i)-s.substr(s.length-1,1)); return(unescape(t)); }

Vous avez désormais votre fonction permettant de décoder la librairie... Il vous suffira de la remplacer (ce sera transparent pour le navigateur) mais cela ne permet toujours pas de dévoiler le code source de la librairie.
Pour se faire, on va remplacer l'opérateur return par un devinez.... console.log() dans la fonction :

function dF(s) {
    var s1 = unescape(s.substr(0, s.length - 1));
    var t = '';
    for (i = 0; i < s1.length; i++)
        t += String.fromCharCode(s1.charCodeAt(i) - s.substr(s.length - 1, 1));
    console.log(unescape(t));
}

Et là, ô surprise dans notre console, on trouve du code JavaScript :

eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('(u($){D n=($.1u.2k&&1v($.1u.2l,10)<7&&1v($.1u.2l,10)>4);q($.H===25){$.1i({H:u(a,b){q(a){H=u(){L a.3e(b||8,4k)}};L H}})};q($.2D===25){$.1i({2D:u(a){3f(D b 4l a){L M}L J}})};$.1i($.3g,{2E...

Bon, le code est packé mais c'est pas si grave... Un gros copié-collé vers un site permettant de décompresser le code et hop, le tour est joué :

(function ($) {
    var n = ($.browser.msie && parseInt($.browser.version, 10) < 7 && parseInt($.browser.version, 10) > 4);
    if ($.proxy === undefined) {
        $.extend({
            proxy: function (a, b) {
                if (a) {
                    proxy = function () {
                        return a.apply(b || this, arguments)
                    }
                };
                return proxy
            }
        })
    };
// ...

Et dans la démo d'un code comme celui de jQuery Lightbox Evolution, on trouve une petite condition à la fin qu'il suffira de supprimer pour profiter de la librairie :

// ...
    $(function () {
        if (parseFloat($.fn.jquery) > 1.2) {
            if (document.domain.indexOf("envato.com") != -1 || document.domain.indexOf("aerowebstudio.net") != -1 || document.domain.indexOf("localhost") != -1) {
                $.LightBoxObject.create()
            }
        } else {
            throw "The jQuery version that was loaded is too old. Lightbox Evolution requires jQuery 1.3+";
        }
    })
// ...

Supprimez le second block if() et le tour est joué :

// ...
    $(function () {
        if (parseFloat($.fn.jquery) > 1.2) {
            $.LightBoxObject.create()
        } else {
            throw "The jQuery version that was loaded is too old. Lightbox Evolution requires jQuery 1.3+";
        }
    })
// ...

Conclusion

On en apprendra que finalement, la seule est unique façon de vraiment bien protéger son code pour des langages client-side sera tout simplement de ne pas le donner (même pas un exemple) ; donc inutile de vous embêter à encoder/encrypter tout ça puisque si votre navigateur peut le faire exécuter, nous aussi MAIS SURTOUT parce que c'est une plaie de lenteur inutile pour les sites Web...