Projects#

C projects in the operator’s sweet spot, small system utilities, parsers, kernel-adjacent code, and the foundations the operator will eventually have to read in a CVE write-up.

Protocol parser#

A safe parser for a binary network protocol. Write one when reverse-engineering a private wire format or building a high-throughput frontend (the parser has to be in C for performance).

/* op_parser.c */
#include <stdint.h>
#include <stddef.h>
#include <string.h>

typedef struct {
    uint8_t  version;
    uint16_t length;
    uint16_t flags;
    const uint8_t *payload;
} op_packet_t;

/* Returns 0 on success, -1 on malformed input. */
int op_parse(const uint8_t *buf, size_t buf_len, op_packet_t *out) {
    if (buf_len < 5) return -1;             /* fixed header is 5 bytes */
    out->version = buf[0];
    memcpy(&out->length, buf + 1, 2);
    memcpy(&out->flags,  buf + 3, 2);
    if (out->length > buf_len - 5) return -1;
    out->payload = buf + 5;
    return 0;
}

Build with sanitisers enabled while developing.

$ clang -std=c11 -Wall -Wextra -Werror \
    -fsanitize=address,undefined -g -O1 \
    op_parser.c test_parser.c -o test_parser
$ ./test_parser

syscall wrapper#

A small library that wraps a syscall you want to use from higher-level code (Python via ctypes, Go via cgo).

/* memfd.c */
#define _GNU_SOURCE
#include <sys/mman.h>
#include <stdint.h>
#include <unistd.h>

int op_memfd_create(const char *name, unsigned int flags) {
    return memfd_create(name, flags);
}

ssize_t op_write_all(int fd, const void *buf, size_t n) {
    const uint8_t *p = buf;
    while (n > 0) {
        ssize_t w = write(fd, p, n);
        if (w < 0) return -1;
        p += w; n -= (size_t)w;
    }
    return 0;
}

Compile as a shared library for FFI from Python or Go.

$ clang -fPIC -shared -o libmemfd.so memfd.c

File scanner#

The classic operator tool, walk a tree, hash each file, write a JSON-Lines manifest. Fast because it’s in C.

#include <stdio.h>
#include <stdlib.h>
#include <ftw.h>
#include <openssl/sha.h>

static int handle(const char *path, const struct stat *st,
                  int type, struct FTW *ftw) {
    if (type != FTW_F) return 0;
    FILE *f = fopen(path, "rb");
    if (!f) return 0;
    SHA256_CTX c; SHA256_Init(&c);
    unsigned char buf[65536]; size_t n;
    while ((n = fread(buf, 1, sizeof(buf), f)) > 0)
        SHA256_Update(&c, buf, n);
    fclose(f);
    unsigned char d[SHA256_DIGEST_LENGTH];
    SHA256_Final(d, &c);
    printf("{\"path\":\"%s\",\"sha256\":\"", path);
    for (int i = 0; i < SHA256_DIGEST_LENGTH; i++)
        printf("%02x", d[i]);
    printf("\",\"size\":%lld}\n", (long long)st->st_size);
    return 0;
}

int main(int argc, char **argv) {
    if (argc < 2) return 2;
    nftw(argv[1], handle, 16, FTW_PHYS);
    return 0;
}

Embedded firmware#

The operator’s “small thing that runs forever” project. C is inevitable on bare-metal microcontrollers (STM32, AVR, ESP32 in C mode). Build with arm-none-eabi-gcc; debug via OpenOCD + GDB.

/* main.c (STM32) */
#include "stm32f4xx.h"

void main(void) {
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN;
    GPIOD->MODER |= (1 << (12 * 2));
    while (1) {
        GPIOD->ODR ^= (1 << 12);
        for (volatile int i = 0; i < 1000000; i++);
    }
}

References#