mmozeiko / aes-finder

Utility to find AES keys in running processes
957 stars 176 forks source link

Need some help #43

Open halloweeks opened 5 months ago

halloweeks commented 5 months ago

I am writing my own aes keys finding code in c language for jni android project, key finding works fine but problem is 'little endian', my code able to find only big endian keys

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/uio.h>
#include <time.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <stdbool.h>

#include "table.h" // aes table

#ifndef process_vm_readv
    #include <sys/syscall.h>
    #include <asm/unistd.h>

    ssize_t process_vm_readv(pid_t pid, const struct iovec *local_iov, unsigned long liovcnt, const struct iovec *remote_iov, unsigned long riovcnt, unsigned long flags) {
        return syscall(__NR_process_vm_readv, pid, local_iov, liovcnt, remote_iov, riovcnt, flags);
    }
#endif

ssize_t read_process_memory(pid_t pid, uintptr_t address, void *value, size_t size) {
    struct iovec local[1];
    struct iovec remote[1];
    local[0].iov_base = value;
    local[0].iov_len = size;
    remote[0].iov_base = (void*)address;
    remote[0].iov_len = size;
    return process_vm_readv(pid, local, 1, remote, 1, 0);
}

pid_t find_pid(const char *process_name) {
    DIR *dir = opendir("/proc");
    struct dirent *entry = NULL;
    char cmdline_path[256];
    char cmdline[256];
    int fd;

    if (dir == NULL) {
        return -1;
    }

    while ((entry = readdir(dir)) != NULL) {
        if ((strcmp(entry->d_name, ".") == 0) || (strcmp(entry->d_name, "..") == 0) || (entry->d_type != DT_DIR) || (strspn(entry->d_name, "0123456789") != strlen(entry->d_name))) {
            continue;
        }
        snprintf(cmdline_path, sizeof(cmdline_path), "/proc/%s/cmdline", entry->d_name);
        fd = open(cmdline_path, O_RDONLY);
        read(fd, cmdline, 256);
        close(fd);

        if (strstr(cmdline, process_name) != NULL) {
            closedir(dir);
            return atoi(entry->d_name);
        }
    }
    closedir(dir);
    return -1;
}

uint8_t get_module_address(pid_t process_id, const char *module_name, uint64_t *start_addr, uint64_t *end_addr) {
    char filename[256];
    char line[1024];
    FILE *fp = NULL;
    uint8_t address_found = 0;
    uint64_t start, end;
    uint8_t permission;

    snprintf(filename, sizeof(filename), "/proc/%d/maps", process_id);

    if (!(fp = fopen(filename, "r"))) {
        return 0;
    }

    while (fgets(line, sizeof(line), fp)) {
        if (strstr(line, module_name)) {
            if (sscanf(line, "%lx-%lx %c", &start, &end, &permission) == 3) {
                if (permission != 'r') {
                    continue;
                }
                address_found = 1;
                *start_addr = start;
                *end_addr = end;
                break;
            }
        }
    }

    fclose(fp);
    return address_found;
}

// Detection aes 128 encryption key
bool aes128_detect_enc(const unsigned int *data) {
    unsigned int roundkey[44];

    roundkey[0] = data[0];
    roundkey[1] = data[1];
    roundkey[2] = data[2];
    roundkey[3] = data[3];

    for (unsigned char index = 4; index < 44; index += 4) {
        roundkey[index] = roundkey[index - 4] ^ 
            (Te4[(roundkey[index - 1] >> 16) & 0xff] & 0xff000000) ^ 
            (Te4[(roundkey[index - 1] >>  8) & 0xff] & 0x00ff0000) ^ 
            (Te4[(roundkey[index - 1] >>  0) & 0xff] & 0x0000ff00) ^ 
            (Te4[(roundkey[index - 1] >> 24) & 0xff] & 0x000000ff) ^ rcon[index / 4 - 1];
        roundkey[index + 1] = roundkey[index - 3] ^ roundkey[index];
        roundkey[index + 2] = roundkey[index - 2] ^ roundkey[index + 1];
        roundkey[index + 3] = roundkey[index - 1] ^ roundkey[index + 2];
    }

    for (int index = 0; index < 44; index++) {
        if (roundkey[index] != data[index]) {
            return false;
        }
    }

    return true;
}

bool aes128_detect_dec(const unsigned int *data) {
    unsigned int roundkey[44];

    roundkey[0] = data[40];
    roundkey[1] = data[41];
    roundkey[2] = data[42];
    roundkey[3] = data[43];

    for (unsigned char index = 4; index < 44; index += 4) {
        roundkey[index] = roundkey[index - 4] ^ 
            (Te4[(roundkey[index - 1] >> 16) & 0xff] & 0xff000000) ^ 
            (Te4[(roundkey[index - 1] >>  8) & 0xff] & 0x00ff0000) ^ 
            (Te4[(roundkey[index - 1] >>  0) & 0xff] & 0x0000ff00) ^ 
            (Te4[(roundkey[index - 1] >> 24) & 0xff] & 0x000000ff) ^ rcon[index / 4 - 1];
        roundkey[index + 1] = roundkey[index - 3] ^ roundkey[index];
        roundkey[index + 2] = roundkey[index - 2] ^ roundkey[index + 1];
        roundkey[index + 3] = roundkey[index - 1] ^ roundkey[index + 2];
    }

    unsigned int temp;

    // Next, invert the order of the round keys.
    for (unsigned char i = 0, j = 40; i < j; i += 4, j -= 4) {
        for (uint8_t k = 0; k < 4; k++) {
            temp = roundkey[i + k];
            roundkey[i + k] = roundkey[j + k];
            roundkey[j + k] = temp;
        }
    }

    // Finally, apply the inverse MixColumn transform to all round keys except the first and last.
    for (unsigned char index = 4; index < 40; index += 4) {
        roundkey[index] =
            Td0[Te4[(roundkey[index] >> 24) & 0xff] & 0xff] ^
            Td1[Te4[(roundkey[index] >> 16) & 0xff] & 0xff] ^
            Td2[Te4[(roundkey[index] >>  8) & 0xff] & 0xff] ^
            Td3[Te4[(roundkey[index] >>  0) & 0xff] & 0xff];
        roundkey[index + 1] =
            Td0[Te4[(roundkey[index + 1] >> 24) & 0xff] & 0xff] ^
            Td1[Te4[(roundkey[index + 1] >> 16) & 0xff] & 0xff] ^
            Td2[Te4[(roundkey[index + 1] >>  8) & 0xff] & 0xff] ^
            Td3[Te4[(roundkey[index + 1] >>  0) & 0xff] & 0xff];
        roundkey[index + 2] =
            Td0[Te4[(roundkey[index + 2] >> 24) & 0xff] & 0xff] ^
            Td1[Te4[(roundkey[index + 2] >> 16) & 0xff] & 0xff] ^
            Td2[Te4[(roundkey[index + 2] >>  8) & 0xff] & 0xff] ^
            Td3[Te4[(roundkey[index + 2] >>  0) & 0xff] & 0xff];
        roundkey[index + 3] =
            Td0[Te4[(roundkey[index + 3] >> 24) & 0xff] & 0xff] ^
            Td1[Te4[(roundkey[index + 3] >> 16) & 0xff] & 0xff] ^
            Td2[Te4[(roundkey[index + 3] >>  8) & 0xff] & 0xff] ^
            Td3[Te4[(roundkey[index + 3] >>  0) & 0xff] & 0xff];
    }

    for (int x = 0; x < 44; x++) {
        if (roundkey[x] != data[x]) {
            return false;
        }
    }

    return true;
}

void find_keys(const unsigned long long address, const uint8_t *buffer) {
    uint32_t *data = (uint32_t*)buffer;

    if (aes128_detect_enc(data)) {
        printf("[%p] Found AES-128 encryption key: 0x", (void*)address);
        for (int index = 0; index < 4; index++) {
            printf("%X", data[index]);
        }
        printf("\n");
    } else if (aes128_detect_dec(data)) {
        printf("[%p] Found AES-128 decryption key: 0x", (void*)address);
        for (int index = 40; index < 44; index++) {
            printf("%X", data[index]);
        }
        printf("\n");
    }
}

int main(int argc, const char *argv[]) {
    const char* package = argv[1]; // target program or application
    const char* module = "[stack]"; // target module

    uint64_t start = 0, end = 0;
    uint8_t data[240];

    pid_t pid = -1;

    printf("[INFO] Waiting for opening '%s' process\n", package);

    while (pid == -1) {
        pid = find_pid(package);
    }

    printf("[INFO] Process '%s' is now open pid %d\n", package, pid);

    printf("[INFO] Searching keys...\n");

    if (!get_module_address(pid, module, &start, &end)) {
        printf("[ERROR] Can't find module address\n");
        return 1;
    }

    uint64_t address = start;
    uint64_t remaining = end - start;

    while (remaining > 0) {
        if (read_process_memory(pid, address, data, 240) == -1) {
            printf("[ERROR] Can't read memory at %p\n", (void*)&start);
            break;
        }

        find_keys(address, data);

        remaining--;
        address++;
    }

    return 0;
}
halloweeks commented 5 months ago

With big endian Screenshot_2024-05-14-12-04-40-26_84d3000e3f4017145260f7618db1d683

With little endian Screenshot_2024-05-14-12-04-55-80_84d3000e3f4017145260f7618db1d683

mmozeiko commented 5 months ago

See how reversed template argument is used here: https://github.com/mmozeiko/aes-finder/blob/master/aes-finder.cpp#L178C16-L178C24 It is once used as true, and other time false thus checking both formats, when expanded key is stored in little or big endian.