Table of Contents
- Executive Summary
- Quick Definition
- Key Takeaways
- Overview
- Threat Group Lineage and Timeline
- The WeedHack Malware-as-a-Service Platform
- Initial Compromise and Social Engineering Vectors
- Victimology and Target Demographics
- Current Status: Portals Down, Operators Still Active
- Technical Analysis
- Why LoaderClient Matters
- Indicators of Compromise (IOCs)
- Yara Rules
- FAQ
- Conclusion
Executive Summary
LoaderClient is a Minecraft-based malware loader linked to the WeedHack Malware-as-a-Service campaign. It is distributed as a malicious Minecraft Fabric mod and is designed to steal Minecraft session data, including display name, account UUID, and live Microsoft OAuth access tokens.
What makes LoaderClient especially notable is its command and control architecture. Instead of hardcoding a traditional C2 domain, the malware uses an Ethereum smart contract to retrieve its active C2 URL. This technique, known as EtherHiding, makes the campaign more resistant to domain takedowns, registrar action, and hosting-provider disruption.
The malware also downloads a second-stage payload entirely in memory. That stage-2 payload is compiled using JNIC v3.7.0, hides its business logic inside native code, re-resolves C2 through the same Ethereum contract, bypasses SSL validation, uses DNS-over-HTTPS, and supports further in-memory staging.
Quick Definition
LoaderClient is a Minecraft-based malware loader that steals account credentials, resolves its command-and-control server through an Ethereum smart contract, and delivers a second-stage payload using in-memory execution techniques.
Key Takeaways
- LoaderClient is distributed through malicious Minecraft Fabric mods.
- The malware is part of the WeedHack Malware-as-a-Service campaign.
- WeedHack has logged more than 116,000 unique host compromises since January 2026.
- LoaderClient steals Minecraft session data, including live Microsoft OAuth access tokens.
- The malware uses EtherHiding to store C2 infrastructure inside an Ethereum smart contract.
- Stage-2 payloads are compiled using JNIC native code.
- The malware executes the stage-2 payload entirely in memory.
- The most durable IOC is the Ethereum smart contract address used for C2 resolution.
Since January 2026, threat intelligence teams have tracked an aggressive malware campaign called WeedHack that distributes data-harvesting payloads and Remote Access Trojans disguised as popular Minecraft mods and optimization clients. By June 2026, the campaign had logged over 116K unique host compromises, averaging 2,000 to 3,000 new infections every 24 hours. The operation runs as a Malware as a Service (MaaS) platform with a free tier accessible to anyone with a Discord account and a premium tier starting at just $5.00 USD per month, pricing that has shifted the demographic of threat operators toward teenagers targeting peers in gaming communities.
This report presents a full technical teardown of LoaderClient (stage-1) and its JNIC-compiled stage-2 payload from the WeedHack campaign. LoaderClient is distributed as a Minecraft Fabric mod and uses a technique called EtherHiding, storing its command-and-control URL inside an Ethereum smart contract on mainnet, making it immune to conventional domain takedowns, registrar seizures, and hosting provider intervention. The stage-2 payload, obtained from an earlier build of the C2 infrastructure, confirms that all business logic is compiled to native code via JNIC v3.7.0, with the Java classes serving as thin skeletons around LZMA2-compressed, ChaCha20-obfuscated native DLLs (x86-64 and AArch64). Stage-2 independently re-resolves C2 via the same Ethereum contract, performs privilege escalation through a CMSTP UAC bypass using JNA Win32 API calls, and bypasses SSL certificate validation to accept all certificates during C2 communication.
This analysis covers the WeedHack campaign’s origins and MaaS infrastructure, the LoaderClient execution chain, the Ethereum-based C2 protocol with RSA signature verification, the custom decS string obfuscation cipher, the stage-2 JNIC architecture and privilege escalation mechanics, and actionable detection and defense recommendations. All technical findings are backed by bytecode analysis of both stages.
Overview
LoaderClient is a stage-1 credential stealer from the WeedHack Malware-as-a-Service campaign. It is distributed as a Minecraft Fabric mod JAR targeting players running Minecraft 1.21. On execution, the malware harvests the victim’s Minecraft session including display name, account UUID, and live Microsoft OAuth access token, then queries an Ethereum smart contract to resolve its C2 URL, downloads a second-stage payload, and executes it entirely in memory.
The WeedHack campaign represents a convergence of consumer-grade malware, blockchain infrastructure abuse, and the unregulated ecosystem of third-party game modifications. Between January and June 2026, it compromised over 116,000 endpoints and produced more than 3,820 unique malicious JAR files. The MaaS platform’s pricing that is free for basic credential theft, $5/month for a full RAT and has commoditized advanced surveillance capabilities for personal disputes, peer-to-peer extortion, and cyberbullying among teenage operators.
This report integrates binary-level static analysis of both the stage-1 (LoaderClient) and stage-2 (Module.jar) payloads with campaign-level threat intelligence from McAfee, PolySwarm, CyberInsider, and independent researchers. The stage-2 sample was obtained from a cached build of the C2 infrastructure. Every technical claim is backed by bytecode evidence or live network verification.
| Metric | Value |
|---|---|
| Campaign name | WeedHack |
| Predecessor | Majanito (late 2025, developer handle “Majanito”) |
| Operational since | January 2026 |
| Total logged infections | 116,000+ unique endpoints |
| Daily infection rate | 2,000–3,000 new compromises |
| Discovered malicious JARs | 3,820+ unique files |
| Active staging domains | 10 current, 11 historical |
| Distribution URLs | 240+ unique malicious URLs |
| MaaS registered accounts | 850+ (Telegram channel) |
| Stage-1 sample | f91714f89616002c6c1411233470f58e74fad7cb5a7da6f77aa6082f5d2e8771.jar |
| Stage-2 sample | e7d1346153b49ce403687bbd0ddbf1db63de6808d64ea2812ea48ef0cfe7cf2a |


Why this matters: WeedHack has lowered the barrier to entry for malware operations to effectively zero. Traditional MaaS platforms cost $250–500/month; WeedHack offers equivalent capabilities for free or $5/month. The campaign’s 116,000+ infections demonstrate that targeting gaming communities with low-cost tooling produces volume that rivals enterprise-focused operations.
Threat Group Lineage and Timeline
From Majanito to WeedHack
WeedHack originated in late 2025 as a private, targeted credential stealer called Majanito, developed by a threat actor using the same handle. The early Majanito codebase was written in standard, uncompiled Java, which made it vulnerable to static reverse-engineering and signature-based detection. Analysis of the recovered stage-2 payload directly confirms this lineage: all operational classes are packaged under the dev.majanito namespace, meaning the original developer’s handle is preserved in the compiled codebase even after the WeedHack rebrand.
Rebrand and MaaS Expansion
In early 2026, the codebase underwent a change in ownership and was rebranded as WeedHack. The new operators made two strategic decisions that transformed the project from a private tool into a scalable operation. First, they transitioned the business model to a Malware-as-a-Service program hosted on the clearnet rather than underground dark-web markets. Second, they implemented the EtherHiding protocol using an Ethereum smart contract to store and rotate C2 URLs, giving the infrastructure takedown resistance that most commodity malware lacks.
C2 Rotation Through Ethereum
By March 2026, the campaign had established active C2 infrastructure resolving to whnewreceive[.]ru. The Ethereum contract has since been updated to resolve to fucktermedfir[.]st, demonstrating the operator’s ability to rotate infrastructure without recompiling or redistributing payloads.


Why this matters: The Majanito-to-WeedHack transition demonstrates how commodity malware codebases are recycled and professionalized. The adoption of EtherHiding, a technique previously associated with more sophisticated operations, signals that blockchain-based C2 is becoming accessible to mid-tier operators. Defenders should expect this pattern to repeat across other gaming-focused campaigns.
The WeedHack Malware-as-a-Service Platform

WeedHack operates as a commercially structured MaaS platform with tiered pricing, a centralized administration dashboard, and an active community of over 850 registered operators on Telegram. The platform’s business model is designed to maximize infections through a free tier that feeds stolen credentials into a centralized dashboard, while monetizing advanced capabilities through a premium tier.
WeedHack MaaS Feature Comparison
| Feature | Free Tier | Premium Tier ($5/mo or $24.99 Lifetime) | Traditional MaaS (Lumma, X-Worm) |
|---|---|---|---|
| Base cost | $0 (ad-supported / Discord verified) | $5.00/mo or $24.99 lifetime | $250–500/mo |
| Minecraft session theft | Yes | Yes + full account takeover | N/A |
| Browser credentials | 36 browsers | 36 browsers + real-time keylogger | Comparable |
| Crypto wallets | 56 browser + 12 desktop | + clipboard monitor + wallet swapping | Comparable |
| Communication tokens | Discord, Telegram, Steam | + account hijacking + payload spreading | Comparable |
| File system access | 24-keyword search | Full file browser (upload/download/delete) | Comparable |
| Surveillance | Single screenshot | Live webcam (25 FPS) + 720p screen-share | Variable |
| Remote control | None | cmd shell + mouse/keyboard | Comparable |


The premium tier’s webcam and screen-sharing modules use a windowless WebSocket handler (@ClientEndpoint) to compress video streams into WebP format at 0.85 quality, maintaining a 25 FPS transfer rate. The WebSocket C2 endpoints are wss://remotev2.whpayment[.]ru/ws/client (primary) and wss://remotev2.whreceive[.]ru/ws/client (backup).
The MaaS administration dashboard contains tutorials instructing operators on distribution best practices. Operators are told to avoid low-quality, AI-generated voice-overs in YouTube videos and instead use custom narrations, background audio, and high-definition overlays to mimic legitimate community developers.


Why this matters: The free tier acts as a wide-net distribution vector, flooding the centralized dashboard with stolen accounts and cryptocurrency profiles at no cost to operators. The premium tier monetizes interactive control. The suggestion system where subscribers vote on features like microphone access or ransomware transforms the platform into a collaborative development model where advanced surveillance capabilities are commoditized for personal disputes.
Initial Compromise and Social Engineering Vectors
WeedHack operators rely on two primary distribution methods: YouTube-driven search redirection and SEO poisoning. Both target the unregulated ecosystem of third-party Minecraft modifications, where players routinely download custom code from unofficial sources.
YouTube Distribution
Operators upload polished video showcases that review or demonstrate popular Minecraft mods, visual add-ons, or custom client launchers. These high-quality videos accumulate thousands of views before being flagged. Download links are placed in video descriptions and pinned comments, directing viewers to malicious JAR files.
SEO Poisoning and Fake Download Portals
For search engines, operators set up single-page web portals that mimic official download pages for open-source Minecraft clients that lack dedicated domains and are hosted on public repositories like GitHub. By targeting niche clients with unique names, the operators execute SEO poisoning and dominate search results for those terms.
Impersonated Minecraft Tools
| Impersonated Software | Original Legitimacy | Malicious Technique |
|---|---|---|
| Meteor Client, Wurst Client | Popular open-source utility modifications | Lookalike domains with copycat download portals |
| Radium Client, LiquidBounce | Optimization mods hosted on GitHub | Counterfeit wikis and poisoned search result headers |
| Impact, Future, Inertia Clients | Classic community movement clients | YouTube demo videos with description links |
| Skytils (SkyBlock mod) | Popular Hypixel game-mode mod | Counterfeit community Discord and download portals |
In typical infection scenarios, victims downloading these compromised JAR files ignore built-in operating system security warnings. Comments in YouTube video descriptions show players warning other community members that their browser or antivirus flagged the download as containing a Trojan. Because third-party mod tools often generate false positives, users regularly bypass these warnings, disable local defenses, and execute the payloads.


Why this matters: The distribution model exploits a structural weakness in the Minecraft modding ecosystem: players are conditioned to download and execute unsigned JARs from unofficial sources, and to dismiss antivirus warnings as false positives. This creates a reliable infection pipeline that requires no exploit code or vulnerability, only social engineering at scale.
Victimology and Target Demographics
WeedHack primarily targets Minecraft players, a demographic that skews toward teenagers and young adults. The campaign’s 116K+ logged infections span a global geographic distribution, driven by the universal popularity of Minecraft and the worldwide availability of mod-sharing communities.
The socioeconomic design of WeedHack has fostered a community of younger threat actors who use the malware for harassment and cyberbullying. The WeedHack Telegram channel has grown to over 850 registered members. Within this group, young threat actors share exfiltrated screenshots and webcam recordings captured from infected peers. Because the victims are often in the same age group, these operations are frequently used for online harassment, peer-to-peer extortion, and social media hijacking rather than purely financial theft.
The suggestions section on the WeedHack dashboard shows active involvement from its user base. Subscribers vote on future development goals, such as adding microphone access or ransomware features. This collaborative development model reflects a shift where advanced surveillance capabilities are commoditized for everyday personal disputes.
Why this matters: WeedHack redefines the threat actor demographic. These are not financially motivated cybercriminals or state-sponsored operators, they are teenagers weaponizing a $5 tool against peers. The combination of live webcam access, credential theft, and social media hijacking creates a cyberbullying vector that traditional security frameworks are not designed to address.
Current Status: Portals Down, Operators Still Active
While the majority of WeedHack’s public-facing portals and distribution pages have been taken offline, the campaign has not been neutralized. Operators who acquired WeedHack tooling whether through the free tier or paid subscriptions, continue to run independent campaigns using previously distributed payloads. The Ethereum smart contract remains active on mainnet, and the decentralized C2 architecture means that even without a central portal, any operator with an existing build can continue to receive stolen data.

Why this matters: The takedown of public distribution portals creates a false sense of security. The MaaS model means hundreds of independent operators already possess functional payloads. The blockchain-based C2 channel cannot be disrupted by taking down websites only by blocking Ethereum RPC traffic at the network level or by the operator losing access to the wallet that controls the smart contract. Defenders should treat WeedHack as an ongoing threat regardless of portal availability.
Technical Analysis
What Is LoaderClient?
LoaderClient is a staged Minecraft session credential stealer delivered as a Fabric mod JAR. It serves as the stage-1 payload in the WeedHack execution chain. On first execution triggered automatically by Fabric’s mod initialization sequence the malware queries an Ethereum smart contract to obtain its C2 URL, downloads a second-stage JAR over HTTPS, loads it entirely in memory, and invokes it with a JSON payload containing the victim’s Minecraft credentials.
Stage-1 Sample Metadata
| Field | Value |
|---|---|
| File name | f91714f89616002c6c1411233470f58e74fad7cb5a7da6f77aa6082f5d2e8771.jar |
| MD5 | D991A7C9E2C3B269975404405A79ADBC |
| SHA1 | F7911F5BE3D08DA95DCDA8AFB1BEB8E462376F9D |
| SHA256 | F91714F89616002C6C1411233470F58E74FAD7CB5A7DA6F77AA6082F5D2E8771 |
| File size | 1,356,407 bytes (1.29 MB; 442+ MB if zip bomb is decompressed) |
| File type | Java Archive (JAR / ZIP), magic 50 4B 03 04 |
| Platform | Minecraft 1.21, Fabric Loader ≥ 0.18.4, Java 21 |
| Class file version | 65.0 (Java 21) |
| Fabric mod name | Github |
| Fabric mod ID | github |
| Fabric mod version | 1.0.0 |
| Campaign UUID | 6fb0a044-eb0c-4d1f-b497-827b715590a7 |
| Bundled libraries | Google Gson, Google ErrorProne (compile-time), Fabric Loader 0.18.4 API |
Stage-1 Network and C2 Indicators
| Contact / IOC Type | Value |
|---|---|
| Ethereum contract (C2 anchor) | 0x1280a841Fbc1F883365d3C83122260E0b2995B74 |
| C2 domain (current) | fucktermedfir.st |
| Stage-2 URL | https://fucktermedfir.st/files/jar/module |
| Campaign UUID | 6fb0a044-eb0c-4d1f-b497-827b715590a7 |
| Ethereum RPC endpoints | 30 hardcoded public providers |
Why this matters: LoaderClient masquerades as a generic utility mod named “Github” with a plausible fabric.mod.json, CC0 license, and GitHub contact URLs. The mod has no declared legitimate functionality. The generic name and legitimate-looking metadata are designed to avoid suspicion during manual mod review.
Stage-2 Sample Analysis
The stage-2 payload is the JAR that LoaderClient downloads and executes in memory through the IMCL ClassLoader. This second-stage payload contains the deeper operational logic of the WeedHack infection chain.
Stage-2 Metadata
| Field | Value |
|---|---|
| SHA256 | E7D1346153B49CE403687BBD0DDBF1DB63DE6808D64EA2812EA48EF0CFE7CF2A |
| File size | 7,064,366 bytes (6.74 MB) |
| File type | Java Archive (JAR / ZIP), magic 50 4B 03 04 |
| Primary package | dev.majanito |
| JNIC version | 3.7.0 |
| JNIC native resource | dev/jnic/lib/dac261f0-fd12-4fb9-9a32-6a945ac10c4c.dat (462,875 bytes, encrypted) |
| Native payload entropy | 7.9996 bits/byte (encrypted/packed) |
| Entry point | dev.majanito.Main.initializeWeedhack(String) |
| Bundled libraries | JNA 5.x (multi-platform), OkHttp3, Okio, Kotlin stdlib, org.json |
| Total JAR entries | ~3,456 files |
| Custom file extension | .acdm (dropped configs) |
| Contact / IOC Type | Value |
|---|---|
| Ethereum contract | 0x1280a841Fbc1F883365d3C83122260E0b2995B74 (same as stage-1) |
| Function selector | 0xce6d41de (same as stage-1) |
| RSA public key | Identical to stage-1 |
| SSL validation | Disabled (trust-all-certs X509TrustManager) |
| DNS resolution | DNS-over-HTTPS via CloudflareDNS class |
The dev.majanito package name in the compiled code directly confirms the Majanito lineage described in the campaign timeline, the original developer’s handle is preserved in the stage-2 codebase even after the WeedHack rebrand.


LoaderClient Execution Chain
LoaderClient uses a two-stage architecture. The stage-1 JAR handles victim identification, C2 discovery, and stage-2 retrieval. The stage-2 JAR handles final data exfiltration. The full execution sequence proceeds through 19 discrete steps:
Execution Flow
- Victim installs the JAR as a Fabric mod (manually or via a compromised mod pack).
- Minecraft starts; Fabric invokes
com.github.LoaderClient.onInitialize(). LoaderClientcallsMinecraftClient.getInstance()to obtain the running game session.- From the session object, it extracts: display name (
method_1676()), account UUID (method_44717()), and OAuth access token (method_1674()). - These values are assembled into a
JsonObjectwith keys encrypted via thedecScipher. - A background thread spawns calling
StagingHelper.stageWithContext(ctx2). StagingHelperreadscfg.jsonfrom the JAR’s embedded resources, obtaining the campaign UUID.StagingHelperinstantiatesRPCHelperand callsgetVerifiedText("0x1280a841Fbc1F883365d3C83122260E0b2995B74").RPCHelperiterates up to 30 Ethereum mainnet RPC endpoints, postingeth_callJSON-RPC requests with function selector0xce6d41de.- The contract returns an ABI-encoded string:
<URL>|<RSA_BASE64_SIGNATURE>. RPCHelpersplits on the last|, verifies the URL against the hardcoded 2048-bit RSA public key usingSHA256withRSA, and returns the verified URL.StagingHelperappends/files/jar/moduleto the URL and callsdl(url), an HTTP GET returning raw bytes.StagingHelperaddsuserId(campaign UUID) to the context.- Downloaded bytes are parsed with
JarInputStream;.classfiles and resources go into in-memoryHashMapobjects. - An
IMCL(in-memory ClassLoader) is constructed with these maps. IMCL.loadClass(decS(...))loads the stage-2 entry class by its obfuscated name.- The class is instantiated via
getDeclaredConstructor().newInstance(). - A background thread calls
clazz.getMethod(decS(...), String.class).invoke(instance, Gson().toJson(context)). - Stage-2 receives the victim’s credentials as a JSON string. It independently re-resolves C2 via the same Ethereum contract, escalates privileges via
Helper.elevate(), and exfiltrates data viaTelemetryHelper.initTelemetry().
Operating Modes
| Mode | Entry Point | Trigger | Capabilities |
|---|---|---|---|
| Fabric mod | LoaderClient.onInitialize() | Minecraft launch with mod installed | Full session data (username, UUID, OAuth token) + staging |
| Standalone JAR | MEntrypoint.main() | Double-click or java -jar | Minimal context (no Minecraft data) + console-hiding relaunch via javaw.exe |
The standalone mode checks for a --jw argument. If absent, it relaunches itself using javaw.exe (the windowless Java runtime) with --jw appended, then calls System.exit(0) on the original process. This suppresses the console window. The standalone path builds a minimal context JSON and proceeds through the same StagingHelper pipeline.


Why this matters: The dual entry-point design gives the operator flexibility. The Fabric mod path is the primary attack vector for Minecraft players. The standalone path may serve as an alternate delivery vector for non-Minecraft targets or as an operator testing mechanism. Both paths converge on the same EtherHiding C2 resolution and in-memory staging pipeline.
Session Theft Process
LoaderClient.onInitialize() runs on Minecraft’s main thread as part of Fabric’s mod initialization sequence. It obtains the singleton MinecraftClient instance (Fabric intermediary name net.minecraft.class_310, method method_1551()) and retrieves the current Session object (method method_1548()).
Stolen Session Fields
The Session object in Minecraft 1.21 holds the player’s authentication state. Three getters are called:
| Field | Source Method (Intermediary) | Description |
|---|---|---|
| Display name | session.method_1676() | Minecraft username shown in-game |
| Account UUID | session.method_44717() | Mojang account UUID; "offline" substituted if null |
| Access token | session.method_1674() | Microsoft/Mojang OAuth access token |
| Campaign UUID | cfg.json embedded resource | Operator-assigned: 6fb0a044-eb0c-4d1f-b497-827b715590a7 |
All JSON property keys in the context object are encrypted with decS. The userId key is sent in plaintext, confirmed by bytecode. The assembled object is passed to StagingHelper.stageWithContext() on a background thread, ensuring data collection does not block Minecraft’s main thread or produce visible lag.
The access token is the most sensitive field. A valid Minecraft OAuth token can authenticate to Mojang’s API, access the victim’s Microsoft account services linked to their Minecraft profile, and purchase or transfer items. Token lifetime depends on the issuing authority (Microsoft) but typically spans hours to days.
Why this matters: The access token theft enables full account takeover. Unlike a stolen password (which 2FA can mitigate), a live OAuth token bypasses authentication entirely for the duration of its validity. The background-thread execution ensures victims see no lag or visual indication of compromise.
EtherHiding and Ethereum-Based C2 Resolution
The C2 architecture is the most operationally significant aspect of LoaderClient. Rather than embedding a server address or using a domain generation algorithm, the operator stores the live C2 URL inside an Ethereum smart contract on mainnet; a technique known as EtherHiding.
Ethereum Contract Details
| Parameter | Value |
|---|---|
| Contract address | 0x1280a841Fbc1F883365d3C83122260E0b2995B74 |
| Network | Ethereum Mainnet |
| Function selector | 0xce6d41de (probable function name: getText()) |
| Return format | <URL>|<base64_RSA_signature> |
| Verification algorithm | SHA256withRSA, 2048-bit key |
| RPC endpoint count | 30 hardcoded public providers |
| Current resolved URL | https://fucktermedfir[.]st |
| Previous URL (March 2026) | https://whnewreceive[.]ru |
RPCHelper.getVerifiedText() iterates the 30 hardcoded RPC endpoints sequentially. For each, it posts a standard JSON-RPC eth_call request:
{
"jsonrpc": "2.0",
"method": "eth_call",
"params": [
{"to": "0x1280a841Fbc1F883365d3C83122260E0b2995B74", "data": "0xce6d41de"},
"latest"
],
"id": 1
}
The contract returns an ABI-encoded string. The malware decodes it, splits on the last | character, and verifies the URL portion against the hardcoded RSA public key using SHA256withRSA. Live verification against eth.drpc.org confirmed the signature is valid for https://fucktermedfir[.]st.
Three properties make this C2 mechanism exceptionally resilient:
- Takedown-resistant. The Ethereum blockchain is immutable. No registrar, hosting provider, or law enforcement agency can modify or seize the contract’s stored value without a protocol-level action against the entire Ethereum network.
- Hijack-resistant. Even if a defender somehow modified the contract’s state, they cannot forge a valid RSA signature without the operator’s 2048-bit private key. The signature verification ensures the malware only trusts URLs the operator intentionally signed.
- RPC-resilient. Thirty hardcoded Ethereum RPC endpoints are tried sequentially. Blocking any one or even most of them does not prevent C2 resolution. The endpoints include major public providers:
eth.drpc.org,ethereum.publicnode.com,rpc.ankr.com/eth,cloudflare-eth.com,1rpc.io/eth, and 25 others.
The stage-2 download URL is constructed by appending /files/jar/module to the verified C2 URL. The stage-2 endpoint at https://fucktermedfir[.]st/files/jar/module is currently down.

Why this matters: EtherHiding fundamentally changes the defender’s playbook. The usual approach, seizing domains, issuing takedown notices, blocking IPs, is ineffective against the C2 channel itself. The contract at 0x1280a841Fbc1F883365d3C83122260E0b2995B74 will continue serving its URL for as long as Ethereum exists. The operator can update it at any time by submitting a transaction from the controlling wallet. The most durable network IOC is therefore the Ethereum contract address itself, it is immutable and unique to this operator.
Detection Evasion Techniques
LoaderClient employs five distinct evasion techniques:
1-Custom String Obfuscation
Every sensitive string literal, stage-2 class names, method names, JSON property keys and values is stored as two encrypted integer arrays and decoded at runtime by StagingHelper.decS(). The cipher produces non-ASCII Unicode characters that are legal Java identifiers under the Java Language Specification but render decompiler output unreadable. No plaintext sensitive strings exist for simple signature rules to match.
2-Zip Bomb Anti-Analysis (META-INF/README.txt)
The JAR contains a 442 MB zip bomb. Compressed size: ~665 KB. Decompressed size: ~442 MB. Compression ratio: ~663:1. Content: exclusively bytes 0x41 (‘A’) and 0x4F (‘O’). This serves two purposes: crashing or slowing analysis tools that eagerly decompress all JAR entries, and defeating upload-size-limited automated scanners such as VirusTotal (10 MB limit) that reject oversized files.

3- In-Memory Stage-2 Execution
The stage-2 JAR is never written to disk. StagingHelper downloads it into a byte[], parses it with JarInputStream in memory, extracts classes and resources into HashMap objects, and loads them via IMCL. From an OS-level perspective, no new file appears on disk and no new process is created. Endpoint detection tools that rely on file-creation events or process-spawn monitoring do not observe the stage-2 payload.
4- Console Suppression
In standalone mode, MEntrypoint.checkJVMLauncher() relaunches the JAR using javaw.exe instead of java.exe. javaw.exe is the Windows GUI-subsystem variant of the Java launcher and does not attach to a console window. A victim who double-clicks the JAR sees no command prompt flash.
5- Fake Mod Identity
The JAR presents as a Minecraft mod named “Github” (mod ID github, version 1.0.0). The fabric.mod.json includes a plausible description, GitHub contact URLs, and a CC0 license. The mod has no declared functionality beyond its malicious entry point.
Why this matters: The combination of string obfuscation, zip bomb anti-analysis, and fileless stage-2 execution creates a layered evasion strategy. No single detection approach covers all layers. Automated scanners may fail on the zip bomb; signature rules miss obfuscated strings; EDR file-monitoring misses the in-memory payload. Effective detection requires network-layer monitoring of Ethereum RPC calls the one step the malware cannot obfuscate.
How LoaderClient Downloads and Executes Stage-2 In Memory
StagingHelper.stageWithContext() implements a staged execution protocol with internal checkpoints labeled S0 through S7:
| Stage | Operation | Detail |
|---|---|---|
| S0 | Config read | Reads cfg.json from JAR resources via getClass().getResourceAsStream("cfg.json"); extracts campaign UUID |
| S1 | HTTP download | dl(url): HTTP GET using java.net.HttpURLConnection; returns raw byte[] if status 200, null otherwise |
| S2 | JAR parsing | JarInputStream wraps downloaded bytes; .class entries → classMap: HashMap<String, byte[]>; all others → resourceMap |
| S3 | Validation | If classMap is empty (download failed), prints "Resource state: S3" and returns the only user-visible output |
| S4 | ClassLoader | Constructs IMCL(classMap, resourceMap); calls loadClass(decS(...)) with obfuscated stage-2 class name |
| S5 | Instantiation | getDeclaredConstructor().newInstance(): creates stage-2 instance |
| S6/S7 | Invocation | Background thread calls clazz.getMethod(decS(...), String.class).invoke(instance, Gson().toJson(context)) |
The IMCL class extends ClassLoader and overrides two methods:
findClass(String name): looks up class bytes from the in-memoryMapand callsdefineClass()to load them into the JVM.getResourceAsStream(String name): returns aByteArrayInputStreamwrapping resource bytes from the resource map.
Stage-2 receives a single JSON string argument containing all victim data. Both the entry class name and the invoked method name are products of decS(): they consist of non-ASCII Unicode characters. The stage-2 JAR must have been compiled to match these exact names, confirming the operator produced both stages.
Stage-2 Architecture: JNIC Native Compilation
Analysis of the recovered stage-2 payload confirms that all business logic is compiled to native code using JNIC v3.7.0 (Java Native Interface Compiler). The Java .class files under dev.majanito retain method names, signatures, and access modifiers (critical for RegisterNatives registration), but all method bodies are replaced with native stubs, each class contains $jnicLoader and $jnicClinit hooks that delegate execution to the LZMA2-compressed and XOR-obfuscated native DLL at runtime. Standard Java decompilers (JD-GUI, CFR, Procyon) can recover the method signatures but not the implementation logic. By parsing the class file method tables directly, all 56 native method names were extracted and validated against the DLL’s RegisterNatives counts.


The native payload is stored as an LZMA2-compressed resource at dev/jnic/lib/dac261f0-fd12-4fb9-9a32-6a945ac10c4c.dat (462,875 bytes, Shannon entropy 7.9996 bits/byte). The first bytes (E3 8C 94 FF) do not match any standard file signature (not PE, ELF, or ZIP). The first byte 0xE3 is a valid LZMA2 chunk control byte (bit 7 = LZMA compressed chunk, bits 5–6 = full state/properties/dictionary reset) confirmed by successful raw LZMA2 decompression. JNIC compresses the platform-specific DLLs into a single resource bundle without a recognizable magic header. The JNICLoader class implements a custom InputStream that wraps LZMA2 decompression: it reads the .dat from the JAR, skips to a platform-specific offset using skip(), writes the target DLL bytes to a createTempFile() output, loads the result via System.load(), and marks it for deletion via deleteOnExit(). Platform detection uses os.name and os.arch to select the correct offset within the compressed stream (x86_64 or aarch64).


JNIC Payload Decompression. Decompressing the .dat with LZMA2 (raw format, 64 MB dictionary) yields a 1,583,616-byte buffer containing two concatenated Windows DLLs:
| DLL | Architecture | File Size | Image Size | PE Sections |
|---|---|---|---|---|
lib_win_x86_64.dll | x86-64 | 837,120 bytes | 868,352 bytes | 7 (.text, .rdata, .buildid, .data, .pdata, .tls, .reloc) |
lib_win_aarch64.dll | AArch64 | 746,496 bytes | 770,048 bytes | 7 |

Both DLLs are compiled with MinGW-w64 (confirmed by runtime error strings: Mingw-w64 runtime failure, Unknown pseudo relocation). Each exports 11 JNI functions one $jnicLoader per dev.majanito class plus JNI_OnLoad:
JNI_OnLoad
Java_dev_majanito_CloudflareDNS__00024jnicLoader
Java_dev_majanito_CloudflareDNS_000241__00024jnicLoader
Java_dev_majanito_CloudflareDNS_000242__00024jnicLoader
Java_dev_majanito_CloudflareDNS_00024CacheEntry__00024jnicLoader
Java_dev_majanito_Helper__00024jnicLoader
Java_dev_majanito_IMCL__00024jnicLoader
Java_dev_majanito_LogHelper__00024jnicLoader
Java_dev_majanito_Main__00024jnicLoader
Java_dev_majanito_RPCHelper__00024jnicLoader
Java_dev_majanito_TelemetryHelper__00024jnicLoader
Each $jnicLoader export calls RegisterNatives to map the Java method stubs to their native implementations. The .rdata section confirms the embedded version string jnic.dev v3.7.0 and the class path dev/jnic/nVmYuM/JNICLoader matching exactly what the Java-level JNICLoader.class references.

RegisterNatives Validation. Binary analysis of each $jnicLoader function confirms the RegisterNatives call (JNI function table offset 0x6B8) and the method count passed in register r9d. Cross-referencing these counts against the Java class file method tables (parsed directly from the stage-2 JAR) produces an exact match for all 10 classes 56 native methods total:
| Class | RegisterNatives Count | Native Methods (from .class file) |
|---|---|---|
Helper | 19 | elevate, isElevated, deleteConfigs, kill, createConfig, run, simulatePressEnter, doSystem, getFileContents, getStartCommand (x2 overloads), getCurrentJar, downloadElevatorToDisk, getJavaExecutable, randomString, lambda$run$2, lambda$deleteConfigs$1, lambda$deleteConfigs$0, + <clinit> body |
CloudflareDNS | 10 | getClient, getClientForHost, resolve, queryDoH, execute, downloadBytes, post, lambda$getClientForHost$1, lambda$getClientForHost$0, + <clinit> body |
Main | 8 | uncacheRestrictedHeaders, extractJnaNative, main, initializeWeedhack, initializeWeedhack2, addMagic, lambda$main$0, + <clinit> body |
RPCHelper | 5 | getVerifiedText, callGetText, decodeAbiString, verifyRsaSignature, + <clinit> body |
LogHelper | 4 | sendLogs, readFile, getHostname, + <clinit> body |
CloudflareDNS$1 | 3 | checkClientTrusted, checkServerTrusted, getAcceptedIssuers |
CloudflareDNS$2 | 3 | checkClientTrusted, checkServerTrusted, getAcceptedIssuers |
IMCL | 2 | findClass, getResourceAsStream |
TelemetryHelper | 1 | initTelemetry |
CloudflareDNS$CacheEntry | 1 | isValid |
JNIC registers the <clinit> (static initializer) body as a native method when the class has a $jnicClinit hook, explaining why RegisterNatives counts are one higher than the visible native method count for classes with static initialization logic.


Native Function Mapping. Each $jnicLoader loads function pointers via RIP-relative LEA instructions into .text section addresses before calling RegisterNatives. Since these pointers are loaded in the same order as the methods appear in the Java class file, every native method maps to a specific DLL entry point. The five largest functions reveal where the critical functionality resides:
| Function | Method Name | Size | .rdata Refs | Behavioral Tags |
|---|---|---|---|---|
0x0883E0 | Main.addMagic() | 62,528 bytes | 13 | Persistence / evasion — largest function in the DLL |
0x00FD80 | LogHelper.sendLogs(String) | 63,472 bytes | 61 | Data exfiltration — 61 encrypted strings = credential paths, browser profiles, wallet locations |
0x07B1A0 | Main.initializeWeedhack2(String) | 53,824 bytes | 22 | Second initialization path with heavy array processing |
0x043C50 | Helper.run() | 50,528 bytes | 24 | Main Helper execution driver — orchestrates UAC bypass, config, persistence |
0x0384E0 | Helper.createConfig(String[]) | 46,960 bytes | 19 | Configuration/persistence setup with array and object manipulation |
Three methods not visible from initial JADX stub review are particularly significant:
Main.addMagic()at 62.5 KB, this is the persistence and evasion function. The name “addMagic” is consistent with installing scheduled tasks (JMonitoringTask, JavaSecurityUpdater), adding Windows Defender exclusion paths, and establishing the double-watchdog mechanism documented in stage-3 threat intelligence.Main.initializeWeedhack2(String)a second, much larger initialization variant (53.8 KB vsinitializeWeedhackat 2 KB), suggesting a different code path for standalone vs Fabric mod execution.Helper.run()at 50.5 KB with 24 encrypted string references, this is the primary Helper execution flow that orchestrates privilege escalation, process manipulation, and system configuration.
The DLL imports only 23 functions total all through the IAT: VirtualProtect, VirtualQuery, Sleep, TlsGetValue, critical section operations (Initialize, Enter, Leave, Delete), CRT heap (malloc, calloc, free), CRT I/O (fwrite, __stdio_common_vfprintf), CRT string (strncmp), and MinGW runtime init. All higher-level Windows API interaction (process enumeration, file I/O, registry access, network operations) is routed through JNA via JNI callbacks the native code calls back into Java to call JNA, which then calls Win32 APIs. This indirect call chain makes static analysis extremely difficult because the actual Win32 API usage is hidden behind multiple layers of JNI indirection.
Native String Obfuscation ChaCha20 Keystream Recovery. All hardcoded strings inside the native DLL (class names, method names, signatures, URLs, credential paths) are encrypted with a modified ChaCha20 keystream cipher. Full static recovery of the ChaCha20 state was achieved by combining binary analysis of JNI_OnLoad (RVA 0xB3600) with Java bytecode disassembly of the JNICLoader.<clinit> method yielding the complete 512-bit cipher state and enabling offline decryption of 78+ unique strings without executing the malware.
ChaCha20 State Recovery:
| State Row | Source | Value |
|---|---|---|
| Row 0 (constant) | .data global → .rdata at 0xB7A60 | 0x696E6A20 0x65642E63 0x33762076 0x302E372E = " jnic.dev v3.7.0" |
| Row 1 (key words 0–3) | .rdata at file 0xB7A40 via MOVAPS | 0x9C34E807 0x6BDF47A0 0x39BEC0CF 0xC9CCE2C8 |
| Row 2 (key words 4–7) | .rdata at file 0xB7A50 via MOVAPS | 0x26C90E48 0xDE07E50E 0xFF5F427E 0x68E91DAE |
| Row 3 (counter + nonce) | Counter = 0; nonce from JNICLoader.class <clinit> | 0x00000000 0xB76313CC 0x1D93DDB1 0x0C56FF6C |
JNIC v3.7.0 replaces the standard ChaCha20 constant "expand 32-byte k" with its own version string " jnic.dev v3.7.0" a non-standard modification that breaks compatibility with standard ChaCha20 implementations. The 256-bit key is embedded in the .rdata section (16 bytes at file offsets 0xB7A40 and 0xB7A50), loaded via two MOVAPS instructions during JNI_OnLoad initialization.

Nonce Recovery. The nonce was initially assessed as runtime-dependent because JNI_OnLoad retrieves it via GetDirectBufferAddress from a Java ByteBuffer object. However, disassembly of the JNICLoader.<clinit> Java bytecode (class dev/jnic/nVmYuM/JNICLoader, version 51.0) revealed that the ByteBuffer is pre-populated with deterministic values before System.load() triggers JNI_OnLoad:
ByteBuffer.allocateDirect(64).order(LITTLE_ENDIAN) // static field 'z'
z.putInt(0xB781207F) // offset 0x00 key material (unused by JNI_OnLoad row setup)
z.putInt(0x4E05B187) // offset 0x04
... // 8 total putInt calls for key/config data
z.putInt(0xB76313CC) // offset 0x20 → nonce word 0 (read by JNI_OnLoad as [rax+0x20])
z.putInt(0x1D93DDB1) // offset 0x24 → nonce word 1
z.putInt(0x0C56FF6C) // offset 0x28 → nonce word 2
System.load(dllPath) // triggers JNI_OnLoad
The <clinit> contains platform-specific branches: the values above apply to win + x86_64/amd64. A separate branch exists for win + aarch64 with different key/nonce values (0x8D1EDBD3, 0xD9A336B0, …), indicating per-architecture obfuscation keys.

Keystream Generation. JNI_OnLoad allocates a 70,029-byte buffer (malloc(0x1118D)), stores the pointer in a global variable (.data RVA 0xCE039), then generates the full keystream using scalar ChaCha20 (10 double-rounds per 64-byte block, 1,095 blocks total). Each string decryption wrapper function loads a byte from the keystream at a specific offset, applies an arithmetic operation (XOR, ADD, or SUB varied per-byte as anti-pattern obfuscation), and stores the plaintext character. Wrapper results are cached in per-string global variables (one-time decryption).

The decrypted imports confirm the malware’s operational architecture: OkHttp3 for HTTP C2, JNA (com/sun/jna/Pointer) for direct Win32 API access, javax.crypto.Cipher for payload encryption, java.security.Signature for RSA C2 verification, ProcessBuilder for command execution, JSONObject for C2 protocol parsing, and ClassLoader for in-memory stage-3 loading. The okhttp3/Dns import confirms custom DNS resolution (DoH) at the native level.
The stage-2 JAR contains seven top-level operational classes plus three inner classes (10 JNIC-compiled classes total) with 56 native methods (validated via RegisterNatives binary analysis):
| Class | Role |
|---|---|
Main | Entry point — main(String[]) orchestrates the full attack chain (44.6 KB); initializeWeedhack(String) and initializeWeedhack2(String) provide two initialization paths (standalone vs Fabric mod — 2 KB and 53.8 KB respectively); addMagic() installs persistence and evasion (62.5 KB — largest function in the DLL); extractJnaNative() unpacks JNA at runtime; uncacheRestrictedHeaders() disables Java HTTP restrictions; lambda$main$0 is an uncaught exception handler |
Helper | Privilege escalation and system manipulation — elevate(String[]) implements CMSTP UAC bypass (17.5 KB); isElevated() checks admin status; run() is the primary execution driver (50.5 KB); createConfig(String[]) sets up persistent configuration (47 KB); deleteConfigs() removes traces; downloadElevatorToDisk() fetches the UAC bypass payload (16.9 KB, byte array operations); simulatePressEnter(HWND) sends VK_ENTER to UAC prompt via JNA; kill() terminates processes (16.1 KB); doSystem(String) runs system commands; getFileContents(String) reads arbitrary files; getStartCommand() (2 overloads) builds relaunch commands; getCurrentJar() locates the running JAR (36.4 KB); getJavaExecutable() finds the Java runtime; randomString(int) generates random filenames |
RPCHelper | EtherHiding C2 — identical protocol to stage-1 with the same RSA public key and Ethereum selector (0xce6d41de), confirming the same operator controls both stages; getVerifiedText(String) is the public API (17.2 KB); decodeAbiString(String) has 17 .rdata string references for ABI parsing |
CloudflareDNS | DNS-over-HTTPS resolver — resolve(String) handles DoH queries; queryDoH(String, String) implements the DNS protocol (19 KB); getClient() / getClientForHost() build OkHttp clients; downloadBytes(String) and post() handle HTTP I/O; execute(Request$Builder) wraps OkHttp execution; lambda$getClientForHost$1 returns true for all SSL sessions (hostname verifier bypass) |
CloudflareDNS$1/$2 | SSL certificate validation bypass — implements X509TrustManager with empty checkClientTrusted() and checkServerTrusted() methods, accepting all certificates; getAcceptedIssuers() returns empty array |
LogHelper | Reconnaissance and exfiltration — sendLogs(String) is 63.5 KB with 61 encrypted string references (the largest .rdata footprint in the DLL — these are the credential paths, browser profiles, and wallet locations); readFile(File) reads arbitrary files (8.6 KB); getHostname() collects host info |
TelemetryHelper | Exfiltration — initTelemetry(String) sends Base64-decoded stolen data to the exfil server (32.4 KB) |
IMCL | In-memory ClassLoader — findClass(String) and getResourceAsStream(String) enable recursive in-memory loading of stage-3 |
CloudflareDNS$CacheEntry | Cache TTL — isValid() checks entry expiry |

The Helper class the most method-rich class with 19 native implementations imports JNA Win32 types (PROCESSENTRY32, HANDLE, HWND, STARTUPINFO, PROCESS_INFORMATION, SECURITY_ATTRIBUTES) to interact with the Windows API directly via JNI-to-JNA callbacks bypassing cmd.exe and avoiding command-line logging. The HWND_BOTTOM and VK_ENTER constants confirm that the CMSTP UAC bypass (elevate(), 17.5 KB) works by locating the elevation prompt window, repositioning it off-screen, and programmatically pressing Enter (simulatePressEnter(HWND), 2.7 KB) to approve it without the victim’s knowledge. The run() method (50.5 KB with 24 encrypted string references) orchestrates the full Helper execution flow, while createConfig() (47 KB) and deleteConfigs() (14.5 KB) manage persistent configuration with filesystem path-walking (evidenced by lambda bodies lambda$deleteConfigs$0 and lambda$deleteConfigs$1 that accept Path arguments).

The CloudflareDNS class implements a custom DNS-over-HTTPS (DoH) client built on OkHttp3 with per-host caching (CacheEntry with TTL expiry). By resolving domains through DoH endpoints rather than the system DNS resolver, the malware evades corporate DNS monitoring and DNS-based blocking. The DoH URLs and RPC endpoint list are stored inside the encrypted JNIC native payload they do not appear as plaintext strings in the JAR.
Stage-2 independently re-resolves the C2 URL via the same Ethereum contract that stage-1 uses. This means that even if stage-1 is removed from the system, stage-2 can recover its C2 channel on its own. The presence of an IMCL ClassLoader in stage-2 confirms that the execution chain can continue to stage-3 using the same in-memory loading pattern each stage is self-sufficient for C2 resolution and capable of loading the next.

Why this matters: The in-memory execution model eliminates disk-based forensic artifacts entirely. While the JNIC .dat payload is merely LZMA2-compressed (and can be decompressed to extract platform DLLs), the native code within uses ChaCha20 keystream XOR to hide all operational strings URLs, RPC endpoints, credential paths, API keys from static analysis. Recovering these strings requires either Ghidra-based constant folding after marking the keystream buffer, or dynamic interception at JNI_OnLoad. The SSL certificate bypass and DNS-over-HTTPS together neutralize two of the most common corporate network defenses: TLS inspection and DNS monitoring. The only reliable detection point remains Ethereum RPC traffic from non-blockchain applications.
Advanced String Obfuscation Cryptography
StagingHelper.decS(int[] a, int[] b, int k1, int k2) is a custom symmetric stream cipher. All calls in the sample use k1=187, k2=67. The cipher produces non-ASCII Unicode characters that serve as valid Java identifiers.
Step 1 Interleave. Construct a merged byte array by interleaving elements: merged = [a[0], b[0], a[1], b[1], ...]. Total length: len(a) + len(b).
Step 2 S-box construction. Build a 256-element substitution table: S[j] = (j * 47 + 131) mod 256. Build inverse table T where T[S[i]] = i.
Step 3 Keystream and decode. For each byte merged[i]:
- Update state:
state = (state * 31 + i * 17) mod 256(initial state = 0) - Compute keystream index:
x = (k1 + state + i * 7) mod 256 - XOR with previous byte:
c = merged[i] XOR merged[i-1](usek1for i=0) - Left-rotate
cby(i * 3 + k2) mod 8bits - Inverse S-box lookup:
T[rotated] - Final decode:
decoded = T[rotated] XOR x XOR k2 - Append
(char) decodedto output string
The cipher is not a standard algorithm. The rotation step and inverse-S-box together defeat simple frequency analysis. The non-ASCII output is deliberate: it produces valid but visually opaque Java identifiers that break decompiler readability.
This same obfuscation function is used across the WeedHack campaign under the name Helper.load(int d1, int d2, int k1, int k2) in other samples, with identical mathematical construction.

Why this matters: The decS cipher ensures that static string extraction the most basic malware analysis technique yields nothing useful. Analysts must either reverse-engineer the cipher and run it against extracted byte arrays, or obtain the stage-2 JAR for cross-reference. The cipher parameters (k1=187, k2=67) serve as a campaign-level fingerprint: any sample using these constants with the same algorithm belongs to the WeedHack operation.
Why LoaderClient Matters
- Blockchain C2 is now commodity-grade. LoaderClient demonstrates that EtherHiding is no longer exclusive to sophisticated threat actors. A MaaS campaign targeting Minecraft players has adopted the same takedown-resistant infrastructure previously associated with advanced operations. Defenders should expect this to become standard in commodity malware.
- The barrier to entry is effectively zero. WeedHack’s free tier gives any teenager with a Discord account access to credential theft across 36 browsers, 56 crypto wallets, and multiple communication platforms. The $5/month premium tier adds live webcam access, keylogging, and remote shell. This is cheaper than a Netflix subscription.
- Gaming communities are high-value targets. The Minecraft modding ecosystem’s structural reliance on unsigned JARs from unofficial sources creates a permanent social engineering surface. WeedHack’s 116,464+ infections prove this surface is exploitable at scale without any vulnerability or exploit code.
- In-memory execution defeats standard EDR. The stage-2 payload never touches disk during delivery. Once loaded, its business logic runs from an encrypted JNIC native DLL extracted to a temp file and marked for deletion combining Java-level filelessness with native-level obfuscation. Detection must happen at the network layer.
- Stage-2 is self-sufficient. Analysis of the recovered stage-2 confirms it independently re-resolves C2 via the same Ethereum contract, carries its own IMCL ClassLoader for further staging, bypasses SSL certificate validation, and uses DNS-over-HTTPS to evade DNS monitoring. Even if stage-1 is removed, stage-2 can operate autonomously.
- The operator maintains durable control. The RSA signature binding means a defender cannot redirect the malware fleet to a sinkhole even if the Ethereum contract were somehow modified. The operator’s 2048-bit private key is the only authority the malware trusts. The same RSA key appears in both stage-1 and stage-2, confirming single-operator control across the entire execution chain.
- OPSEC failure: the Ethereum contract is a permanent fingerprint. The contract address
0x1280a841Fbc1F883365d3C83122260E0b2995B74is immutable and unique. It links all WeedHack variants that reference it, and its transaction history on Etherscan reveals the operator’s wallet and URL rotation timeline. This is the single most valuable IOC for tracking the campaign.
Indicators of Compromise (IOCs)
File-Based Indicators
| Type | Value |
|---|---|
| SHA256 | F91714F89616002C6C1411233470F58E74FAD7CB5A7DA6F77AA6082F5D2E8771 |
| SHA1 | F7911F5BE3D08DA95DCDA8AFB1BEB8E462376F9D |
| MD5 | D991A7C9E2C3B269975404405A79ADBC |
| JAR entry | META-INF/README.txt |
| JAR entry | cfg.json |
| Stage-2 | |
| SHA256 | E7D1346153B49CE403687BBD0DDBF1DB63DE6808D64EA2812EA48EF0CFE7CF2A |
| Resource | dev/jnic/lib/dac261f0-fd12-4fb9-9a32-6a945ac10c4c.dat |
| Extension | .acdm |
Network Indicators
| Type | Value |
|---|---|
| Ethereum contract | 0x1280a841Fbc1F883365d3C83122260E0b2995B74 |
| Domain | fucktermedfir[.]st |
| Domain | whnewreceive[.]ru |
| URL | https://fucktermedfir[.]st/files/jar/module |
| WebSocket | wss://remotev2.whpayment[.]ru/ws/client |
| WebSocket | wss://remotev2.whreceive[.]ru/ws/client |
| Exfiltration | telemetrydata[.]to |
| IPv4 | 45.141.119.34 (Port 50169) |
Host-Based Indicators
| Artifact | Location |
|---|---|
| Dropped backdoor | %APPDATA%\Roaming\RuntimeBroker.exe |
| Dropped stealer | %APPDATA%\Roaming\Microsoft\Tlmtry\Telemetry.exe |
| Backup payload | %APPDATA%\Roaming\WindowsRunetimeBroker.exe |
| Native DLL | %TEMP%\lib*.dll |
| Config file | %TEMP%\*.acdm |
| Registry key | HKCU\Software\Microsoft\Windows\CurrentVersion\Run |
| Scheduled task | JMonitoringTask (every 2 minutes) |
| Scheduled task | JavaSecurityUpdater (ONLOGON, HIGHEST privilege) |
Yara Rules
Stage-1: LoaderClient Fabric Mod
rule WeedHack_LoaderClient_Stage1
{
meta:
description = "WeedHack LoaderClient Stage-1 Minecraft Stealer Yara Rule"
author = "Dark Atlas; @ELJoOker"
date = "2026-06-17"
strings:
$s0 = "0x1280a841Fbc1F883365d3C83122260E0b2995B74" ascii
$s1 = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA" ascii
$s2 = "6fb0a044-eb0c-4d1f-b497-827b715590a7" ascii
$s3 = "com/github/StagingHelper" ascii
$s4 = "com/github/RPCHelper" ascii
$s5 = "com/github/IMCL" ascii
$s6 = "/files/jar/module" ascii
$s7 = "cfg.json" ascii
$s8 = "0xce6d41de" ascii
$s9 = "loaderclient" ascii
condition:
uint16(0) == 0x4B50 and
(
$s0 or
($s1 and $s2) or
($s3 and $s4 and $s5) or
($s8 and $s9) or
($s6 and $s7 and $s9)
)
}
Stage-2: Module.jar and Extracted Native DLLs
rule WeedHack_Module_Stage2
{
meta:
description = "WeedHack JNIC-Compiled Stage-2 Payload Yara Rule"
author = "Dark Atlas; @ELJoOker"
date = "2026-06-17"
strings:
$s0 = "dev/majanito/Main" ascii
$s1 = "dev/majanito/Helper" ascii
$s2 = "dev/majanito/RPCHelper" ascii
$s3 = "dev/jnic/nVmYuM/JNICLoader" ascii
$s4 = "dac261f0-fd12-4fb9-9a32-6a945ac10c4c" ascii
$s5 = "Java_dev_majanito_Helper__00024jnicLoader" ascii
$s6 = "Java_dev_majanito_RPCHelper__00024jnicLoader" ascii
$s7 = "Java_dev_majanito_Main__00024jnicLoader" ascii
$s8 = "jnic.dev v3.7.0" ascii
$s9 = "Mingw-w64 runtime failure" ascii
condition:
(
uint16(0) == 0x4B50 and
(
($s0 and $s1 and $s2) or
($s3 and $s4)
)
)
or
(
uint16(0) == 0x5A4D and
($s5 or $s6 or $s7) and
$s8 and
$s9
)
}
FAQ
What is LoaderClient malware?
LoaderClient is a Minecraft-based malware loader that steals session credentials, resolves its C2 server through an Ethereum smart contract, and downloads a second-stage payload in memory.
What is WeedHack?
WeedHack is a Malware-as-a-Service campaign that distributes credential stealers and RATs disguised as Minecraft mods and optimization clients.
What is EtherHiding?
EtherHiding is a technique where malware stores or retrieves C2 information from a blockchain smart contract. In this case, LoaderClient uses an Ethereum smart contract to retrieve its active C2 URL.
Why does LoaderClient use Ethereum?
LoaderClient uses Ethereum because a smart contract is difficult to remove or seize. This makes the C2 channel more resilient than a normal hardcoded domain.
How does LoaderClient evade detection?
LoaderClient uses string obfuscation, a zip bomb, fake mod metadata, console suppression, and in-memory stage-2 execution.
Who is targeted by WeedHack?
The campaign primarily targets Minecraft players, especially users who download third-party mods or optimization clients from unofficial sources.
What is the most important IOC?
The most important IOC is the Ethereum contract address: 0x1280a841Fbc1F883365d3C83122260E0b2995B74.
How can organizations defend against LoaderClient?
Organizations can block unnecessary Ethereum RPC traffic, monitor Java processes, restrict unofficial mod downloads, inspect suspicious Fabric mods, deploy YARA detections, and rotate credentials after suspected infection.
Conclusion
LoaderClient is a multi-stage Minecraft credential stealer that uses an Ethereum smart contract for takedown-resistant C2 resolution. Stage-1 harvests session tokens and downloads a stage-2 payload entirely in memory. Stage-2 packaged under the dev.majanito namespace and compiled to native code via JNIC v3.7.0 independently re-resolves C2 via the same Ethereum contract, escalates privileges through a CMSTP UAC bypass using JNA Win32 API calls, bypasses SSL certificate validation, and resolves domains through DNS-over-HTTPS to evade network monitoring. Both stages share the same RSA public key and Ethereum selector, and both carry an IMCL ClassLoader capable of loading further stages in memory. The campaign has compromised over 116,000 endpoints since January 2026 by weaponizing the Minecraft modding ecosystem through YouTube social engineering and SEO poisoning.
Three immediate defender actions:
- Block Ethereum RPC traffic from gaming and educational networks. This is the single most effective disruption point it breaks the C2 discovery chain regardless of domain rotation. No legitimate Minecraft activity requires blockchain RPC calls.
- Monitor the Ethereum contract
0x1280a841Fbc1F883365d3C83122260E0b2995B74on Etherscan for transaction history. Every URL rotation the operator performs leaves a permanent, public record. This is the most durable IOC in the entire campaign it cannot be changed or deleted. - Deploy the YARA rule and coordinate credential rotation for any environment where Minecraft mods are used. The stolen OAuth tokens have a limited lifetime, but the window is sufficient for account takeover. Credential rotation must happen alongside malware removal, not after.
The most valuable finding from this analysis is the Ethereum contract address itself. It is immutable, unique to this operator, and links every WeedHack variant that references it. Combined with Etherscan transaction history, it provides a complete timeline of the operator’s infrastructure rotation an OPSEC failure that turns the campaign’s greatest strength (blockchain permanence) into its most exploitable weakness.