A Minecraft hacked client built in Rust, using JNI (Java Native Interface) for seamless integration with Minecraft's Java runtime. DarkClient provides a robust architecture for developing game modifications through dynamic library injection.
- Obfuscated builds (โค 1.21.11): bundled Mojmap mappings (
mappings.json, currently 1.21.10). - Unobfuscated builds (26.1+): no mappings needed โ names are resolved directly, method signatures via runtime JNI reflection. Latest tested: 26.1.2.
The build auto-detects which mode to use at runtime. A single binary works on both.
DarkClient runs on vanilla Minecraft, Fabric, and Forge/NeoForge. It auto-discovers the game's class loader (KnotClassLoader for Fabric, TransformingClassLoader for Forge/NeoForge), so injection is loader-agnostic.
Note
Fabric and Forge/NeoForge support requires an unobfuscated build (26.1+). Obfuscated Minecraft under a mod loader (intermediary/SRG names) is not supported.
- ๐ง Dynamic Library Injection: Hot-swappable module system without requiring game restarts
- ๐จ Cross-Platform GUI: Beautiful injector interface built with egui
- ๐ฅ๏ธ In-Game ClickGUI: egui overlay with draggable category panels, per-module settings, scrollable lists and rebindable keys
- โจ๏ธ Real-time Input Handling: Advanced keyboard/mouse event processing for module toggling
- ๐บ๏ธ Smart Mapping System: Automatic obfuscation handling โ bundled mappings for obfuscated builds, runtime JNI reflection for unobfuscated ones
- ๐ก Packet Layer: Netty-pipeline interception (pure JNI, no JVMTI) for packet-level modules โ powers NoFall and Velocity / Anti-Knockback
- ๐ Module Architecture: Extensible module system for easy feature development
- ๐พ Persistent Config: keybinds, settings, enabled modules and GUI layout saved across injections
- ๐งฉ Mod Loader Support: Works with vanilla Minecraft, Fabric, and Forge/NeoForge
- ๐ Comprehensive Logging: Detailed logging system for debugging and monitoring
- ๐ Thread-Safe Design: Robust multi-threaded architecture with proper synchronization
A Cargo workspace of five crates plus an xtask helper:
The shared contract between the injector and the agent: the localhost socket address and the typed command set, defined once so the two ends cannot drift apart.
The injection tool โ a redesigned egui GUI, a --tui terminal mode and
--list / --inject <pid> headless modes โ that handles:
- Process detection (finding Minecraft instances)
- Library injection into target processes (per-platform, behind a trait)
- Status monitoring and error reporting
A cdylib injected into the JVM. On load it provides:
- Dynamic library loading and hot-reloading of the client
- A TCP command server
- A JVM health monitor and clean process lifecycle handling
The core modification framework featuring:
- JNI integration with Minecraft's runtime
- Module system for game modifications (combat, movement, render)
- Mapping system for obfuscation handling
- An in-game ClickGUI overlay, input processing and event management
- A packet layer (
net/) that injects a handler into Minecraft's Netty pipeline - Persistent configuration of keybinds, settings and GUI layout
A proc-macro crate providing #[derive(MappedObject)] for the JVM-object
wrappers in the client โ generates the JNI helper methods so each game
wrapper stays a thin, safe handle.
- Rust 1.95.0+ with Cargo package manager
- Java Development Kit (JDK) 21+
- Minecraft Java Edition
If you prefer precompiled binaries instead of building from source:
- Go to the Actions tab on GitHub.
- Open the latest workflow run.
- Scroll to the bottom of the page to find the Artifacts section.
- Download the compiled binaries for your platform (Linux or Windows).
This allows you to get up and running without waiting for compilation.
bash git clone https://github.com/TheDarkSword/DarkClient
cd darkclientcargo build --releaseThe framework uses obfuscation mappings to interact with Minecraft:
python conversion.py- Launch the Injector:
cd target/release ./injector
Warning
libagent_loader and libclient must be in the same directory where you run the injector.
-
Start Minecraft โ you can inject from the main menu; modules stay idle until you load a world
-
In the Injector GUI:
- Click "Scan" to detect the Minecraft process
- Select it and click "Inject" to load the modification framework
- Use Modules:
- Modules can be toggled using their assigned keybinds
- Check the log files for module status and debugging info
Create new modules by implementing the Module trait:
use crate::module::{Module, ModuleData};
pub struct CustomModule {
data: ModuleData,
// Your module-specific fields
}
impl Module for CustomModule {
fn get_module_data(&self) -> &ModuleData {
&self.data
}
fn get_module_data_mut(&mut self) -> &mut ModuleData {
&mut self.data
}
fn on_start(&self) -> anyhow::Result<()> {
// Called when the module is enabled.
Ok(())
}
fn on_stop(&self) -> anyhow::Result<()> {
// Called when the module is disabled.
Ok(())
}
fn on_tick(&self) -> anyhow::Result<()> {
// Called every game tick while enabled.
Ok(())
}
}Register it in register_modules() in client/src/lib.rs. Modules that need
to read or rewrite network packets can also implement the optional
handle_packet method โ see NoFall and Velocity for examples.
DarkClient/
โโโ ๐ protocol/ # Shared injector โ agent IPC contract
โโโ ๐ injector/ # Injection tool (GUI / TUI / headless CLI)
โโโ ๐ agent_loader/ # Injected cdylib: command server + client lifecycle
โโโ ๐ client/ # Core modification framework
โ โโโ ๐ src/
โ โโโ ๐ lib.rs # Entry points (initialize_client / cleanup_client)
โ โโโ ๐ state.rs # Global client + mapping state
โ โโโ ๐ config.rs # Persistent config (keybinds, settings, GUI layout)
โ โโโ ๐ mapping/ # Minecraft mapping system (obfuscated + reflected)
โ โโโ ๐ graphic/ # Overlay, hooks, input, platform seam
โ โโโ ๐ module/ # Module framework + registry
โ โโโ ๐ net/ # Netty packet layer (packet structs + dispatch)
โโโ ๐ mapping_derive/ # proc-macro: #[derive(MappedObject)]
โโโ ๐ xtask/ # Workspace task runner (cargo xtask e2e)
โโโ ๐ mappings.json # Minecraft obfuscation mappings
โโโ ๐ conversion.py # Mapping conversion utility
โโโ ๐ Cargo.toml # Workspace configuration
DarkClient writes nothing into .minecraft โ all of its files live in the
directory the injector is started from:
app.logโ injector logagent_loader.logโ agent loader logdark_client.logโ client logdark_client_config.jsonโ persisted keybinds, settings, enabled modules and GUI layout
The injector and agent communicate over TCP 127.0.0.1:7878, defined once in the protocol crate:
// protocol/src/lib.rs
pub const SOCKET_ADDR: SocketAddr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 7878);DarkClient vendors a patched copy of ilhook
(the inline-hook crate behind the frame hook) under vendor/ilhook, wired in through
[patch.crates-io]. Upstream ilhook 2.3.0 has a Linux bug: its hook trampoline is a
heap allocation that can straddle a page boundary, yet only one page is marked
executable โ so roughly one inject in four ended in a SIGSEGV in native code.
๐ Full write-up โ causes, crash-log evidence and the fix:
docs/vendored-ilhook-fix.md
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-module) - Commit your changes (
git commit -am 'Add amazing module') - Push to the branch (
git push origin feature/amazing-module) - Create a Pull Request
- Follow Rust best practices and use
cargo fmt - Add comprehensive documentation for new modules
- Include proper error handling and logging
This project is intended for educational and research purposes. Users are responsible for complying with:
- Minecraft's Terms of Service
- Mojang's Commercial Usage Guidelines
- Local laws and regulations regarding game modifications
This project is licensed under the GNU GPL License - see the LICENSE file for details.
