├── 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 |
36 |
37 |
40 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/test/test1.html:
--------------------------------------------------------------------------------
1 |
2 | f6d
3 |
33 | 0
34 |
--------------------------------------------------------------------------------
/test/test5.html:
--------------------------------------------------------------------------------
1 |
2 |
22 |
--------------------------------------------------------------------------------