#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <sys/mman.h>

#include "blobs.h"

int main(void) {
    setbuf(stdout, NULL);
    setbuf(stdin,  NULL);

    /* ------------------------------------------------------------------ *
     * Stage 1: decrypt blob1 with hardcoded key and execute it.
     *
     * blob1 is x86-64 shellcode — it immediately returns (C3).
     * After decryption its body contains flag1 in plaintext at offset +1.
     *
     * flag1 is both the first flag and the XOR key for blob2.
     * It is never returned to main; the participant must examine
     * the decrypted blob1 memory in a debugger to find it.
     * ------------------------------------------------------------------ */
    uint8_t *mem1 = mmap(NULL, BLOB1_SIZE,
                         PROT_READ | PROT_WRITE | PROT_EXEC,
                         MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    if (mem1 == MAP_FAILED) { perror("mmap"); return 1; }

    memcpy(mem1, blob1_encrypted, BLOB1_SIZE);

    for (size_t i = 0; i < BLOB1_SIZE; i++)
        mem1[i] ^= BLOB1_KEY;

    typedef void (*blob1_fn)(void);
    ((blob1_fn)mem1)();

    /* ------------------------------------------------------------------ *
     * Stage 2: ask for the key the participant found inside blob1.
     * There is no correctness check here — the key is used directly to
     * decrypt blob2.  Wrong key => garbled shellcode => crash or silence.
     * ------------------------------------------------------------------ */
    printf("Enter key: ");

    char key_input[256] = {0};
    if (fgets(key_input, sizeof(key_input), stdin) == NULL) {
        puts(":(");
        return 1;
    }
    size_t klen = strlen(key_input);
    if (klen > 0 && key_input[klen - 1] == '\n')
        key_input[--klen] = '\0';

    if (klen == 0) {
        puts(":(");
        return 1;
    }

    /* ------------------------------------------------------------------ *
     * Stage 3: decrypt blob2 using the participant-supplied key and run.
     *
     * blob2 is x86-64 shellcode that:
     *   - reads up to 4 bytes from stdin (raw syscall)
     *   - prints flag2 only if the input starts with "hey"
     * ------------------------------------------------------------------ */
    uint8_t *mem2 = mmap(NULL, BLOB2_SIZE,
                         PROT_READ | PROT_WRITE | PROT_EXEC,
                         MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    if (mem2 == MAP_FAILED) { perror("mmap"); return 1; }

    memcpy(mem2, blob2_encrypted, BLOB2_SIZE);

    for (size_t i = 0; i < BLOB2_SIZE; i++)
        mem2[i] ^= (uint8_t)key_input[i % klen];

    typedef void (*blob2_fn)(void);
    ((blob2_fn)mem2)();

    return 0;
}
