GS2 Bytecode Decompiler - Decompiles Graal Script 2 bytecode to readable GS2 code
Project description
gbf-rs
gbf_core is a Rust library designed to analyze, disassemble, process, and decompile Graal Script 2 (GS2) bytecode. It provides tools for GS2 bytecode analysis, control flow graph (CFG) generation, and abstract syntax tree (AST) construction, with a focus on modern Rust best practices.
Features
- GS2 Bytecode Analysis:
- Decode and analyze GS2 bytecode for program analysis.
- Disassembly and Decompilation:
- Disassemble bytecode into human-readable instructions.
- Control Flow Graph Visualization:
- Generate and render CFGs using Graphviz-compatible DOT files.
- Abstract Syntax Tree (AST) Construction:
- Build ASTs from bytecode to enable higher-level program understanding.
- Customizable Graph Rendering:
- Flexible, trait-based rendering for both pre-processed and post-processed CFGs.
- Modular Design:
- Highly extensible and idiomatic Rust library design.
Getting Started
Installation
Add gbf_core as a dependency in your Cargo.toml:
[dependencies]
gbf_core = "0.1.17"
Minimum Supported Rust Version
This project supports Rust 1.81.0 and later.
Usage
Decompile GS2 Bytecode
Decompiling GS2 Bytecode is easy and extremely customizable in gbf_core. We can do so by loading a GS2 module and invoking the FunctionDecompiler, like so:
use std::{fs::File, io::Read, path::Path};
use gbf_core::decompiler::{
ast::visitors::emit_context::{EmitContextBuilder, EmitVerbosity, IndentStyle},
function_decompiler::FunctionDecompilerBuilder,
};
fn load_bytecode(name: &str) -> Result<impl Read, std::io::Error> {
let path = Path::new("tests").join("gs2bc").join(name);
let file = File::open(path)?;
Ok(file)
}
fn main() {
// Load `simple.gs2bc` bytecode file
let reader = load_bytecode("simple.gs2bc").unwrap();
let module = gbf_core::module::ModuleBuilder::new()
.name("simple.gs2".to_string())
.reader(Box::new(reader))
.build()
.unwrap();
// Get the first function in the module
let function = module.get(0).unwrap();
// Configure the emitter to use specific formatting
let context = EmitContextBuilder::default()
.verbosity(EmitVerbosity::Pretty)
.format_number_hex(true)
.indent_style(IndentStyle::Allman)
.build();
// Invoke the `FunctionDecompiler`
let mut decompiler = FunctionDecompilerBuilder::new(function.clone()).build();
let decompiled = decompiler.decompile(context).unwrap();
println!("{}", decompiled);
}
This is the resulting GS2 decompilation for simple.gs2bc:
player.chat = "Hello, World!";
echo("This is a test");
temp.x = 0x0;
temp.x += 0x2;
echo(temp.x);
Generate Control Flow Graph (CFG)
This library can generate directed control flow graphs using Graphviz. We can load arbitrary GS2 bytecode using the following Rust code:
use std::{fs::File, io::Read, path::Path};
use gbf_core::cfg_dot::{CfgDotConfig, DotRenderableGraph};
fn load_bytecode(name: &str) -> Result<impl Read, std::io::Error> {
let path = Path::new("tests").join("gs2bc").join(name);
let file = File::open(path)?;
Ok(file)
}
fn main() {
// Load `switch.gs2bc` bytecode file
let reader = load_bytecode("switch.gs2bc").unwrap();
let module = gbf_core::module::ModuleBuilder::new()
.name("switch.gs2".to_string())
.reader(Box::new(reader))
.build()
.unwrap();
// Get the first function in the module. The "entry"
// function is 0, so this really is the "first"
// function.
let function = module.get(1).unwrap();
println!("{}", function.render_dot(CfgDotConfig::default()));
}
As an example, consider this simple GS2 switch statement.
function switchWithMultipleCasesPerNode() {
temp.server = "classicplus";
switch (temp.server) {
case "classic":
case "classicplus":
this.loginserver = "loginclassic1.graalonline.com:14900";
break;
case "delteria":
case "delteriaplus":
this.loginserver = "logindelteria1.graalonline.com:14900";
break;
case "foo":
this.loginserver = "loginfoo1.graalonline.com:14900";
break;
default:
this.loginserver = "loginserver.graalonline.com:14900";
break;
}
temp.i = this.loginserver.pos(":");
this.loginhost = this.loginserver.substring(0, temp.i);
this.loginport = this.loginserver.substring(temp.i + 1, 255);
}
The resulting Graphviz code that gbf_core generates will look like this when exported:
To export the resulting Graphviz code, you can use the popular dot utility like so:
$ dot -Tpng cfg.dot -o cfg.png
Build Abstract Syntax Trees (ASTs)
The library can also be used to manually build ASTs. Not only can you access the AST from the decompiled output, there are helper functions you can use to define your own AST for testing purposes:
use gbf_core::decompiler::ast::{
emit, new_assignment, new_id, new_member_access, new_str, AstNodeError,
};
fn build_player_chat() -> Result<String, AstNodeError> {
// player.chat = "Hello, world!";
let stmt = new_assignment(
new_member_access(new_id("player"), new_id("chat"))?,
new_str("Hello, world!"),
);
Ok(emit(stmt))
}
fn main() -> Result<(), AstNodeError> {
let result = build_player_chat()?;
println!("{}", result);
Ok(())
}
Development
Prerequisites
- Rust 1.81.0 or later
- Graphviz (optional, for rendering CFGs)
Build and Test
To build the library:
$ cargo build
To run tests:
$ cargo test
To check formatting:
$ cargo fmt --all -- --check
To lint the code:
$ cargo clippy --workspace --all-targets -- -D warnings
Documentation
Generate and view the documentation locally
$ cargo doc --no-deps --workspace
Contributing
Contributions are welcome! If you’d like to contribute:
- Fork the repository.
- Create a new branch (
git checkout -b feature-branch). - Commit your changes (
git commit -m "Add a new feature"). - Push the branch (
git push origin feature-branch). - Open a pull request.
Please ensure your code passes all tests and adheres to the project’s style guidelines.
License & Legal Disclaimer
This project is licensed under the Mozilla Public License 2.0 and is not affiliated with GraalOnline or its owners. GraalOnline and Graal are registered trademarks of Stephane Portha, and all trademarks are the property of their respective owners.
This project includes code from the Rust project, which is licensed under either the MIT License or Apache License 2.0. You may choose either license when copying the code included from the Rust project.
The original Rust code is available at: ptr.rs
Acknowledgments
- Rust, for being awesome.
- Graphviz is used to make human-readable directed graphs for debugging purposes.
- petgraph is used to implement the directed graph functionality.
- NextJS is used to render the front-end test environment.
- Netlify is used to host the front-end test environment.
Contact
If you have any questions or feedback, feel free to reach out via the repository's issues section.
Happy hacking!
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file gs2decompiler-0.1.2-cp312-cp312-win_amd64.whl.
File metadata
- Download URL: gs2decompiler-0.1.2-cp312-cp312-win_amd64.whl
- Upload date:
- Size: 363.0 kB
- Tags: CPython 3.12, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f8da6f8321f3d3980f152f01693fde1895769d332c2b6124c7163ec45fdc9500
|
|
| MD5 |
71ae8df6c91a0949c6bbc6fe6d0d877f
|
|
| BLAKE2b-256 |
cde3e35d73b4cd8563695b333b59f0fadaaf875dbce11556e61ff6f259451079
|
Provenance
The following attestation bundles were made for gs2decompiler-0.1.2-cp312-cp312-win_amd64.whl:
Publisher:
build-wheels.yml on Denveous/gbf-rs
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
gs2decompiler-0.1.2-cp312-cp312-win_amd64.whl -
Subject digest:
f8da6f8321f3d3980f152f01693fde1895769d332c2b6124c7163ec45fdc9500 - Sigstore transparency entry: 903363705
- Sigstore integration time:
-
Permalink:
Denveous/gbf-rs@12fecea3428cb9acda21730663e8522f6c2d66dc -
Branch / Tag:
refs/heads/feature/whl-build - Owner: https://github.com/Denveous
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
build-wheels.yml@12fecea3428cb9acda21730663e8522f6c2d66dc -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file gs2decompiler-0.1.2-cp312-cp312-manylinux_2_34_x86_64.whl.
File metadata
- Download URL: gs2decompiler-0.1.2-cp312-cp312-manylinux_2_34_x86_64.whl
- Upload date:
- Size: 446.9 kB
- Tags: CPython 3.12, manylinux: glibc 2.34+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b2eb88589b6a14dacdf9f75cf8c2a778808c1d456a31e4e07fd09bbe5c7bc482
|
|
| MD5 |
7de101f17ce0af85b5b484d36ea08f00
|
|
| BLAKE2b-256 |
ca9ff10e5cd7652eda9601e3c10c0520ad1df8f6ae6b2822a58349f65e9da4dc
|
Provenance
The following attestation bundles were made for gs2decompiler-0.1.2-cp312-cp312-manylinux_2_34_x86_64.whl:
Publisher:
build-wheels.yml on Denveous/gbf-rs
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
gs2decompiler-0.1.2-cp312-cp312-manylinux_2_34_x86_64.whl -
Subject digest:
b2eb88589b6a14dacdf9f75cf8c2a778808c1d456a31e4e07fd09bbe5c7bc482 - Sigstore transparency entry: 903363505
- Sigstore integration time:
-
Permalink:
Denveous/gbf-rs@12fecea3428cb9acda21730663e8522f6c2d66dc -
Branch / Tag:
refs/heads/feature/whl-build - Owner: https://github.com/Denveous
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
build-wheels.yml@12fecea3428cb9acda21730663e8522f6c2d66dc -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file gs2decompiler-0.1.2-cp312-cp312-macosx_11_0_arm64.whl.
File metadata
- Download URL: gs2decompiler-0.1.2-cp312-cp312-macosx_11_0_arm64.whl
- Upload date:
- Size: 399.4 kB
- Tags: CPython 3.12, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9c6a6eb233b55f1adfd51118b138a1b352f875c0e05e53e90314b49be6b5f4bf
|
|
| MD5 |
11275bad46be76125333c9a56e0ea35a
|
|
| BLAKE2b-256 |
23b2d22b851588750fd4c4c69ae9ef219737943e7972f560a288090e6f99741f
|
Provenance
The following attestation bundles were made for gs2decompiler-0.1.2-cp312-cp312-macosx_11_0_arm64.whl:
Publisher:
build-wheels.yml on Denveous/gbf-rs
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
gs2decompiler-0.1.2-cp312-cp312-macosx_11_0_arm64.whl -
Subject digest:
9c6a6eb233b55f1adfd51118b138a1b352f875c0e05e53e90314b49be6b5f4bf - Sigstore transparency entry: 903363606
- Sigstore integration time:
-
Permalink:
Denveous/gbf-rs@12fecea3428cb9acda21730663e8522f6c2d66dc -
Branch / Tag:
refs/heads/feature/whl-build - Owner: https://github.com/Denveous
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
build-wheels.yml@12fecea3428cb9acda21730663e8522f6c2d66dc -
Trigger Event:
workflow_dispatch
-
Statement type: