{"id":15060155,"url":"https://github.com/emproof-com/nyxstone","last_synced_at":"2025-05-15T02:09:24.738Z","repository":{"id":245222110,"uuid":"694757498","full_name":"emproof-com/nyxstone","owner":"emproof-com","description":"Nyxstone: assembly / disassembly library based on LLVM, implemented in C++ with Rust and Python bindings, maintained by emproof.com","archived":false,"fork":false,"pushed_at":"2024-12-04T01:37:45.000Z","size":1344,"stargazers_count":360,"open_issues_count":10,"forks_count":16,"subscribers_count":9,"default_branch":"main","last_synced_at":"2025-04-14T02:59:51.475Z","etag":null,"topics":["aarch64","arm","assembly","disassembly","infosec","mips","powerpc","reverse-engineering","risc-v","security","thumb","x86","x86-64"],"latest_commit_sha":null,"homepage":"https://www.emproof.com","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/emproof-com.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-09-21T16:21:25.000Z","updated_at":"2025-04-13T20:35:54.000Z","dependencies_parsed_at":"2024-10-12T20:40:56.869Z","dependency_job_id":"8d176eb7-c0ce-4e30-a645-3e70114b183d","html_url":"https://github.com/emproof-com/nyxstone","commit_stats":{"total_commits":130,"total_committers":8,"mean_commits":16.25,"dds":0.3538461538461538,"last_synced_commit":"3016c479ac77f387545d9c93f4025b96610ff554"},"previous_names":["emproof-com/nyxstone"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emproof-com%2Fnyxstone","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emproof-com%2Fnyxstone/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emproof-com%2Fnyxstone/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emproof-com%2Fnyxstone/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/emproof-com","download_url":"https://codeload.github.com/emproof-com/nyxstone/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254259384,"owners_count":22040820,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aarch64","arm","assembly","disassembly","infosec","mips","powerpc","reverse-engineering","risc-v","security","thumb","x86","x86-64"],"created_at":"2024-09-24T22:53:47.964Z","updated_at":"2025-05-15T02:09:24.713Z","avatar_url":"https://github.com/emproof-com.png","language":"C++","funding_links":[],"categories":["C++","Rust"],"sub_categories":[],"readme":"# Nyxstone\n\n[![Github Cpp CI Badge](https://github.com/emproof-com/nyxstone/actions/workflows/cpp.yml/badge.svg)](https://github.com/emproof-com/nyxstone/actions/workflows/cpp.yml)\n[![crates.io](https://img.shields.io/crates/v/nyxstone.svg)](https://crates.io/crates/nyxstone)\n[![PyPI](https://img.shields.io/pypi/v/nyxstone.svg)](https://pypi.org/project/nyxstone)\n[![cpp-docs](https://github.com/emproof-com/nyxstone/actions/workflows/doxygen.yml/badge.svg)](https://emproof-com.github.io/nyxstone/)\n\nNyxstone is a powerful assembly and disassembly library based on LLVM. It doesn’t require patches to the LLVM source tree and links against standard LLVM libraries available in most Linux distributions. Implemented as a C++ library, Nyxstone also offers Rust and Python bindings. It supports all official LLVM architectures and allows to configure architecture-specific target settings.\n\n![Nyxstone Python binding demo](/images/demo.svg)\n\n## Index\n\n1. [Core Features](#core-features)\n2. [Using Nyxstone](#using-nyxstone)\n    1. [Prerequisites](#prerequisites)\n    2. [CLI Tool](#cli-tool)\n    3. [C++ Library](#c-library)\n    4. [Rust Bindings](#rust-bindings)\n    5. [Python Bindings](#python-bindings)\n3. [How it works](#how-it-works)\n4. [Roadmap](#roadmap)\n5. [License](#license)\n6. [Contributing](#contributing)\n7. [Contributors](#contributors)\n\n## Core Features\n\n* Assembles and disassembles code for all architectures supported by the linked LLVM, including x86, ARM, MIPS, RISC-V and others.\n\n* C++ library based on LLVM with Rust and Python bindings.\n\n* Native platform support for Linux and macOS.\n\n* Supports labels in the assembler, including the specification of label-to-address mappings\n\n* Assembles and disassembles to raw bytes and text, but also provides detailed instruction objects containing the address, raw bytes, and the assembly representation.\n\n* Disassembly can be limited to a user-specified number of instructions from byte sequences.\n\n* Allows to configure architecture-specific target features, such as ISA extensions and hardware features.\n\nFor a comprehensive list of supported architectures, you can use `clang -print-targets`. For a comprehensive list of features for each architecture, refer to `llc -march=ARCH -mattr=help`.\n\n\u003e [!NOTE]\n\u003e Disclaimer: Nyxstone has been primarily developed and tested for x86_64, AArch64, and ARM32 architectures. We have a high degree of confidence in its ability to accurately generate assembly and identify errors for these platforms. For other architectures, Nyxstone's effectiveness depends on the reliability and performance of their respective LLVM backends.\n\n## Using Nyxstone\n\nThis section provides instructions on how to get started with Nyxstone, covering the necessary prerequisites, how to use the CLI tool, and step-by-step guidelines for using the library with C++, Rust, and Python.\n\n### Prerequisites\n\nBefore building Nyxstone, ensure clang and LLVM are present on your system. Nyxstone supports LLVM major versions 15-18.\nWhen building it looks for `llvm-config` in your system's `$PATH` or the specified environment variable `$NYXSTONE_LLVM_PREFIX/bin`.\n\nInstallation Options for LLVM versions 15-18:\n\n* Ubuntu\n```bash\nsudo apt install llvm-${version} llvm-${version}-dev\n```\n\n* Debian\nLLVM version 15 and 16 are available through debian repositories. Installation is the same as for Ubuntu.\nFor versions 17 or 18 refer to [https://apt.llvm.org/](https://apt.llvm.org/) for installation instructions.\n\n* Arch\n```bash\nsudo pacman -S llvm llvm-libs\n```\n\n* Homebrew (macOS, Linux and others):\n```bash\nbrew install llvm@18\nexport NYXSTONE_LLVM_PREFIX=/opt/homebrew/opt/llvm@18\n```\n\n* From LLVM Source:\n\n_Note_: On Windows you need to run these commands from a Visual Studio 2022 x64 command prompt. Additionally replace `~lib/my-llvm-18` with a different path.\n\n```bash\n# checkout llvm\ngit clone -b release/18.x --single-branch https://github.com/llvm/llvm-project.git\ncd llvm-project\n\n# build LLVM with custom installation directory\ncmake -S llvm -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DLLVM_PARALLEL_LINK_JOBS=1\ncmake --build build\ncmake --install build --prefix ~/lib/my-llvm-18\n\n# export path\nexport NYXSTONE_LLVM_PREFIX=~/lib/my-llvm-18\n```\n\nAlso make sure to install any system dependent libraries needed by your LLVM version for static linking. They can be viewed with the command `llvm-config --system-libs`; the list can be empty. On Ubuntu/Debian, you will need the packages `zlib1g-dev` and `zlibstd-dev`.\n\n### CLI Tool\n\nNyxstone comes with a handy [CLI tool](examples/nyxstone-cli.cpp) for quick assembly and disassembly tasks. Checkout the Nyxstone repository, and build the tool with CMake:\n\n```bash\n# clone directory\ngit clone https://github.com/emproof-com/nyxstone\ncd nyxstone\n\n# build nyxstone\nmkdir build \u0026\u0026 cd build \u0026\u0026 cmake .. \u0026\u0026 make \n```\n\nThen, `nyxstone` can be used from the command line. Here's an output of its help menu:\n\n```\n$ ./nyxstone -h\nUsage: nyxstone [-t=\u003ctriple\u003e] [-p=\u003cpc\u003e] [-d] \u003cinput\u003e\n\nExamples:\n  # Assemble an instruction with the default architecture ('x86_64').\n  nyxstone 'push eax'\n\n  # Disassemble the bytes 'ffc300d1' as AArch64 code.\n  nyxstone -t aarch64 -d ffc300d1\n\nOptions:\n  -t, --triple=\u003ctriple\u003e      LLVM target triple or alias, e.g. 'aarch64'\n  -c, --cpu=\u003ccpu\u003e            LLVM CPU specifier, e.g. 'cortex-a53'\n  -f, --features=\u003clist\u003e      LLVM architecture/CPU feature list, e.g. '+mte,-neon'\n  -p, --address=\u003cpc\u003e         Initial address to assemble/disassemble relative to\n  -l, --labels=\u003clist\u003e        Label-to-address mappings (used when assembling only)\n  -d, --disassemble          Treat \u003cinput\u003e as bytes to disassemble instead of assembly\n  -h, --help                 Show this help and usage message\n\nNotes:\n  The '--triple' parameter also supports aliases for common target triples:\n\n     'x86_32' -\u003e 'i686-linux-gnu'\n     'x86_64' -\u003e 'x86_64-linux-gnu'\n     'armv6m' -\u003e 'armv6m-none-eabi'\n     'armv7m' -\u003e 'armv7m-none-eabi'\n     'armv8m' -\u003e 'armv8m.main-none-eabi'\n    'aarch64' -\u003e 'aarch64-linux-gnueabihf'\n\n  The CPUs for a target can be found with 'llc -mtriple=\u003ctriple\u003e -mcpu=help'.\n  The features for a target can be found with 'llc -mtriple=\u003ctriple\u003e -mattr=help'.\n```\n\nNow, we can assemble an instruction for the x86_64 architecture:\n\n```\n$ ./nyxstone -t x86_64 \"mov rax, rbx\"\n        0x00000000: mov rax, rbx                     ; 48 89 d8\n```\n\nWe can also assemble a sequence of instructions. In the following, we make use of label-based addressing and assume the first instruction is mapped to address `0xdeadbeef`:\n\n```\n$ ./nyxstone -t x86_64 -p 0xdeadbeef \"cmp rax, rbx; jz .exit; inc rax; .exit: ret\"\n        0xdeadbeef: cmp rax, rbx                     ; 48 39 d8 \n        0xdeadbef2: je .exit                         ; 74 03 \n        0xdeadbef4: inc rax                          ; 48 ff c0 \n        0xdeadbef7: ret                              ; c3 \n```\n\nFurthermore, we can disassemble instructions for different instruction sets, here the ARM32 thumb instruction set:\n\n```\n$ ./nyxstone -t thumbv8 -d \"13 37\"\n        0x00000000: adds r7, #19                     ; 13 37 \n```\n\nUsing the support for user-defined labels, we can assemble this snippet which does not contain the label `.label` by specifying its memory location ourself.\n\n```\n$ ./nyxstone -p \"0x1000\" -l \".label=0x1238\" \"jmp .label\"\n        0x00001000: jmp .label                       ; e9 33 02 00 00\n```\n\n### C++ Library\n\nTo use Nyxstone as a C++ library, your C++ code has to be linked against Nyxstone and LLVM.\n\nThe following cmake example assumes Nyxstone in a subdirectory `nyxstone` in your project:\n\n```cmake\nadd_subdirectory(nyxstone)\n\nadd_executable(my_executable main.cpp)\ntarget_link_libraries(my_executable nyxstone::nyxstone)\n```\n\nThe corresponding C++ usage example:\n\n\n```c++\n#include \u003ccassert\u003e\n#include \u003ciostream\u003e\n\n#include \"nyxstone.h\"\n\nint main(int, char**) {\n    // Create the nyxstone instance:\n    auto nyxstone {\n        NyxstoneBuilder(\"x86_64\")\n            .build()\n            .value()\n    };\n\n     // Assemble to bytes\n    std::vector\u003cuint8_t\u003e bytes = \n        nyxstone-\u003eassemble(/*assembly=*/\"mov rax, rbx\", /*address=*/0x1000, /* labels= */ {}).value();\n\n    std::vector\u003cuint8_t\u003e expected {0x48, 0x89, 0xd8};\n    assert(bytes == expected);\n\n    return 0;\n}\n```\n\nFor a comprehensive C++ example, take a look at [example.cpp](examples/example.cpp).\n\n\n### Rust Bindings\n\nTo use Nyxstone as a Rust library, add it to your `Cargo.toml`and use it as shown in the following example:\n\n```rust\nuse anyhow::Result;\nuse nyxstone::{Nyxstone, NyxstoneConfig};\n\nuse std::collections::HashMap;\n\nfn main() -\u003e Result\u003c()\u003e {\n    let nyxstone = Nyxstone::new(\"x86_64\", NyxstoneConfig::default())?;\n\n    let bytes = nyxstone.assemble_with(\n        \"mov rax, rbx; cmp rax, rdx; jne .label\",\n        0x1000,\n        \u0026HashMap::from([(\".label\", 0x1200)]),\n    )?;\n\n    println!(\"Bytes: {:x?}\", bytes);\n\n    Ok(())\n}\n```\n\nFor more instructions regarding the Rust binding, take a look at the corresponding [README](bindings/rust/README.md).\n\n### Python Bindings\n\nTo use Nyxstone from Python, install it using pip:\n\n```bash\npip install nyxstone\n```\n\nThen, you can use it from Python:\n\n```\n$ python -q\n\u003e\u003e\u003e from nyxstone import Nyxstone\n\u003e\u003e\u003e nyxstone = Nyxstone(\"x86_64\")\n\u003e\u003e\u003e nyxstone.assemble(\"jne .loop\", 0x1100, {\".loop\": 0x1000})\n```\n\nDetailed instructions are available in the corresponding [README](bindings/python/README.md).\n\n\n\n## How it works\n\nNyxstone leverages public C++ API functions from LLVM such as `Target::createMCAsmParser` and `Target::createMCDisassembler` to perform assembly and disassembly tasks. Nyxstone also extends two LLVM classes, `MCELFStreamer` and `MCObjectWriter`, to inject custom logic and extract additional information. Specifically, Nyxstone augments the assembly process with the following steps:\n\n* `ELFStreamerWrapper::emitInstruction`: Captures assembly representation and initial raw bytes of instructions if detailed instruction objects are requested by the user.\n\n* `ObjectWriterWrapper::writeObject`: Writes the final raw bytes of instructions (with relocation adjustments) to detailed instruction objects. Furthermore, it switches raw bytes output from complete ELF file to just the .text section.\n\n* `ObjectWriterWrapper::validate_fixups`: Conducts extra checks, such as verifying the range and alignment of relocations.\n\n* `ObjectWriterWrapper::recordRelocation`: Applies additional relocations. `MCObjectWriter` skips some relocations that are only applied during linking. Right now, this is only relevant for the `fixup_aarch64_pcrel_adrp_imm21` relocation of the Aarch64 instruction `adrp`.\n\nWhile extending LLVM classes introduces some drawbacks, like a strong dependency on a specific LLVM version, we believe this approach is still preferable over alternatives that require hard to maintain patches in the LLVM source tree.\n\nWe are committed to further reduce the project's complexity and open to suggestions for improvement. Looking ahead, we may eliminate the need to extend LLVM classes by leveraging the existing LLVM infrastructure in a smarter way or incorporating additional logic in a post-processing step.\n\n\n\n## Roadmap\n\nBelow are some ideas and improvements we believe would significantly advance Nyxstone. The items are not listed in any particular order:\n\n* [ ] Check thread safety\n\n* [ ] Add support for more LLVM versions (auto select depending on found LLVM library version)\n\n* [ ] Explore option to make LLVM apply all relocations (including `adrp`) by configuring `MCObjectWriter` differently or using a different writer\n\n* [ ] Explore option to generate detailed instructions objects by disassembling the raw bytes output of the assembly process instead of relying on the extension of LLVM classes\n\n* [ ] Explore option to implement extra range and alignment of relocations in a post-processing step instead of relying on the extension of LLVM classes\n\n\n## License\n\nNyxstone is available under the [MIT license](LICENSE).\n\n## Contributing\n\nWe welcome contributions from the community! If you encounter any issues with Nyxstone, please feel free to open a GitHub issue. \n\nIf you are interested in contributing directly to the project, you can for example:\n\n* Address an existing issue\n* Develop new features\n* Improve documentation\n\nOnce you're ready, submit a pull request with your changes. We are looking forward to your contribution!\n\n## Contributors\n\nThe current contributors are:\n\n**Core**:\n* Philipp Koppe (emproof)\n* Rachid Mzannar (emproof)\n* Darius Hartlief (emproof)\n\n**Minor**:\n* Marc Fyrbiak (emproof)\n* Tim Blazytko (emproof)\n\n## Acknowledgements\n\nTo ensure that we link LLVM correctly with proper versioning in Rust, we adapted the build.rs from [llvm-sys](https://gitlab.com/taricorp/llvm-sys.rs/).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Femproof-com%2Fnyxstone","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Femproof-com%2Fnyxstone","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Femproof-com%2Fnyxstone/lists"}