The Spanner logo
    • Home
    • Blog
      • Blog home
      • RSS
    • Login
    • Home
    • Blog
      • Blog home
      • RSS
    • Login
    The Spanner logo

    The Spanner
    Web security blog

    Made by Gareth Heyes
    Follow me on Twitter: @garethheyes

    Javascript for hackers!

    Hackvertor logo
    Shazzer logo
    My Github account
    Recent posts
    Pure-CSS 3D world collision detection How to write a Hackvertor tagIntroducing Feedworm: A Privacy-First RSS Reader That Lives in DevToolsSpeedy RSVP extensionAutoVaderHackvertor history and tag finderShadow Repeater v1.2.3 releaseBurp Hackvertor v2.1.24 releaseHacking roomsXSSing TypeErrors in SafarivalueOf: Another way to get thisMaking the Unexploitable Exploitable with X-Mixed-Replace on FirefoxThe curious case of the evt parameterCSS-Only Tic Tac Toe ChallengeRewriting relative urls with the base tag in SafariBypassing DOMPurify with mXSSNew IE mutation vectorHow I smashed MentalJSMentalJS DOM bypassAnother XSS auditor bypassXSS Auditor bypassBypassing the IE XSS filterUnbreakable filterMentalJS bypassesmXSSJava SerializationBypassing the XSS filter using function reassignmentRPOSandboxed jQueryX-Domain scroll detection on IE using focusEpic fail IEnew operatorDecoding complex non-alphanumeric JavaScriptHacking FirefoxDOM ClobberingBypassing XSS AuditorThe evolution of codeNon-Alpha PHP in 6-7 charsetTweetable PHP-Non AlphaMentalJS for PHP

    Decoding non-alphanumeric code with Hackvertor

    By Gareth Heyes (@hackvertor)

    Published 15 years ago • Last updated March 22, 2025 • ⏱️ 2 min read

    ← Back to articles

    I saw this post from Thomas Stig Jacobsen. He uses eval to decompile the code, I thought there has to be a better way :) so in literally about 30 minutes I managed to do it after a few tweaks to the JSReg code base. What does non-alphanumeric JavaScript look like?

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

    Produced by my friend Yosuke Hasegawa using his JJEncode.

    How the hell do you decode that Gareth? (I hear you say). Quite easily actually. First off I extend the Hackvertor environment to allow sandboxed code to call the JSReg parser.

    
    parser.extendWindow("$sandbox$", function(code){});
    
    

    This makes "sandbox" a global function within each tag, I need to do this because I want to listen for any calls to "Function" and instead of eval'ing the results I simply want to return the string generated. To do this I add more code to the "sandbox" function to create an instance of JSReg and execute the code:-

    
    parser.extendWindow("$sandbox$", function(code){	
    	var js = JSReg.create(), result; 
    	js.setDebugObjects({doNotFunctionEval:true,functionCode: function(code) {
    			code = code.replace("J.F();var $arguments$=J.A(arguments);",'');
    			result = code;						
    	}});
    	try {
    	  js.eval(code);
    	} catch(e){
    	   return e;
    	}
    	return result;
    });
    
    

    So as you can see the magic happens in the debug objects of JSReg, I use the "doNotFunctionEval" to listen to Function but not eval the code sent. Then I use another listener to "functionCode" to intercept the results.

    The final Hackvertor tag is dead simple:-

    
    (function(){
        return sandbox(code);
    })();
    
    

    The final results can be seen here:- Decode non-alpha please feel free to go whoa now. That's sandboxed code calling a unsandboxed function, sending a non-alpha string, sandboxing it, listening to the results and returning the decoded code. In the blink of an eye :)

    Credits as always to Lever one and Jonas Magazinius for testing JSReg and making this possible.

    ← Back to articles