Several Windows applications that present themselves as legitimate utilities—Internet speed testers, “manual reader” and “finder” tools, certain PDF utilities, and even some AI search frontends such as justaskjacky have been observed to drop a portable Node runtime folder alongside a heavily obfuscated JavaScript payload.
The visible executable performs as expected to the users, however the installer also extracts the Node runtime, a scheduled task, and an obfuscated *.js
file that don’t appear necessary for the application's primary function.
That JavaScript is executed by the dropped Node instance via a scheduled task (observed to run on roughly a 12-hour cycle). Its capabilities include encoded/obfuscated network communications and the potential to execute arbitrary code delivered by the server.
Because the JS runs independently from the main executable and is persistent via scheduled tasks, it significantly increases the attack surface: the bundled app becomes a convenient installer for a covert background component that can receive commands or payloads while the advertised app remains the user-facing cover.
This behavior has been seen across multiple app categories, including fake online speed tests, manual readers/finder utilities, PDF tools, and some AI search wrappers.
The samples are packed with an Inno-Packer installer, they drop node, run an obfuscated JS file, and set persistence using a task.xml file.
Obfuscated JS:
Just like the previously-mentioned manual-reader/finder software applications, the decoded strings from the JavaScript (JS) are the same.
MachineGuid
0.2.1
Content-Type
text/plain
Content-Length
POST
utf8
data
end
error
base64
/log.txt
0.2.1
=_=
app
asdc
#version#
#a#
{ "ver": #version#, "a": #argString# }
exports
require
module
__filename
__dirname
//# sourceURL=
./temp.js
Function
You can get this by patching the return statement of the decode function:
return (() => { const r = _0x4375f0.decode(_0xfca211); console.log(r); return r; })();
I set up a local listener, pointed the C2 server (cloud.appusagestats[.]com) to localhost, and generated a certificate. Doing so enabled me to capture the POST data:
Looking at the malware itself there are a couple things we can do to extract information: For the POST data, there is a JSON.stringify that follows the URL section seen here:
Simply adding code to write the value of _0x4c2a32 to a file or to the console immediately after the const is declared, we can see what the POST was going to be:
","19":"\\","20":"\"","21":"a","22":"\\","23":"\"","24":":","25":" ","26":"#","27":"a","28":"r","29":"g","30":"S","31":"t","32":"r","33":"i","34":"n","35":"g","36":"#","37":"
","38":"}","39":"\"","_0x54ff88":"app","_0x207b95":"f4f34c43-9bc1-4a9a-b55f-1d4dd97e0e88","_0x467b2c":"67492aa0-a9de-41ef-9107-3bc675d45663","_0x235f3c":"0.2.1","_0x2e9a79":"10.0.26100"}
Local Listener/MockC2, executes powershell popup (can be any arbitrary code).
Capture Response from mock C2, then save the response to a separate file, I'm not executing here: Going to look at the saved response file then execute.
[RESPONSE PREVIEW] (function(){
try {
const cp = require && require('child_process');
if (cp && cp.exec) {
const cmd = 'powershell -NoProfile -WindowStyle Hidden -Command "Add-Type -AssemblyName System.Windows.Forms;[System.Windows.Forms.MessageBox]::Show(\'Hello from server\',\'Server\')"';
cp.exec(cmd, (err) => { /* ignore errors */ });
} else {
try { if (typeof alert === 'function') alert('Hello from server'); } catch(e){}
}
} catch (e) {
try { console.log('payload exec failed', e); } catch(e) {}
}
})();
saved to response.js
[RESPONSE CLOSE]
For clarification: the Mock C2 is local to my virtual machine (VM) and is intentionally responding with PowerShell. This does not imply that the real C2 server will use PowerShell or deliver malicious code, but it does show the capability to do so. To date I have only observed an empty JSON response from the server; this could change, but until it does there are no overt signs of compromise.
Similar types of malware have been noted to take days, or even weeks before malicious execution may occur per TrueSec.
Screenshot from PoC MockC2 local server providing a response from node.exe running the suspicious JS file and pointing known server to localhost.
Real return data from server (no longer using my Mock C2)
Content-Type: application/octet-stream
Content-Length: 40
Connection: keep-alive
Date: Mon, 22 Sep 2025 16:55:26 GMT
x-azure-ref: 20250922T165525Z-1699cd475d4jmgqnhC1CHIpn3g0000000s50000000001mqe
Permissions-Policy: ch-ua-platform-version=(self)
Permissions-Policy: ch-ua-platform-version=(self)
Accept:
X-Frame-Options: SAMEORIGIN
Accept-CH: Sec-CH-UA,Sec-CH-UA-Mobile,Sec-CH-UA-Platform,Sec-CH-UA-Platform-Version,Sec-CH-UA-Full-Version-List,Sec-CH-UA-Bitness,Sec-CH-UA-Windows-Platform-Version,Sec-CH-UA-Windows-Platform,Sec-CH-UA,Sec-CH-UA-Mobile,Sec-CH-UA-Platform,Sec-CH-UA-Platform-Version,Sec-CH-UA-Full-Version-List,Sec-CH-UA-Bitness,Sec-CH-UA-Windows-Platform-Version,Sec-CH-UA-Windows-Platform
X-Robots-Tag: noindex, nofollow
X-Content-Type-Options: nosniff
X-Powered-By: Super.NET Core/26.5
x-amzn-Remapped-Host: https://cloud.appusagestats.com
Accept-Ranges: bytes
Via: 1.1 07cd926cacea30be011995815cfac2ca.cloudfront.net (CloudFront), 1.1 fbb57b33b603409a00479cc40a7a88a4.cloudfront.net (CloudFront)
X-Cache: Miss from cloudfront
X-Amz-Cf-Pop: ORD58-P14
X-Amz-Cf-Id: Ps_eS_qb77SwN8Jmyve-ZvNq3DGiYKgv_VoSBvbWJhDO0qyrmmvpcg==
fXIuXHMyRDoudW3mshMOrgZ4DnxRQigYFFU2u7hu
This can be decoded by performing the base64 decode, take the first 16 bytes (as hex) as an XOR key, then apply that key to everything following the first 16 bytes
this gets a simple JSON, in my case pl didn't reutrn anything.
"pl": []
}
Indicators
List of suspected EvilAI files and hashes can be found on the SecurityMagic GitHub.
Indicator Type | Name | Value |
---|---|---|
Domain | C2 | cloud.appusagestats.com |
Domain | Download site | onlinespeedtestservice.com |
Hash (MD5) | onlinespeedtest.exe | 77b85765b07954ac0ef88757cb87ac85 |
Hash (MD5) | utils-api.js | 8139f622af19e46bacef44a04890afac |
Hash (MD5) | internetconnectioncheck.exe | 7feff78eaa5bc4b6986c7077b4c0bb82 |
Hash (MD5) | measureinternetspeed.exe | 5323dcab8dc8bd7e3282e75c0357eeab |
Hash (MD5) | viewspeedtest.exe | 20acdf3519635a75fce5dff425f64166 |
Comments
Post a Comment