Mod Analysis & Detections
A practical reference for identifying suspicious, disguised, or unfair Minecraft mods through trust validation, metadata review, mixin analysis, decompilation, and behavioral triage.
What Mod Analysis Actually Proves
To analyze unfair mods properly, it helps to think like the player trying to hide one. Most users are not building custom clients from scratch — they are downloading a jar, renaming it, bundling it into something else, or relying on a loader that makes the whole thing look normal. Mod analysis is therefore not just "is this file weird?" The real question is whether the file's claimed identity, technical behavior, and level of concealment all line up. If those three things do not match, you have something worth escalating.
In practice, mod analysis tries to answer four core questions: what the jar claims to be, whether the file is authentic, whether it can provide an unfair advantage, and whether it was built to hide that fact.
| Source | What to Check | Why It Matters |
|---|---|---|
| Jar name and version | Branding, claimed purpose, loader version, release naming convention | Useful for first-pass context, but very easy to fake |
| Hash | SHA-256 or SHA-512 compared to an official source | A mismatch is one of the strongest single authenticity failures |
| Loader metadata | fabric.mod.json, mods.toml, mcmod.info, manifest data | Shows what the mod claims about itself and how it loads |
| Mixin configs | Targets, injectors, overwritten methods, package layout | Often exposes real intent faster than class names do |
| Decompiled code | Combat, input, network, timing, GUI, config handling | Primary source for proving actual capability |
| Resources and configs | Icons, hidden modules, keybinds, default settings, language keys | Can expose module names even when code is heavily obfuscated |
| Embedded libraries | Shaded jars, native files, custom loaders, decryptors | May reveal second-stage payloads or bundled frameworks |
| Runtime behavior | New files, network requests, overlays, toggles, packet changes | Confirms how the mod behaves when actually loaded |
We are reporters. We document indicators, explain why they matter, and preserve confidence levels. We do not need to overstate. A clean report with moderate confidence is better than a dramatic report built on guesses.
Classification of Suspicious Mods
A useful way to classify suspicious jars is to separate visibility from readability. Some clients are obvious and essentially admit what they are. Others hide behind a normal name, a copied icon, or a legitimate project. Others go one step further and make the code deliberately painful to read. This gives you three common groups in actual casework — each can still be unfair; the difference is how much work it takes to prove.
Unknown does not equal malicious, and obfuscated does not equal cheat. What matters is capability, concealment, and inconsistency between the jar's story and the jar's behavior.
Trust Validation Before Reverse Engineering
Before pulling classes apart, verify whether the jar is even authentic. A significant amount of time gets wasted reverse engineering files that could have been flagged in the first two minutes by hash comparison alone. Players can rename a jar in five seconds — they can also repackage a legitimate project with added code. Trust validation is what separates a cosmetic rename from an actually altered build.
For Fabric projects, fabric.mod.json is the primary metadata file, defining the mod ID, version, and entrypoints. For Forge, mods.toml under META-INF fills that role. These files tell you what the jar claims to be and how it expects to load.
# Step 1: Hash every jar in the mods folder $modsPath = "$env:APPDATA\.minecraft\mods" Get-ChildItem $modsPath -Filter *.jar | Get-FileHash -Algorithm SHA256 | Sort-Object Path | Select-Object Path, Hash # Step 2: Unpack jar for inspection # A .jar is a ZIP archive — rename or extract directly Expand-Archive "suspect.jar" -DestinationPath ".\unpacked\" -Force # Step 3: Read loader metadata Get-Content ".\unpacked\fabric.mod.json" # Fabric Get-Content ".\unpacked\META-INF\mods.toml" # Forge Get-Content ".\unpacked\META-INF\MANIFEST.MF" # Manifest # Step 4: List mixin configuration files Get-ChildItem ".\unpacked" -Filter *.json -Recurse | Where-Object { $_.Name -match 'mixin' } | Select-Object FullName
- Hash mismatches matter most when the file claims to be a known public release — if SHA-256 does not match the official release hash, the jar has been modified
- A copied mod name with a different internal package structure is a major warning sign — the brand is borrowed but the contents are not what they claim
- A legitimate name plus unrelated combat or network hooks is stronger evidence than a suspicious filename alone
- Mod IDs that do not match the claimed project — e.g., fabric.mod.json claims to be "SodiumFabric" but the mod ID is "cheatclient" — are an immediate escalation point
- A mod that cannot be matched to any official source should be documented as unverified, not automatically called malicious
- Version numbers that do not exist in any official changelog often indicate a custom build or a modified release
Metadata, Entrypoints & Mixin Review
Loader metadata tells you how a jar introduces itself. Mixin configuration tells you where it plans to interfere. In advanced reviews, the second part is often more valuable — a jar can hide behind generic names while still targeting player update loops, interaction managers, mouse input, packet handlers, or rendering paths.
Mixins are designed to modify classes before they are loaded. That is normal in modern Minecraft modding, but it is also exactly why they are so forensically useful. The mixin config is often the fastest path to understanding a jar's real intent.
| Mixin Target Area | Why It Matters | Signal Level |
|---|---|---|
| Player update / tick loops | Core execution path for automation, auto-walk, continuous input injection | HIGH |
| Attack / interaction managers | Direct modification of how hits are registered; reach, timing, auto-crit logic | CRITICAL |
| Mouse / keyboard input handlers | CPS schedulers, auto-clickers, input spoofing, and aim assistance | CRITICAL |
| Packet send / receive paths | Velocity modification, blink, packet delay, desync-based cheats | CRITICAL |
| Motion and physics | Speed, fly, step height, bunny-hop; alters how the client calculates movement | HIGH |
| Rendering / GUI overlays | ESP, chest finder, player trackers; suspicious if claimed purpose is non-visual | MEDIUM |
| Rendering pipeline only | Expected for shaders, performance, and visual mods; low suspicion in isolation | LOW |
| Resource loading only | Normal for resource pack and asset mods; minimal concern by itself | LOW |
{
"required": true,
"minVersion": "0.8",
"package": "com.example.mixins",
"compatibilityLevel": "JAVA_17",
"mixins": [
"MixinClientPlayerEntity", // player entity — worth checking
"MixinMouseHandler", // mouse input — HIGH signal
"MixinClientPacketListener", // packet handling — CRITICAL
"MixinGameRenderer" // rendering — context-dependent
],
"injectors": {
"defaultRequire": 1
}
}
// Injection types that warrant deeper review:
// @Inject — adds code at a target point (most common)
// @Overwrite — completely replaces the target method (highest risk)
// @Redirect — intercepts a method call within the target (often stealthy)
// @ModifyArg — alters a single argument passed to a call (subtle changes)If a jar claims to be a replay, HUD, or quality-of-life mod but its mixins target attack routines, motion control, or outgoing packet logic — the metadata story and the technical story do not match. This inconsistency is one of the strongest indicators available at the metadata review stage.
Static Triage & String Analysis
Static triage is the first real pass through the jar. You are looking for fast indicators that tell you where deeper review should go next. File structure, class naming patterns, embedded resources, decryptors, native payloads, and repeated terminology all matter here.
String searching is still useful — just not on its own. Plenty of public clients still leak terms like killaura, velocity, trigger, or scaffold. At the same time, many legitimate mods also contain generic words like rotation, timer, or click. Treat keyword hits as routing signals, not final proof. Good triage combines three things: metadata review, targeted string searches, and decompilation.
# After decompiling the jar to .\decompiled\ # Run targeted keyword search across all decompiled sources $terms = @( 'autoclick', 'killaura', 'reach', 'velocity', 'trigger', 'aim', 'rotation', 'scaffold', 'blink', 'cps', 'criticals', 'aimbot', 'timer', 'speed', 'fly', 'esp', 'wallhack', 'tracers', 'chams', 'nametags' ) Get-ChildItem .\decompiled -Recurse -File | Select-String -Pattern $terms -SimpleMatch | Select-Object Path, LineNumber, Line | Format-Table -AutoSize # Also check language files for leaked module names Get-ChildItem .\unpacked\assets -Recurse -Filter *.json | Get-Content | Select-String -Pattern $terms -SimpleMatch
- Hidden folders or unexpected package hierarchies — deeply nested packages with single-letter names are a common obfuscation footprint
- Shaded dependencies not documented in metadata — bundled libraries that are not declared in
fabric.mod.jsonormods.toml - Nested or embedded jars — a .jar inside a .jar, especially if it is encrypted or has no manifest
- Decryptor utility classes — classes whose sole function is to decrypt strings or resources at runtime
- Custom class loaders — non-standard loaders that bypass normal Fabric/Forge class loading mechanisms
- GUI systems and category managers that do not fit the claimed mod purpose — a "performance mod" shipping a full clickGUI framework
- Keybind registries and command frameworks — especially when the claimed mod has no documented configurable features
- Packet classes and rotation math —
Vec3drotation calculations in a non-movement mod, or references toPlayerInteractC2SPacketin an unrelated context
Instead of writing "cheat strings found", write: "Keyword triage surfaced combat-related terminology in decompiled sources, which was then corroborated by class behavior and mixin targets." The evidence chain matters more than the individual finding.
Detecting Masked or Embedded Clients
Masked clients usually give themselves away through inconsistency. The name says one thing. The metadata says something close to that. The code says something else entirely. Common examples include jars that impersonate a performance mod, a replay utility, or a harmless HUD project while shipping module managers, combat toggles, click schedulers, or packet manipulation routines.
A mod should generally align across three dimensions. When any of these three do not line up, document the mismatch clearly — the inconsistency itself is meaningful evidence even before proving specific capability.
| Indicator | What It Suggests | Next Step |
|---|---|---|
| Metadata claims harmless purpose but code touches combat, targeting, or network flow | Intentional mislabeling; primary masking technique | Document the mismatch; decompile combat classes directly |
| Package names imitate a known project but internal structure differs significantly | Borrowed brand, different codebase — likely a modified or wrapped build | Diff against official release file list |
| Resources or language keys expose feature names the official project does not ship | Leaked module names surviving obfuscation; strong capability evidence | Extract all lang files and compare to official release |
| Unrelated shaded libraries, native binaries, or custom loaders bundled inside | Second-stage payload, additional framework, or runtime decryptor | Inspect embedded jar; identify all native and foreign libraries |
| File list in the jar does not match the official version's file manifest | Added packages, injected mixins, or removed classes relative to clean release | Diff jarfiles; flag added and modified files for targeted review |
| Icon copied from a legitimate mod but SHA differs from the official icon file | Deliberate impersonation of a trusted project | Hash icon; check against official asset; note the impersonation directly |
# Unpack both jars to compare file lists Expand-Archive "official.jar" -DestinationPath ".\official\" -Force Expand-Archive "suspect.jar" -DestinationPath ".\suspect\" -Force # Compare file listings — identify added, removed, or modified entries $officialFiles = Get-ChildItem ".\official\" -Recurse | Select-Object -Expand FullName $suspectFiles = Get-ChildItem ".\suspect\" -Recurse | Select-Object -Expand FullName # Files in suspect jar not present in official release: Compare-Object $officialFiles $suspectFiles | Where-Object { $_.SideIndicator -eq '=>' } | Select-Object InputObject # Hash-compare files present in both (detect modified classes): Get-ChildItem ".\official\" -Recurse -File | ForEach-Object { $rel = $_.FullName.Replace(".\official\", "") $suspect = ".\suspect\" + $rel if (Test-Path $suspect) { $h1 = (Get-FileHash $_.FullName -Algorithm SHA256).Hash $h2 = (Get-FileHash $suspect -Algorithm SHA256).Hash if ($h1 -ne $h2) { Write-Output "MODIFIED: $rel" } } }
Obfuscation & Loader Patterns
Obfuscation changes the reading experience, not the purpose of the code. A cheat still has to read game state, make decisions, alter movement or combat, schedule inputs, render overlays, save config, and activate modules. Those tasks leave structural signatures behind even when all identifiable names are shredded. When normal decompilation gets difficult, the analysis strategy shifts from names to behavior.
Decrypt("a7f3c...") rather than "killaura". The decryptor class is usually identifiable; its inputs reveal the original strings when analyzed statically or traced at runtime.Class.forName() and Method.invoke(), often combining string encryption with reflection to break the static call graph. Tracing decryptor inputs reconstructs the target method names.invokedynamic instruction used to obscure method calls. Some decompilers fail to reconstruct these calls cleanly, producing incomplete or incorrect output. Bytecode-level inspection bypasses the decompiler for these sections.- Locate decryptor methods and note which classes feed them — decryptors are often one of the few remaining readable components and act as an index into the obfuscated code
- Track repeated call patterns — even when names are randomized, a method called from 30 different classes is almost certainly a core dispatcher or feature controller
- Look for reflection helpers that resolve fields or methods by decrypted string — trace the string inputs to identify targeted Minecraft classes
- Mark classes with unusually high branching or dispatcher tables — these are the signature of control-flow flattening; focus on the state variable values
- Inspect resources for encrypted blobs, serialized configs, or hidden jars loaded at runtime — encrypted resources are a strong indicator of a second-stage payload
- Count event hook registrations — a mod that registers many more event hooks than its claimed purpose requires is a structural anomaly regardless of readable names
AI tools can help summarize hostile control flow, cluster suspicious methods, or explain likely function of obfuscated code. Treat that output as analyst assistance — a starting point for focused review. The proof still comes from the jar, not the summary. Do not cite AI-generated analysis as evidence; cite the specific class, method, and behavior the AI helped you locate.
Obfuscation hides readability. It does not remove capability. The structural fingerprint of a module system, a target loop, or a packet interceptor survives most obfuscation techniques.
Behavioral Analysis in Isolation
Static review gets you far, but some jars only become obvious when loaded in a controlled environment. If you do this step, isolate it. Use a disposable VM or a dedicated test machine — never load unknown jars on a personal or production system. The goal is to document runtime behavior safely and deliberately, not to casually run suspicious files out of curiosity.
Behavioral analysis of unknown jars must only be performed in an isolated, disposable environment — a fresh VM with no personal data, no saved credentials, and no persistent network access to production systems. Snapshot the VM before loading the jar so the environment can be restored cleanly after analysis.
# Pre-launch: baseline snapshot of relevant filesystem locations $watchPaths = @( "$env:APPDATA\.minecraft\config", "$env:APPDATA\.minecraft\logs", "$env:APPDATA\.minecraft\mods", "$env:TEMP", "$env:LOCALAPPDATA\Temp" ) # Capture pre-launch state $baseline = $watchPaths | ForEach-Object { Get-ChildItem $_ -Recurse -ErrorAction SilentlyContinue | Get-FileHash -Algorithm SHA256 } # [ Launch Minecraft with the suspect mod in isolated VM ] # [ Wait for fully loaded state — observe GUI, keybinds, overlays ] # Post-launch: compare filesystem state $postLaunch = $watchPaths | ForEach-Object { Get-ChildItem $_ -Recurse -ErrorAction SilentlyContinue | Get-FileHash -Algorithm SHA256 } # New or modified files since launch: Compare-Object $baseline $postLaunch -Property Hash | Where-Object { $_.SideIndicator -eq '=>' }
| Observable | What It Reveals | Priority |
|---|---|---|
| Generated config files | Module names, category labels, default keybind values, hidden states — even when code is fully obfuscated, configs are almost always readable | P1 |
| GUI behavior and hidden menus | A clickGUI, module list, or category panel that appears on a keybind press reveals a full module system regardless of what the jar claims to be | P1 |
| Filesystem writes during launch | New directories, config trees, and log files created at startup; the structure alone often reveals feature categories | P2 |
| Network requests at launch | Outbound connections to external hosts at startup may indicate license checking, update fetching, or second-stage payload download | P2 |
| Secret keybind activations | Activating undocumented binds may reveal hidden overlays, toggles, or module panels not visible at initial launch | P3 |
| Console / log output | Some loaders print module lists, version information, or capability flags to the game log even when the GUI is hidden | P3 |
Even when code is heavily obfuscated, config files often leak feature names, category labels, default binds, or hidden module states. They are one of the most underrated artifacts in mod review — and one of the few things that obfuscation tools do not touch.
Reporting Confidence & False Positives
The cleanest reports separate observation from conclusion. Start with what you found, explain why it matters, then state how confident you are. That structure keeps your notes usable even when the final moderation decision is made by someone else. Admins decide the outcome — analysts document the facts.
| Level | Basis | How to Write It |
|---|---|---|
| LOW | Unknown jar, odd strings, but no verified capability. Anomalies exist but do not yet support a conclusion about function. | Document anomalies only. Do not claim cheat functionality. Use language like "warrants further review" and "could not be authenticated." |
| MEDIUM | Misleading metadata plus suspicious hooks or resources. The jar is inconsistent with its claimed purpose but specific capability is not fully confirmed. | State that the jar is inconsistent with its claimed purpose and warrants deeper review. List specific inconsistencies. Avoid definitive language about function. |
| HIGH | Readable combat, input, or packet manipulation logic found through decompilation. Specific functionality is identifiable and located. | Describe the specific functionality and where it was found — class name, method, behavior. State that the capability was identified in decompiled sources. |
| VERY HIGH | Cheat modules, configs, toggles, or runtime confirmation. Capability is directly confirmed through multiple independent artifact sources. | Report the behavior directly and attach the strongest artifacts first. Name specific modules, config keys, or runtime observations. State that multiple sources corroborate the finding. |
────────────────────────────────────────────────────────── OBSERVATION: What artifact was found and where. E.g. "MixinMouseHandler found in mixin config targeting com.example.mixins package." INDICATOR: What behavior or inconsistency this suggests. E.g. "Mouse input handler injection is inconsistent with a claimed replay mod." WHY IT MATTERS: How this could provide advantage or concealment. E.g. "Mouse handler modification is a standard technique for CPS scheduling and aim assist." CONFIDENCE: Low / Medium / High / Very High E.g. "Medium — mixin target identified, full method behavior not yet confirmed." ──────────────────────────────────────────────────────────
- Leaning too hard on a single signal — one scary string without corroborating code behavior does not prove a module exists
- Treating public popularity as proof of legitimacy — a well-known mod can still be tampered with; hash validation always applies
- Ignoring hash mismatches because the filename looks right — the filename is the easiest thing to fake and the least reliable indicator
- Letting keyword results outweigh mixin and behavior analysis — many legitimate mods contain terms like "rotation" or "click" in non-cheat contexts
- Treating obfuscation alone as proof — some legitimate mods use obfuscation for IP protection; obfuscation raises suspicion but does not confirm capability
- Conflating "unusual" with "malicious" — custom, private, or poorly documented mods are not automatically cheats; document anomalies and escalate appropriately
Useful Workflows & Scripts
The goal of quick scripts is not to replace actual analysis — it is to speed up repetitive work so your attention stays on the jars that deserve it most. A solid first-pass workflow is: inventory the mod folder, hash every jar, compare claimed releases to official sources, unpack or decompile suspicious files, run targeted searches, then document what was actually confirmed.
# ── STEP 1: Inventory and hash all jars ──────────────────────── $modsPath = "$env:APPDATA\.minecraft\mods" Get-ChildItem $modsPath -Filter *.jar | Get-FileHash -Algorithm SHA256 | Sort-Object Path | Export-Csv ".\hashes.csv" -NoTypeInformation # ── STEP 2: Unpack a suspect jar ─────────────────────────────── $target = ".\suspect.jar" Expand-Archive $target -DestinationPath ".\unpacked\" -Force # ── STEP 3: Read loader metadata ─────────────────────────────── foreach ($meta in @('fabric.mod.json','META-INF\mods.toml','META-INF\MANIFEST.MF')) { $path = ".\unpacked\" + $meta if (Test-Path $path) { Write-Host "=== $meta ===" -ForegroundColor Cyan Get-Content $path } } # ── STEP 4: List mixin configs ───────────────────────────────── Get-ChildItem ".\unpacked" -Filter *.json -Recurse | Where-Object { $_.Name -match 'mixin' } | ForEach-Object { Write-Host $_.FullName; Get-Content $_.FullName } # ── STEP 5: Keyword search across decompiled sources ─────────── # (Run after decompiling with Vineflower / CFR / Procyon) $patterns = 'reach','velocity','autoclick','trigger','rotation', 'killaura','scaffold','blink','cps','aimbot', 'criticals','esp','wallhack','speed','fly' Get-ChildItem .\decompiled -Recurse -File | Select-String -Pattern $patterns -SimpleMatch | Sort-Object Path, LineNumber | Format-Table Path, LineNumber, Line -AutoSize # ── STEP 6: Check language / resource files for module names ─── Get-ChildItem .\unpacked\assets -Recurse -Filter *.json -ErrorAction SilentlyContinue | Select-String -Pattern $patterns -SimpleMatch | Format-Table Path, LineNumber, Line -AutoSize
| Tool | Type | Best For | Source |
|---|---|---|---|
| Vineflower | Java Decompiler | Most accurate modern Java decompilation; successor to Fernflower; handles complex patterns well | Open source — github.com/Vineflower |
| CFR | Java Decompiler | Strong on modern Java features; good for comparing output against Vineflower when results differ | Free — benf.org/counterclockwise/cfr |
| Procyon | Java Decompiler | Alternative decompiler; useful when Vineflower and CFR produce poor output on specific classes | Open source — bitbucket.org/mstrobel/procyon |
| BytecodeViewer | Multi-tool GUI | All-in-one GUI combining multiple decompilers, bytecode view, and string search; good for triage | Open source — github.com/Konloch/bytecode-viewer |
| Recaf | Bytecode Editor / Viewer | Bytecode-level inspection; invaluable for invokedynamic abuse and sections decompilers fail on | Open source — github.com/Col-E/Recaf |
| jadx | Java Decompiler | Fast and readable output; strong GUI; good for initial orientation before deeper analysis | Open source — github.com/skylot/jadx |
1. Inventory first — hash all jars, document what is present. 2. Trust validation second — compare hashes, read metadata, identify version inconsistencies. 3. Metadata and mixins third — read loader configs, list mixin targets, flag high-signal injection points. 4. Decompiled behavior fourth — targeted class review based on mixin findings, string triage, and structural anomalies. 5. Isolation testing only when needed — and only in a controlled, disposable environment with pre- and post-launch filesystem comparison.
The strongest mod analysis is boring in a good way. It is organized, reproducible, and based on artifacts you can point to without any guesswork. Every claim has a source. Every source has a confidence level. Every conclusion follows from the evidence, not from assumption.