Skip to content

Instantly share code, notes, and snippets.

@jocopa3
Last active March 2, 2017 01:00
Show Gist options
  • Save jocopa3/092219dd8b3c57f7ebbf9eacdd28aa44 to your computer and use it in GitHub Desktop.
Save jocopa3/092219dd8b3c57f7ebbf9eacdd28aa44 to your computer and use it in GitHub Desktop.
Rudimentary webpage which can help deobfuscate malicious JScript files. It reports the URLS accessed, Files accessed, and ActiveX API calls made.
<html><head>
<script type="text/javascript">
var URLSRequested = [];
var FilesAccessed = [];
var APICalls = [];
// If true, the analyzer displays an alert box whenever the script calls WScript.echo
// If false, the analyzer prints the echo message to console
var AlertEchos = false;
// calls Console.trace() whenever addAPI is called to allow for easier debugging
var DEBUG_SCRIPT = false;
var TODAY = new Date();
// Simulate downloaded payload in-order to trick malware into "executing"
var payloadHeader = "payload data";
//var payloadHeader = "\u001D\u0020 payload data";
var payloadLength = payloadHeader.length;
var simulatedPayload = payloadHeader;
// Optionally fill the simulated payload with a number of zero-width spaces
// to trick malware into thinking the payload is a certain size
for(var i = 0; i < payloadLength - payloadHeader.length; i++) {
simulatedPayload += "\u200B";
}
function addURL(a) {
if(URLSRequested.indexOf(a) < 0) {
URLSRequested.push(a);
document.getElementById("urls").value += a+"\n";
}
}
function addFile(a) {
if(FilesAccessed.indexOf(a) < 0) {
FilesAccessed.push(a);
document.getElementById("files").value += a+"\n";
}
}
function addAPI(a) {
if(DEBUG_SCRIPT) {console.trace(a);}
APICalls.push(a);
document.getElementById("api").value += a+"\n";
}
// Resets the state of the anaylzer
function clearAll(a) {
totalEvals = 0;
URLSRequested = []
FilesAccessed = [];
APICalls = [];
document.getElementById("urls").value = "";
document.getElementById("files").value = "";
document.getElementById("api").value = "";
// Possible bug: doesn't clear eval'd code
var oldScript = document.getElementById("maliciousCode");
if(oldScript !== null) {
oldScript.remove();
}
}
// Buggy
function isFunction(f) {
return typeof f === "function";
}
// Emulates JScript's case-insensitivity when accessing ActiveX object properties
var defaultProxyHandler = {
get: function(target, name) {
if(typeof name === "symbol") {
return function() {return "Windows Script Host";};
}
if (name.toLowerCase() in target) {
if(!isFunction(target[name.toLowerCase])) {
//addAPI("Accessed Property: " + name);
}
return target[name.toLowerCase()];
} else {
console.log("Missing Property in " + target._OBJTYPEPROPERTY + ": " + name);
}
return undefined;
},
set: function(target, name, value) {
//addAPI("Set Property: " + target._OBJTYPEPROPERTY + "." + name + " = " + value);
}
};
var WinHTTPProxyHandler = {
get: function(target, name) {
if (name.toLowerCase === "option") {
return "";
}
if (name.toLowerCase() in target) {
if(!isFunction(target[name.toLowerCase])) {
//addAPI("Accessed Property: " + name);
}
return target[name.toLowerCase()];
} else {
console.log("Missing Property in " + target._OBJTYPEPROPERTY + ": " + name);
}
return undefined;
},
set: function(target, name, value) {
//addAPI("Set Property: " + target._OBJTYPEPROPERTY + "." + name + " = " + value);
}
};
function createProxy(objType, obj, handler) {
obj._OBJTYPEPROPERTY = objType;
if(typeof handler === typeof undefined) {
return new Proxy(obj, defaultProxyHandler);
} else {
return new Proxy(obj, handler);
}
}
// TODO: Possibly emulate file system and record file reads/writes/deletes
var FileSystem = {};
var ActiveXObject = function (a, b) {
if (!b) {
addAPI("ActiveXObject(\"" + a + "\")");
}
switch (a.toUpperCase()) {
case "MSXML2.XMLHTTP":
return createProxy(a, {
open: function (a, b, c) {
addURL(b);
addAPI("MSXML2.XMLHTTP.open(\"" + a + "\", \"" + b + "\", " + c + ")");
},
send: function () {
addAPI("MSXML2.XMLHTTP.send()");
},
status: 200,
responsebody: simulatedPayload,
responsetext: simulatedPayload,
setrequestheader: function (a, b) {
addAPI("MSXML2.XMLHTTP.setRequestHeader(\"" + a + "\", \"" + b + "\")");
}
});
case "WSCRIPT.SHELL":
return createProxy(a, {
run: function (a, b, c) {
var enumVal = "";
if(b) {
switch(b.toString()) {
case "0":
enumVal = "HideWindow";
break;
}
}
addAPI("WScript.Shell.run(\"" + a + "\", " + b + " ["+enumVal+"], " + c + ")");
return 0;
},
expandenvironmentstrings: function (a) {
addAPI("WScript.Shell.ExpandEnvironmentStrings(\"" + a + "\")");
var b = a.split("%");
switch (b[1].toUpperCase()) {
case "TEMP":
return "C:/Users/FakeUser/AppData/Local/Temp" + b[2];
}
}
});
case "ADODB.STREAM":
return createProxy(a, {
type: 0,
charset: 0,
open: function () {
addAPI("ADODB.Stream.open()");
},
loadfromfile: function (a) {
addAPI("ADODB.Stream.LoadFromFile(\"" + a + "\")");
},
readtext: simulatedPayload,
close: function () {
addAPI("ADODB.Stream.close()");
},
readtext: function(a) {
return simulatedPayload.substr(0, a);
},
write: function (a) {
addAPI("ADODB.Stream.write(\"" + a + "\")");
},
writetext: function (a) {
addAPI("ADODB.Stream.writeText(\"" + a.substr(0, 16).replace("\n", " ") + "..." + "\")");
},
savetofile: function (a, b) {
addFile(a);
var enumVal = "adSaveDoNotCreate";
if(b) {
switch(b.toString()) {
case "1":
enumVal = "adSaveCreateNotExist";
break;
case "2":
enumVal = "adSaveCreateOverWrite";
break;
}
}
addAPI("ADODB.Stream.SaveToFile(\"" + a + "\", "+b+" [" + enumVal + "])");
}
});
case "SCRIPTING.FILESYSTEMOBJECT":
return createProxy(a, {
copyfile: function (a, b, c) {
addFile(a);
addFile(b);
addAPI("Scripting.FileSystemObject.CopyFile(\"" + a + "\", \"" + b + "\", " + c + ")");
},
getdrive: function (a) {
addAPI("Scripting.FileSystemObject.GetDrive(\"" + a + "\")");
return createProxy("Drive", new function () {
this.filesystem = a.toUpperCase() + ":\\";
this.serialnumber = 1234567;
});
},
getdrivename: function (a) {
addAPI("Scripting.FileSystemObject.GetDriveName(\"" + a + "\")");
return a.charAt(0);
},
getfile: function (a) {
addFile(a);
addAPI("Scripting.FileSystemObject.GetFile(\"" + a + "\")");
return createProxy("File", new function () {
this.datelastmodified = TODAY;
});
},
getspecialfolder: function (a) {
addAPI("Scripting.FileSystemObject.GetTempFolder(\"" + a + "\")");
switch (a.toString()) {
case "2":
return "C:/Users/FakeUser/AppData/Local/Temp/";
}
},
gettempname: function () {
addAPI("Scripting.FileSystemObject.GetTempName()");
return "tempName";
},
deletefile: function (a) {
addFile(a);
addAPI("Scripting.FileSystemObject.deleteFile(\"" + a + "\")");
},
createfolder: function (a) {
addFile(a);
addAPI("Scripting.FileSystemObject.CreateFolder(\"" + a + "\")");
},
fileexists: function (a) {
addFile(a);
addAPI("Scripting.FileSystemObject.FileExists(\"" + a + "\")");
return true;
},
folderexists: function (a) {
addFile(a);
addAPI("Scripting.FileSystemObject.FolderExists(\"" + a + "\")");
return true;
},
opentextfile: function(a, b, c, d) {
addFile(a);
addAPI("Scripting.FileSystemObject.OpenTextFile(\"" + a + "\", \"" + b + "\", \"" + c + "\", \"" + d + "\")");
return createProxy("TextStream", {
close: function(a) {
addAPI("TextStream.Close()");
},
write: function(a) {
addAPI("TextStream.Write(\"" + a + "\")");
},
writeline: function(a) {
addAPI("TextStream.WriteLine(\"" + a + "\")");
}
});
}
});
case "WSCRIPT.NETWORK":
return createProxy(a, {
username: "FakeUser"
});
case "WINHTTP.WINHTTPREQUEST.5.1":
return createProxy(a, {
open: function (a, b, c) {
addURL(b);
addAPI("WinHttpRequest.5.1.Open(\"" + a + "\", \"" + b + "\", " + c + ")");
},
send: function () {
addAPI("WinHttpRequest.5.1.Send()");
},
status: 200,
responsetext: simulatedPayload,
responsebody: simulatedPayload,
readystate: true,
option: function(a) {
var enumVal = "Unknown Enum";
switch(a.toString()) {
case "0":
enumVal = "UserAgentString";
break;
case "1":
enumVal = "URL";
break;
case "2":
enumVal = "URLCodePage";
break;
}
addAPI("WinHttpRequest.5.1.Option(" + a + " ["+enumVal+"])");
return 0;
}
}, WinHTTPProxyHandler);
case "SCRIPTING.DICTIONARY":
return createProxy(a, new function() {
var dict = [];
this.add = function(a, b) {
dict[a] = b;
};
this.exists = function(a) {
return typeof dict[a] !== typeof undefined;
};
this.keys = function() {
return Object.keys(dict);
};
this.item = function(a) {
return dict[a];
};
});
}
};
var WScript = createProxy("WScript", {
createobject: function (a) {
addAPI("WScript.CreateObject(\"" + a + "\")");
return new ActiveXObject(a, true);
},
echo: function(a) {
addAPI("WScript.Echo(\"" + a + "\")");
if(AlertEchos)
alert(a);
else
console.log(a);
},
quit: function() {
addAPI("WScript.Quit()");
},
scriptfullname: "WScript.ScriptFullName",
sleep: function(a) {
addAPI("WScript.Sleep(" + a + ")");
},
toString: function() {
return "Windows Script Host";
}
});
var WSH = "Windows Script Host";
// Some JScript's check if URL is defined, indicating it's running in a browser
var URL = undefined;
function runMaliciousCode(code, id) {
var script = document.createElement('script');
script.id = id;
script.src = 'data:text/javascript,' + encodeURIComponent(code);
document.body.appendChild(script);
}
// Replace eval to allow breakpoint persistance in Chrome DevTools.
/*
var totalEvals = 0;
var _eval = eval;
var eval = function(a) {
totalEvals++;
runMaliciousCode(a, "eval"+totalEvals);
};
*/
</script>
</head>
<body>
<table style="width:100%; height:96%">
<tbody>
<tr>
<td rowspan="3" style="width: 50%;height: 95%;">
<div style="float:left;width: 100%;height: 100%">
<h>Code to Analyze</h>
<br />
<textarea name="codeToRun" id="code2run" style="margin: 0px;width: 100%;height: 100%;padding-right: 2px;padding-bottom: 2px;"></textarea>
<br />
<button onclick="clearAll();runMaliciousCode(document.getElementById('code2run').value, 'maliciousCode')">Run</button>
</div>
</td>
<td style="width: 48%;height: 30%;">
<div style="float:right;width: 100%;height: 100%">
<h>URLs Requested</h>
<br />
<textarea id="urls" style="margin: 0px;width: 100%;height: 100%;padding-right: 2px;padding-bottom: 10px;"></textarea>
</div>
</td>
</tr>
<tr>
<td style="width: 48%;height: 30%;">
<div style="float:right;width: 100%;height: 100%;padding-top: 2%;">
<h>Files Accessed</h>
<br />
<textarea id="files" style="margin: 0px;width: 100%;height: 100%;padding-right: 2px;padding-bottom: 10px;"></textarea>
</div>
</td>
</tr>
<tr>
<td style="width: 48%;height: 30%;">
<div style="float:right;width: 100%;height: 100%;padding-top: 2%;">
<h>API Calls</h>
<br />
<textarea id="api" style="margin: 0px;width: 100%;height: 100%;padding-right: 2px;padding-bottom: 10px;"></textarea>
</div>
</td>
</tr>
</tbody></table>
</body></html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment