├── test ├── test3.html ├── test4.html ├── test2.html ├── test1.html └── test5.html ├── README.md ├── dumper.js └── jsado.py /test/test3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | JS Auto DeObfuscator 2 | ======================== 3 | 4 | ##About 5 | JsADO automatically deobfuscate javascript scripts which use eval or some other function, one or more time, to de-obfuscat it-self. 6 | This tool hopes to be useful to security researches for speed up their work. 7 | It uses to work as default browser Firefox, but at last line of the source you can change firefox with an other browser as Chrome, obviously. 8 | 9 | #Dependencies 10 | JsADO with Selenium needs: 11 | * Selenium for python: http://pypi.python.org/pypi/selenium 12 | * Selenium server:http://seleniumhq.org/download/ 13 | * ChromeDriver for Chrome support: https://code.google.com/p/chromedriver/ 14 | 15 | ##How to use 16 | If you want to use Firefox with Selenium you must run the selenium-server: java -jar selenium-server-standalone-XX.jar 17 | If you want to use Chrome with Selenium you must run only the ChromeDriver. 18 | 19 | After that you can use these scripts: download jsado.py and run 20 | 21 | **python jsado.py file.html function_to_hack [nExec:0] [useJB] [useS] [injStart]** 22 | 23 | where 24 | * nExec says that the function_to_hack have to be executed nExec times normally 25 | * useJB says to use "js beautify" to show the output: you have to create **beautify.js** (https://github.com/einars/js-beautify) into *outputFileName* dir 26 | * useS says to use Selenium 27 | * injStart to injects js deobfuscation code at file start 28 | 29 | For example: you can call this script with: "python jsado.py obf.html eval" to don't let's execute eval in obf.html and get into the browser all params passed to eval. 30 | You can use the increment to let execute eval one time, for example: the first time with eval there are some variables declaration. 31 | 32 | ##How JsADO works 33 | JsADO injects into the webpage a js script, that hook the function. Once the function hooked is executed, the js script injected shows a pannel with the code catched. 34 | 35 | ##Personalization 36 | You can open jsado.py and change: browserName, outputFileName and useSelenium to don't set 'useS' every time. 37 | For Selenium and Chrome: the default port is 9515, if you need: change it. 38 | 39 | ##Developer 40 | [Luciano Giuseppe] (http://sites.google.com/site/lucianogiuseppeprogrammi/) 41 | -------------------------------------------------------------------------------- /test/test4.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /dumper.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Arguments dumper by Luciano Giuseppe 3 | * It's just an example 4 | */ 5 | 6 | /** 7 | How to use: 8 | If you see code like this: 9 | window[tb('-57,-45,-46,-38,-55,-42,-40,-72,-45,-74,-85,-90')] = function(color) { 10 | return 'rgb(' + HexToR(color) + ',' + HexToG(color) + ',' + HexToB(color) + ')' 11 | 12 | You can use the dumper into function to get output: 13 | function tb(str) { 14 | dump("in", str); 15 | ....//string decrypting code 16 | dump("out", rs); 17 | return rs 18 | } 19 | 20 | And you will get this into the webpage: 21 | 1) 22 | -46,-58,-61,-40,-51,-47,-55,-41,-61,-54,-39,-46,-57,-40,-51,-45,-46,-61,-57,-59,-48,-48,-55,-56 23 | nb_times_function_called 24 | */ 25 | 26 | 27 | var cont = 0; //I suggest you to rename it 28 | var outputString = ""; //I suggest you to rename it 29 | 30 | /* Dump params of a function 31 | * input = input value of the function to check 32 | * type : can be "in" or "out" 33 | */ 34 | function dump(type, input) { 35 | if(typeof(input) === "object") { 36 | var str = "Object:
{"; 37 | for(var t in input) { 38 | str += t +":"+input[t]+","; 39 | } 40 | str = str.substring(0, str.length-1) + "}"; 41 | input = str; 42 | } else if(typeof(input) === "string") { 43 | input = input.replace("&","&",'g').replace("<","<",'g').replace(">",">",'g'); 44 | } 45 | if(window.outputCode === undefined || outputCode.inDom === undefined) { 46 | outputString += formatString(type, input); 47 | } 48 | 49 | if(cont == 1 && !window.outputCode) { 50 | var div = document.createElement("div"); 51 | div.setAttribute("style", "width:95%; height:95%; overflow:no;z-index:100;position:fixed;bottom:0;left:0;border:1px solid black; background:#cccccc;"); 52 | var button = document.createElement("button"); 53 | button.innerHTML = "Minimize"; 54 | button.addEventListener("click", function() { 55 | var p = this.parentNode; 56 | if(p.style.height=="30px") { 57 | p.childNodes[1].style.display="block"; 58 | p.style.height="95%"; 59 | this.innerHTML="Minimize"; 60 | } else { 61 | p.childNodes[1].style.display="none"; 62 | p.style.height="30px"; 63 | this.innerHTML="Maximize"; 64 | } 65 | }); 66 | div.appendChild(button); 67 | outputCode = document.createElement("pre"); 68 | outputCode.setAttribute("style","display:block; height:94%; width:96%; overflow:scroll;color:black;border:1px solid #AAAAAA;background:white;font-size:14px;margin:0 0 0 3px;"); 69 | div.appendChild(outputCode); 70 | if(document.body === undefined || document.body === null) { 71 | addEventListener("load", function() { 72 | outputCode.innerHTML = outputString; 73 | document.body.appendChild(div); 74 | outputCode.inDom =true; 75 | }); 76 | } else { 77 | outputCode.innerHTML = outputString; 78 | document.body.appendChild(div); 79 | outputCode.inDom =true; 80 | } 81 | 82 | } else 83 | if(document.body !== undefined || document.body !== null) { 84 | outputCode.innerHTML += formatString(type, input); 85 | } 86 | } 87 | 88 | function formatString(type, input) { 89 | var str = ""; 90 | if(type == "in") {cont++; str += cont+ ")
"; } 91 | str += input +"
"; 92 | if(type == "out") str += "
"; 93 | return str; 94 | } -------------------------------------------------------------------------------- /jsado.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # JS Auto DeObfuscator 0.7.2 by Luciano Giuseppe 4 | # Useful on eval deobfuscation code 5 | # 6 | #Dependencies: Selenium for python: http://pypi.python.org/pypi/selenium, Selenium server:http://seleniumhq.org/download/ 7 | #More infos: http://pypi.python.org/pypi/selenium 8 | 9 | import subprocess 10 | import sys 11 | import os 12 | import string 13 | import random 14 | 15 | 16 | ##You can personalize these params!! 17 | useSelenium = False # True o False 18 | browserName = "firefox" #the command to run your browser or the complete path 19 | outputFileName = "t.html" #output filename 20 | ##End of pesonalization params!! 21 | 22 | 23 | #check selenium presence 24 | canUseSelenium = True 25 | try: 26 | from selenium import webdriver 27 | from selenium.common.exceptions import NoSuchElementException, WebDriverException 28 | from selenium.webdriver.common.desired_capabilities import DesiredCapabilities 29 | except: 30 | canUseSelenium = False 31 | 32 | 33 | #JS Auto DeObfuscator Class by Luciano Giuseppe 34 | class jsado: 35 | 36 | #Init some class attributes 37 | #browserName: the commandline istruction to run your browser 38 | #outputFileName: output filename 39 | def __init__(self, browserName, outputFileName, injS = False): 40 | self.fileTxt = None; 41 | self.browserName = browserName 42 | self.outputFileName = os.getcwd() + os.sep + outputFileName 43 | self.outputUrlName = "file://"+self.outputFileName 44 | self.injectStart = injS 45 | 46 | #return a random string 47 | def __r(self): 48 | size = random.randint(4, 12) 49 | return ''.join(random.choice(string.ascii_letters) for x in xrange(size)) 50 | 51 | #get the js code to inject into page 52 | def __getHackString(self,f, l): 53 | hackStr = string.Template(""" 54 | \n"""); 129 | return hackStr.substitute({'function': f, 'limit' : l, 'memFct' : self.__r(), 'cont': self.__r(), 'str' : self.__r(), 'div': self.__r(), 'code': self.__r(), 'oldOnError' : self.__r(), 'p' : self.__r(), 'beautify' : self.__r()}) 130 | 131 | #apply the hack to webpage for deobfuscate the js code 132 | def applyHack(self, fileInput, functionName, limitExecution, useJB): 133 | try: 134 | if self.fileTxt is None: #only the first time 135 | with open(fileInput, 'r') as f: 136 | self.fileTxt = f.read() 137 | 138 | 139 | #generate the js code to inject into html 140 | injString = "" 141 | if useJB == True: 142 | injString += "" #you should download js lib from https://github.com/einars/js-beautify 143 | injString += self.__getHackString(functionName, limitExecution) 144 | 145 | #inject into html page 146 | outHtml = self.fileTxt 147 | if self.injectStart == True: 148 | outHtml = injString + outHtml 149 | else: 150 | if outHtml.find("") != -1: 151 | injString = ""+injString 152 | outHtml = outHtml.replace("", injString) 153 | elif outHtml.find("") != -1: 154 | injString = ""+injString+"" 155 | outHtml = outHtml.replace("", injString) 156 | else: 157 | self.injectStart = True #for the next iteration 158 | outHtml = injString + outHtml 159 | 160 | #write the output html file 161 | with open(self.outputFileName, 'w') as outFile: 162 | outFile.write(outHtml) 163 | 164 | except IOError as e: 165 | print("I/O error({0}): {1}".format(e.errno, e.strerror)) 166 | return 0 167 | else: 168 | return 1 169 | 170 | 171 | #Browser launcher factory 172 | class LauncherFactory(object): 173 | def __new__(cls, selenium): 174 | if selenium == True: 175 | return LauncherSelenium() 176 | else: 177 | return LauncherNormal() 178 | 179 | #Launcher that use Selenium to inteface with browser 180 | class LauncherSelenium: 181 | browser = None 182 | 183 | def start(self,browserName, outputUrlName): 184 | if browserName == "chrome": 185 | self.browser = webdriver.chrome.webdriver.WebDriver(executable_path='chromium-browser', port=9515); 186 | else: 187 | self.browser = webdriver.Firefox() # Get local session of firefox 188 | self.browser.get(outputUrlName) # Load page 189 | 190 | def refresh(self): 191 | if self.browser == None: 192 | return 193 | print("Page refreshing...\n") 194 | self.browser.refresh() 195 | 196 | #Normal browser launcher 197 | class LauncherNormal: 198 | 199 | def start(self, browserName, outputUrlName): 200 | subprocess.CREATE_NEW_CONSOLE=True 201 | subprocess.Popen([hack.browserName, hack.outputFileName]); 202 | 203 | def refresh(self): 204 | print("You should refresh page into browser\n") 205 | return 206 | 207 | 208 | 209 | #Parse the argv 210 | def parseArgv(argv): 211 | global useSelenium, canUseSelenium 212 | execLimit = 0 213 | useJsBeauty = False 214 | injStart = False 215 | 216 | argLen = len(sys.argv) 217 | for x in xrange(3,argLen): 218 | str = argv[x].split(':') 219 | matchStr = str[0].lower() 220 | if matchStr == "nexec": 221 | try: 222 | execLimit = int(str[1]) 223 | except ValueError: 224 | print("Bad nExec value: assume it as 0") 225 | elif matchStr == "usejb": 226 | useJsBeauty = True; 227 | elif matchStr == "uses" and canUseSelenium == True: 228 | useSelenium = True 229 | elif matchStr == "injstart": 230 | injStart = True 231 | 232 | return [execLimit, useJsBeauty, injStart] 233 | 234 | # Main 235 | if __name__ == "__main__": 236 | print("JS Auto DeObfuscator\n") 237 | 238 | #checks the args 239 | execLimit = 0 240 | useJsBeauty = False 241 | injStart = False 242 | 243 | argLen = len(sys.argv) 244 | if (argLen < 3): 245 | print("How to use:\n"+ os.path.basename(__file__)+" file.html function_to_hack [nExec:number] [useJB] [useS] [injStart]\n\nSee the site for more information:\nhttp://github.com/lucianogiuseppe/JS-Auto-DeObfuscator") 246 | sys.exit() 247 | else: 248 | execLimit, useJsBeauty, injStart = parseArgv(sys.argv); 249 | 250 | try: 251 | #Prepare the jsado 252 | hack = jsado(browserName, outputFileName, injStart) 253 | #Prepare the browser launcher 254 | launcher = LauncherFactory(useSelenium) 255 | 256 | #apply the hack to webpage 257 | if(hack.applyHack(sys.argv[1], sys.argv[2], execLimit, useJsBeauty) == 0): 258 | print("An error occurred: byee!") 259 | sys.exit() 260 | 261 | #try to run the browser with the decrypter webpage 262 | print("Work completed: %s running..."%hack.browserName) 263 | launcher.start(hack.browserName, hack.outputUrlName) 264 | 265 | #Some descryption about the use 266 | print("If there're some ReferenceError errors in js console or the js deobuscated shows strange strings or seems to be obfuscated use 'increment'!\n") 267 | 268 | #User want to increment the times that eval is normally executed 269 | question = "Do you want to increment the %s execution times? yes/no : "%sys.argv[2] 270 | answer = raw_input(question) 271 | while answer.lower() in ('y', 'yes'): 272 | execLimit += 1 273 | if (hack.applyHack(sys.argv[1], sys.argv[2], execLimit, useJsBeauty) == 0): 274 | print("An error occurred: byee!") 275 | sys.exit() 276 | print("%s execution limit:%d"%(sys.argv[2],execLimit)) 277 | launcher.refresh() #refresh the page 278 | answer = raw_input(question) 279 | except Exception as e: 280 | print("Error: %s\n"%e) 281 | sys.exit(1) 282 | 283 | #exit 284 | print("Bye bye!!") 285 | 286 | -------------------------------------------------------------------------------- /test/test2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Main 7 | 13 | 14 | 26 | 27 | 28 |
29 |
30 | 31 | 32 | 33 | 34 |
35 |
36 | 37 | 40 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /test/test1.html: -------------------------------------------------------------------------------- 1 | 2 | f6d 3 |
33 | 0 34 | -------------------------------------------------------------------------------- /test/test5.html: -------------------------------------------------------------------------------- 1 | 2 |
22 | --------------------------------------------------------------------------------