Skip to content

Hakkun goober

Modular C++ toolchain and set of libraries for userspace Nintendo Switch processes with 64-bit and 32-bit support. This is the library repository to be cloned as submodule into a project. An example project can be found here

Features

  • Clang/LLVM toolchain, linking musl libc + LLVM libc++
  • Can be used for standalone programs, modification of existing ones, NROs, and homebrews
  • Compatible with RTLD
  • Bundled with RTLD reimplementation [WIP]
  • Compatible with programs that statically link RTLD into their main executable
  • Runtime Replace, Trampoline, B/BL hooking, RW access to code memory
  • Sophisticated symbol sourcing system with proper error reporting and compatibility across multiple program target versions
  • Constexpr AArch64 assembler
  • Abort/Assert util that prints text visible in Atmosphère crash reports
  • Symbols imported dynamically can be stripped from final binary
  • Framework and user code clearly separated with a submodule to prevent messy codebases and forks
  • Multiple addons with additional functionality:
  • SF client implementation [WIP]:
    • SM, PM, LM, Socket

Setup

Prerequisites

  • CMake + GNUMake or Ninja
  • cURL
  • Clang, LLVM, LLD 19 or later
  • Python 3.10, pyelftools, mmh, and lz4 packages

Compile stdlibs and sail

This part can be skipped, since these scripts are ran automatically when needed.

You can either use a prepackaged stdlib, or compile one yourself (pass 'aarch32' as argument to either of the scripts if using 32-bit):

Using prepackaged stdlib

Run tools/setup_libcxx_prepackaged.py from your repository's root to download a pre-packaged stdlib. (~20MiB)

Compiling stdlib yourself

After setting up a repository in a similar fashion to the example repository, run tools/setup_libcxx.py from your repository's root to download and compile musl libc and LLVM libc++. (~1.7GiB)

Sail

Run tools/setup_sail.py from your repository's root to compile sail, the tool used to parse .sym files for symbol sourcing.

Build

With a CMakeLists.txt setup similar to the example repository, the project can be built by running CMake from the build folder and calling the build system:

  • mkdir build
  • cd build
  • cmake .. -DCMAKE_BUILD_TYPE=Debug (or Release)
  • Run make or ninja depending on which you used in the above command

Deploy

Hakkun provides 2 ways of deploying the built files into a usable structure, besides manually copying from the build folder:

SD

By default, binaries are output into the sd folder in the build folder in Atmosphère's LayeredFS structure/the switch folder:

sd
├── atmosphere
│   └── contents
│       └── 0100000000010000
│           └── exefs
│               ├── main.npdm
│               └── subsdk4
└───switch
    └── YourProject.nro

FTP

If following environment variables are set, Hakkun will automatically attempt to upload files to an FTP server after linking:

  • HAKKUN_FTP_IP: IP (e.g. 192.168.188.151, my switch)
  • HAKKUN_FTP_PORT: Port (optional, 5000 by default)
  • HAKKUN_FTP_USER: User (optional)
  • HAKKUN_FTP_PASS: Password (optional)

GitHub workflow

A GitHub workflow template can be found in .github/workflow_templates/build.yml.

Configuration

config.cmake

Hakkun provides various options that you can configure from config/config.cmake within your repository:

Common options
  • LINKFLAGS: Flags passed to compiler linking command
  • LLDFLAGS: Flags passed to linker
  • OPTIMIZE_OPTIONS_DEBUG: Optimization options for Debug mode
  • OPTIMIZE_OPTIONS_RELEASE: Optimization options for Release mode
  • WARN_OPTIONS: Warn options
  • DEFINITIONS: Preprocessor definitions
  • INCLUDES: Include directories
  • ASM_OPTIONS, C_OPTIONS, CXX_OPTIONS: Various compiler options
  • USE_ADVANCED_RESULT: Whether to enable stack trace building in hk::Result. Use hk::ResultNN to mask out extra data for compatibility with nn::Result
  • TRAMPOLINE_LEVEL: Level for trampoline hook.
    • 0: only basic backups (no b.cond, cbz/cbnz, tbz/tbnz), +-128MB branch range
    • 1: all backups, +-128MB branch range
    • 2: all backups, infinite branch range
  • HAKKUN_ADDONS: List of Hakkun addons to enable
  • IS_32_BIT: Whether or not target is 32-bit
  • HAKKUN_TARGET: Type of program, MODULE by default
    • MODULE: Default RTLD module (e.g. for game mods)
    • MODULE_STANDALONE: Standalone main module providing nn::init::Start + rtld module, packs an exefs.nsp (e.g. for sysmodules)
    • MODULE_DLL: Outputs as a dynamic-link module (NRO) (e.g. for homebrews)
  • HOMEBREW_TYPE: Type of homebrew loader to target
    • NONE: Default
    • HBLOADER: Target nx-hbloader (libnx)
MODULE/MODULE_STANDALONE options
  • MODULE_NAME: Name of your output RTLD module
  • TITLE_ID: Title ID of the target program
  • MODULE_BINARY: ExeFS slot for your output module (can be sdk, or subsdk0-subsdk9)
  • SDK_PAST_1900: Enable if RTLD version of target program is from SDK 19.0.0 or later, usually the case with titles updated in or later than late 2024
  • TARGET_IS_STATIC: Whether or not target program has statically linked rtld/sdk. Usually sysmodules or applets do this, Applications do not. Enabling this will also add a dummy RTLD module, to work around an unfortunate decision in loader
  • USE_SAIL: Whether or not to use sail. If disabled, you can dynamic link normally
  • BAKE_SYMBOLS: Whether or not to 'bake' symbols provided by sail. Baking will replace all string references to symbols with hashes, reducing binary size at the expense of harder debugging

Sail

Sail reads the following configuration file:

VersionList.sym

List of modules with versions bound to NSO build IDs, if versioning is desired, for example:

@rtld = nnrtld
@smo = RedStar.nss
100 = 3ca12dfaaf9c82da064d1698df79cda1
101 = 50ade4b5eb6e45efb170a6b230d3b0ba
110 = 948dbbfc2fa0c60e2c30316e4c961aba
120 = f5dccddb37e97724ebdbcccdbeb965ff
130 = b424be150a8e7d78701cbe7a439d9ebf
@multimedia
@sdk = nnSdk
100 = ae34e75d02925f4417b24499ad80c39412fc76db
101 = ae34e75d02925f4417b24499ad80c39412fc76db
110 = ae34e75d02925f4417b24499ad80c39412fc76db
120 = ae34e75d02925f4417b24499ad80c39412fc76db
130 = fcf93a41b08c5193a1410d262602dc621617c56f

npdm.json

config/npdm.json configures the NPDM file required to grant certain SVC permissions needed. The following SVC permissions are used and need to be allowed for Hakkun to function:

"svcQueryMemory": "0x06",
"svcBreak": "0x26",
"svcOutputDebugString": "0x27",
"svcGetInfo": "0x29",
"svcMapProcessMemory": "0x74",

Additionally, the following SVC permissions are needed in 32-bit mode:

"svcInvalidateProcessDataCache": "0x5d",
"svcFlushProcessDataCache": "0x5f",

Symbol Language

Hakkun provides sail, a tool that allows parsing of a symbol language contained within .sym files in the sym/ directory of your repository, for the purpose of sourcing symbols across different versions of programs. After configuring ModuleList.sym and VersionList.sym, the following ways of adding symbols can be used:

// immediate symbols
@game:100

coolsymbol = 0x1234
coolsymbol_2 = 0x1238

@game:110 // different version

coolsymbol = 0x1334
coolsymbol_2 = 0x1338

// dynamic symbols:
@sdk:100,110 // multiple versions

_ZN2nn3abc7acquireEv = "_ZN2nn3abc7acquireEv"
_ZN2nn3abc7acquireEv // compact
_ZN2nn3abc8OneThingEv = "_ZN2nn3abc12AnotherThingEv" // different

// data search blocks

// version doesn't matter for data search
some_cool_sead_thingy = 0123456789ABCDEF @ game + 0x20 // < some instructions
some_other_sead_thingy = 0123456789ABCDEF @ game - 0x20
some_another_sead_thingy = 0?23????89AB???F @ game - 0x20 // masking

// data may change
some_other_sead_thingy2 = FEDCBA9876543210 @ game<110 - 0x20 // before 110
some_other_sead_thingy3 = 0123456789ABCDEF @ game>110 - 0x20 // at and after 110

// optimization
some_shit = 0123456789ABCDEF @ game:text + 0x20 // only search .text section
some_balls = 01234567 @ game:rodata // no addend

// addend

a_close_symbol = some_balls + 0x1000
another_close_symbol = a_close_symbol - 0x124

// ReadADRPGlobal
$some_adrp_ldr_instruction = 0123456789ABCDEF @ game - 0x20
some_global_variable = readAdrpGlobal($some_adrp_ldr_instruction)
some_global_variable = readAdrpGlobal($some_adrp_ldr_instruction, 0x2) // 0x2 indicates the offset of the LDR instruction from the ADRP instruction

Symbols can be accessed directly through linking, or through hk::util::lookupSymbol.

Feature Examples

using namespace hk;

// trampoline hook
HkTrampoline myHook = [](TrampolineStatic(), void* something) -> int /* don't forget the return type! */ {
    int value = orig(something); // call original function
    // do something ...
    return value;
};

static void test() { }

// executed at boot
extern "C" void hkMain() {
    // trampoline/replace
    myHook.installAtSym<"SomeFunction">(); // install to symbol provided by sail
    myHook.uninstall(); // hooks can be uninstalled
    myHook.installAtOffset(ro::getMainModule(), 0x1234); // by offset (not recommended)
    myHook.uninstall();
    myHook.installAtPtr(BlahFunc);
    myHook.installAtPtr(&BlahClass::Func);

    // replace hooks are also a thing, use HkReplace instead of HkTrampoline

    // b/bl branching to function
    hook::writeBranchLinkAtSym<"SomeFunction2">(test);
    hook::writeBranchAtPtr(1234, test);

    // writing to module
    ro::getMainModule()->writeRo<u32>(/* offset */ 0x12345678, /* u32 value */ 0xfefefefe);

    // constexpr AArch64 assembler
    hook::a64::assemble<"add x0, x0, {}">()
        .arg(1234)
        .installAtMainOffset(0x007feb88)
        .installAtSym<"Blablablabla">();

    hook::a64::assemble<"nop", true /* Uninstallable */>()
        .installAtMainOffset(0x12345678)
        .uninstall();
}

Credits:

  • shadowninja108
  • Sanae6 for sf implementation
  • marysaka for oss-rtld
  • tetraxile
  • GLOSHSEP

Code of conduct

Read the code of conduct for rules in engaging with this project.

This project is licensed under the 2-Clause BSD License in LICENSE.BSD2, as well as under the custom license in LICENSE.TDM.

The 2 licenses named above do not apply to the addons/ExpHeap subdirectory, it is individually licensed under the GNU GENERAL PUBLIC LICENSE Version 2 in addons/ExpHeap/LICENSE.

About

Nintendo Switch toolchain and code modification framework

Resources

Code of conduct

Contributing

Stars

Watchers

Forks

Releases

Contributors

Languages