Skip to main content

GS2 Bytecode Decompiler - Decompiles Graal Script 2 bytecode to readable GS2 code

Project description

gbf-rs

codecov Rust CI

GBF Logo

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: Switch CFG

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:

  1. Fork the repository.
  2. Create a new branch (git checkout -b feature-branch).
  3. Commit your changes (git commit -m "Add a new feature").
  4. Push the branch (git push origin feature-branch).
  5. 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

gs2decompiler-0.1.2-cp312-cp312-win_amd64.whl (363.0 kB view details)

Uploaded CPython 3.12Windows x86-64

gs2decompiler-0.1.2-cp312-cp312-manylinux_2_34_x86_64.whl (446.9 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.34+ x86-64

gs2decompiler-0.1.2-cp312-cp312-macosx_11_0_arm64.whl (399.4 kB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

File details

Details for the file gs2decompiler-0.1.2-cp312-cp312-win_amd64.whl.

File metadata

File hashes

Hashes for gs2decompiler-0.1.2-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 f8da6f8321f3d3980f152f01693fde1895769d332c2b6124c7163ec45fdc9500
MD5 71ae8df6c91a0949c6bbc6fe6d0d877f
BLAKE2b-256 cde3e35d73b4cd8563695b333b59f0fadaaf875dbce11556e61ff6f259451079

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file gs2decompiler-0.1.2-cp312-cp312-manylinux_2_34_x86_64.whl.

File metadata

File hashes

Hashes for gs2decompiler-0.1.2-cp312-cp312-manylinux_2_34_x86_64.whl
Algorithm Hash digest
SHA256 b2eb88589b6a14dacdf9f75cf8c2a778808c1d456a31e4e07fd09bbe5c7bc482
MD5 7de101f17ce0af85b5b484d36ea08f00
BLAKE2b-256 ca9ff10e5cd7652eda9601e3c10c0520ad1df8f6ae6b2822a58349f65e9da4dc

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file gs2decompiler-0.1.2-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for gs2decompiler-0.1.2-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 9c6a6eb233b55f1adfd51118b138a1b352f875c0e05e53e90314b49be6b5f4bf
MD5 11275bad46be76125333c9a56e0ea35a
BLAKE2b-256 23b2d22b851588750fd4c4c69ae9ef219737943e7972f560a288090e6f99741f

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page