Exemple #1
0
static status_t init_task_kaslr_test(vmi_instance_t vmi, addr_t page_vaddr) {
    status_t ret = VMI_FAILURE;
    uint32_t pid;
    addr_t init_task = page_vaddr + (vmi->init_task & VMI_BIT_MASK(0,11));
    linux_instance_t linux_instance = vmi->os_data;
    access_context_t ctx = {
        .translate_mechanism = VMI_TM_PROCESS_DTB,
        .dtb = vmi->kpgd
    };

    ctx.addr = init_task + linux_instance->pid_offset;
    if ( VMI_FAILURE == vmi_read_32(vmi, &ctx, &pid) )
        return ret;

    if ( pid )
        return ret;

    ctx.addr = init_task + linux_instance->name_offset;
    char* init_task_name = vmi_read_str(vmi, &ctx);

    if ( init_task_name && !strncmp("swapper", init_task_name, 7) )
        ret = VMI_SUCCESS;

    free(init_task_name);
    return ret;
}

status_t init_kaslr(vmi_instance_t vmi) {
    /*
     * Let's check if we can translate init_task first as is.
     */
    uint32_t test;
    access_context_t ctx = {
        .translate_mechanism = VMI_TM_PROCESS_DTB,
        .dtb = vmi->kpgd,
        .addr = vmi->init_task
    };

    if ( VMI_SUCCESS == vmi_read_32(vmi, &ctx, &test) )
        return VMI_SUCCESS;

    status_t ret = VMI_FAILURE;
    linux_instance_t linux_instance = vmi->os_data;
    GSList *loop, *pages = vmi_get_va_pages(vmi, vmi->kpgd);
    loop = pages;
    while (loop) {
        page_info_t *info = loop->data;

        if ( !linux_instance->kaslr_offset ) {
            switch(vmi->page_mode) {
                case VMI_PM_AARCH64:
                case VMI_PM_IA32E:
                    if ( VMI_GET_BIT(info->vaddr, 47) )
                        ret = init_task_kaslr_test(vmi, info->vaddr);
                    break;
                default:
                    ret = init_task_kaslr_test(vmi, info->vaddr);
                    break;
            };

            if ( VMI_SUCCESS == ret ) {
                linux_instance->kaslr_offset = info->vaddr - (vmi->init_task & ~VMI_BIT_MASK(0,11));
                vmi->init_task += linux_instance->kaslr_offset;
                dbprint(VMI_DEBUG_MISC, "**calculated KASLR offset: 0x%"PRIx64"\n", linux_instance->kaslr_offset);
            }
        }

        g_free(info);
        loop = loop->next;
    }

    g_slist_free(pages);
    return ret;
}

status_t linux_init(vmi_instance_t vmi) {

    status_t rc;
    os_interface_t os_interface = NULL;

    if (vmi->config == NULL) {
        errprint("No config table found\n");
        return VMI_FAILURE;
    }

    if (vmi->os_data != NULL) {
        errprint("os data already initialized, reinitializing\n");
        free(vmi->os_data);
    }

    vmi->os_data = safe_malloc(sizeof(struct linux_instance));
    bzero(vmi->os_data, sizeof(struct linux_instance));
    linux_instance_t linux_instance = vmi->os_data;

    g_hash_table_foreach(vmi->config, (GHFunc)linux_read_config_ghashtable_entries, vmi);

    if(linux_instance->rekall_profile)
        rc = init_from_rekall_profile(vmi);
    else
        rc = linux_symbol_to_address(vmi, "init_task", NULL, &vmi->init_task);

    if (VMI_FAILURE == rc) {
        errprint("Could not get init_task from Rekall profile or System.map\n");
        goto _exit;
    }

    vmi->init_task = canonical_addr(vmi->init_task);

#if defined(ARM32) || defined(ARM64)
    rc = driver_get_vcpureg(vmi, &vmi->kpgd, TTBR1, 0);
#elif defined(I386) || defined(X86_64)
    rc = driver_get_vcpureg(vmi, &vmi->kpgd, CR3, 0);
#endif

    /*
     * The driver failed to get us a pagetable.
     * As a fall-back, try to init using heuristics.
     * This path is taken in FILE mode as well.
     */
    if (VMI_FAILURE == rc)
        if (VMI_FAILURE == linux_filemode_init(vmi))
            goto _exit;

    if ( VMI_FAILURE == init_kaslr(vmi) ) {
        dbprint(VMI_DEBUG_MISC, "**failed to determine KASLR offset\n");
        goto _exit;
    }

    dbprint(VMI_DEBUG_MISC, "**set vmi->kpgd (0x%.16"PRIx64").\n", vmi->kpgd);

    os_interface = safe_malloc(sizeof(struct os_interface));
    bzero(os_interface, sizeof(struct os_interface));
    os_interface->os_get_offset = linux_get_offset;
    os_interface->os_pid_to_pgd = linux_pid_to_pgd;
    os_interface->os_pgd_to_pid = linux_pgd_to_pid;
    os_interface->os_ksym2v = linux_symbol_to_address;
    os_interface->os_usym2rva = NULL;
    os_interface->os_v2sym = linux_system_map_address_to_symbol;
    os_interface->os_read_unicode_struct = NULL;
    os_interface->os_teardown = linux_teardown;

    vmi->os_interface = os_interface;

    return VMI_SUCCESS;

    _exit:
    free(vmi->os_data);
    vmi->os_data = NULL;
    return VMI_FAILURE;
}
Exemple #2
0
event_response_t cr3_callback(vmi_instance_t vmi, vmi_event_t *event) {

    va_pages = vmi_get_va_pages(vmi, event->reg_event.value);

    GSList *loop = va_pages;
    while(loop) {
        page_info_t *page = loop->data;

        // Demonstrate using access_context_t
        access_context_t ctx = {
            .translate_mechanism = VMI_TM_PROCESS_DTB,
            .addr = page->vaddr,
            .dtb = event->reg_event.value,
        };

        uint64_t test;
        if(VMI_FAILURE == vmi_read_64(vmi, &ctx, &test)) {
            printf("Page in virtual address space of DTB 0x%"PRIx64" unaccessible: 0x%"PRIx64".\t"
                   "Size: 0x%"PRIx64"\n",
                   ctx.dtb, page->vaddr, (uint64_t)page->size);
        }

        loop=loop->next;
    }
    free_va_pages();
    return 0;
}

int main (int argc, char **argv)
{
    vmi_instance_t vmi = NULL;
    status_t status = VMI_SUCCESS;

    struct sigaction act;

    char *name = NULL;
    va_pages = NULL;

    if(argc < 2) {
        fprintf(stderr, "Usage: events_example <name of VM>\n");
        exit(1);
    }

    // Arg 1 is the VM name.
    name = argv[1];

    /* for a clean exit */
    act.sa_handler = close_handler;
    act.sa_flags = 0;
    sigemptyset(&act.sa_mask);
    sigaction(SIGHUP,  &act, NULL);
    sigaction(SIGTERM, &act, NULL);
    sigaction(SIGINT,  &act, NULL);
    sigaction(SIGALRM, &act, NULL);

    // Initialize the libvmi library.
    if (vmi_init(&vmi, VMI_XEN | VMI_INIT_COMPLETE | VMI_INIT_EVENTS, name) == VMI_FAILURE) {
        printf("Failed to init LibVMI library.\n");
        if (vmi != NULL ) {
            vmi_destroy(vmi);
        }
        return 1;
    }
    else {
        printf("LibVMI init succeeded!\n");
    }

    /* Configure an event to track when the process is running.
     * (The CR3 register is updated on task context switch, allowing
     *  us to follow as various tasks are scheduled and run upon the CPU)
     */
    SETUP_REG_EVENT(&cr3_event, CR3, VMI_REGACCESS_W, 0, cr3_callback);
    vmi_register_event(vmi, &cr3_event);

    while(!interrupted) {
        printf("Waiting for events...\n");
        status = vmi_events_listen(vmi,500);
        if (status != VMI_SUCCESS) {
            printf("Error waiting for events, quitting...\n");
            interrupted = -1;
        }
    }
    printf("Finished with test.\n");

    free_va_pages();
    // cleanup any memory associated with the libvmi instance
    vmi_destroy(vmi);

    return 0;
}
Exemple #3
0
status_t
find_kdbg_address_fast(
    vmi_instance_t vmi,
    addr_t *kdbg_pa,
    addr_t *kernel_pa,
    addr_t *kernel_va)
{

    dbprint(VMI_DEBUG_MISC, "**Trying find_kdbg_address_fast\n");

    status_t ret = VMI_FAILURE;
    reg_t cr3;
    if (VMI_FAILURE == driver_get_vcpureg(vmi, &cr3, CR3, 0)) {
        return ret;
    }

    addr_t memsize = vmi_get_max_physical_address(vmi);
    GSList *va_pages = vmi_get_va_pages(vmi, (addr_t)cr3);
    void *bm = 0;   // boyer-moore internal state
    unsigned char haystack[VMI_PS_4KB];
    int find_ofs = 0;

    if (VMI_PM_IA32E == vmi->page_mode) {
        bm = boyer_moore_init((unsigned char *)"\x00\xf8\xff\xffKDBG", 8);
        find_ofs = 0xc;
    } else {
        bm = boyer_moore_init((unsigned char *)"\x00\x00\x00\x00\x00\x00\x00\x00KDBG",
                              12);
        find_ofs = 0x8;
    }   // if-else

    GSList *va_pages_loop = va_pages;
    while (va_pages_loop) {

        page_info_t *vap = (page_info_t *)va_pages_loop->data;

        // We might get pages that are greater than 4Kb
        // so we are just going to split them to 4Kb pages
        while (vap && vap->size >= VMI_PS_4KB) {
            vap->size -= VMI_PS_4KB;
            addr_t page_paddr = vap->paddr+vap->size;

            if (page_paddr + VMI_PS_4KB - 1 > memsize) {
                continue;
            }

            if ( VMI_FAILURE == vmi_read_pa(vmi, page_paddr, VMI_PS_4KB, haystack, NULL) )
                continue;

            int match_offset = boyer_moore2(bm, haystack, VMI_PS_4KB);

            if (-1 != match_offset) {

                addr_t tmp_kva = 0, tmp_kpa = 0;
                addr_t tmp_kdbg = page_paddr + (unsigned int) match_offset - find_ofs;

                if (VMI_FAILURE == vmi_read_64_pa(vmi, tmp_kdbg + sizeof(DBGKD_DEBUG_DATA_HEADER64), &tmp_kva)) {
                    continue;
                }

                if ( VMI_FAILURE == vmi_pagetable_lookup(vmi, cr3, tmp_kva, &tmp_kpa) )
                    continue;

                *kdbg_pa = tmp_kdbg;
                *kernel_va = tmp_kva;
                *kernel_pa = tmp_kpa;

                ret = VMI_SUCCESS;

                goto done;
            }
        }
        g_free(vap);
        va_pages_loop = va_pages_loop->next;
    }

done:
    // free the rest of the list
    while (va_pages_loop) {
        g_free(va_pages_loop->data);
        va_pages_loop = va_pages_loop->next;
    }
    g_slist_free(va_pages);

    if (VMI_SUCCESS == ret)
        dbprint(VMI_DEBUG_MISC, "--Found KdDebuggerDataBlock at PA %.16"PRIx64"\n", *kdbg_pa);
    boyer_moore_fini(bm);
    return ret;
}