Skip to main content

Quick Start

Get up and running with STX, the modern C++23 systems toolbelt for low-level binary analysis, memory manipulation, and security research.

What is STX?

STX is a header-only C++23 library providing type-safe, zero-overhead abstractions for:

Memory Operations

Safe, low-level memory access and alignment primitives

Binary I/O

Type-safe file operations for binary parsing

Function Wrappers

Strongly-typed wrappers around memory addresses

Time Utilities

UNIX time conversions and high-resolution stopwatch

Prerequisites

STX requires a C++23-compliant compiler:
  • Clang 16+
  • GCC 14+
  • MSVC 19.34+
For C++ Modules support, you’ll also need CMake 3.28+.

Your First STX Program

Let’s create a simple program that demonstrates STX’s type-safe memory operations.
1

Include STX

Start by including the main STX header:
#include <lbyte/stx.hpp>
#include <print>

using namespace lbyte::stx;
The library provides both traditional headers and C++23 modules. Choose the approach that fits your build system.
2

Use Strong Types

STX provides strong types for type-safe operations:
int main() {
    // Strong types prevent accidental misuse
    offset_t file_offset{0x1000};
    rva_t relative_address{0x2000};
    va_t virtual_address{0x400000};

    std::println("File offset: 0x{:x}", file_offset.get());
    std::println("RVA: 0x{:x}", relative_address.get());
    std::println("VA: 0x{:x}", virtual_address.get());

    return 0;
}
Strong types like offset_t, rva_t, and va_t provide compile-time safety and prevent mixing different address types.
3

Memory Operations

Demonstrate safe memory reading:
#include <lbyte/stx.hpp>
#include <print>
#include <array>

using namespace lbyte::stx;

int main() {
    // Create a buffer to read from
    std::array<u8, 16> buffer = {
        0x48, 0x65, 0x6C, 0x6C, // "Hell"
        0x6F, 0x20, 0x53, 0x54, // "o ST"
        0x58, 0x21, 0x00, 0x00, // "X!"
        0xDE, 0xAD, 0xBE, 0xEF  // 0xEFBEADDE
    };

    // Safe copy-based read (works with unaligned memory)
    auto value = read<u32>(buffer.data(), offset_t{12});
    std::println("Read value: 0x{:08x}", value);

    // Align operations
    auto addr = 0x1234u;
    std::println("Original: 0x{:x}", addr);
    std::println("Aligned up to 16: 0x{:x}", align_up(addr, 16u));
    std::println("Aligned down to 16: 0x{:x}", align_down(addr, 16u));

    return 0;
}
4

Binary File Reading

Create a complete example that reads a binary file:
#include <lbyte/stx.hpp>
#include <fstream>
#include <print>

using namespace lbyte::stx;

struct Header {
    u32 magic;
    u32 version;
    u64 timestamp;
};

int main() {
    std::ifstream file{"data.bin", std::ios::binary};
    if (!file.is_open()) {
        std::println(stderr, "Failed to open file");
        return 1;
    }

    // Type-safe file reading
    auto header = readfs<Header>(file);
    std::println("Magic: 0x{:08x}", header.magic);
    std::println("Version: {}", header.version);
    std::println("Timestamp: {}", header.timestamp);

    // Read bulk data into optimized buffer
    auto data = readfs<u8>(file, offset_t{sizeof(Header)}, 256);
    std::println("Read {} bytes", data.size());

    return 0;
}
The readfs function provides type-safe, offset-based file reading. The dirty_vector return type avoids unnecessary zero-initialization for better performance.

Complete Example: PE Section Reader

Here’s a real-world example from the STX documentation that demonstrates parsing a PE file:
#include <lbyte/stx.hpp>
#include <fstream>
#include <print>

using namespace lbyte::stx;

int main() {
    std::ifstream file{"target.dll", std::ios::binary};
    if (!file.is_open()) return EXIT_FAILURE;

    // Read DOS and NT headers
    auto dos = readfs<IMAGE_DOS_HEADER>(file);
    auto nt  = readfs<IMAGE_NT_HEADERS64>(file, offset_t{dos.e_lfanew});

    // Calculate Section Table offset
    auto sections_offset = offset_t{
        dos.e_lfanew
        + sizeof(u32)
        + sizeof(IMAGE_FILE_HEADER)
        + nt.FileHeader.SizeOfOptionalHeader
    };

    // Bulk read sections into optimized buffer
    auto sections = readfs<IMAGE_SECTION_HEADER>(
        file,
        sections_offset,
        nt.FileHeader.NumberOfSections
    );

    for (const auto& sec : sections) {
        std::println("Section: {}", sec.get_name());
    }

    return EXIT_SUCCESS;
}
This example demonstrates:
  • Type-safe file reading with readfs
  • Offset arithmetic using offset_t
  • Bulk allocation with dirty_vector
  • Strong-type safe iteration

Key Concepts

Strong Types

STX uses strong types to prevent common errors:
TypePurposeExample
offset_tFile or buffer offsetsoffset_t{0x1000}
rva_tRelative virtual addressesrva_t{0x2000}
va_tVirtual addressesva_t{0x400000}

Type Aliases

Convenient shorthand for common types:
using namespace lbyte::stx;

u8, u16, u32, u64    // Unsigned integers
i8, i16, i32, i64    // Signed integers
f32, f64              // Floating point
usize, isize          // Size types
uptr, iptr            // Pointer-sized integers

Memory Safety

STX provides both safe and raw memory operations:
  • read<T>() / write<T>(): Use memcpy, safe for unaligned access
  • read_raw<T>() / write_raw<T>(): Direct dereference, requires alignment

Next Steps

Installation

Learn how to integrate STX into your project

Memory API

Explore memory manipulation utilities

File System API

Type-safe binary file operations

GitHub Repository

View the source code and examples

Build docs developers (and LLMs) love