Exemple #1
0
static addr_t
find_kdversionblock_address_fast(
    vmi_instance_t vmi)
{
    // Note: this function has several limitations:
    // -the KD version block signature cannot cross block (frame) boundaries
    // -reading PA 0 fails; hope the KD version block is not in frame 0
    // 
    // Todo:
    // -support matching across frames (can this happen in windows?)

    addr_t kdvb_address = 0;
    addr_t block_pa = 0;
    addr_t memsize = vmi_get_memsize(vmi);
    size_t read = 0;
    void *bm = 0;   // boyer-moore internal state
    int find_ofs = 0;

#define BLOCK_SIZE 1024 * 1024 * 1
    unsigned char haystack[BLOCK_SIZE];

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

    for (block_pa = 4096; block_pa < memsize; block_pa += BLOCK_SIZE) {
        read = vmi_read_pa(vmi, block_pa, haystack, BLOCK_SIZE);
        if (BLOCK_SIZE != read) {
            continue;
        }

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

        if (-1 != match_offset) {
            kdvb_address =
                block_pa + (unsigned int) match_offset - find_ofs;
            break;
        }   // if
    }   // outer for

    if (kdvb_address)
        dbprint("--Found KD version block at PA %.16"PRIx64"\n",
                kdvb_address);
    boyer_moore_fini(bm);
    return kdvb_address;
}
Exemple #2
0
int
find_pname_offset(
    vmi_instance_t vmi,
    check_magic_func check)
{
    addr_t block_pa = 0;
    addr_t offset = 0;
    uint32_t value = 0;
    void *bm = 0;

    bm = boyer_moore_init((unsigned char *)"Idle", 4);

#define BLOCK_SIZE 1024 * 1024 * 1
    unsigned char block_buffer[BLOCK_SIZE];

    if (NULL == check) {
        check = get_check_magic_func(vmi);
    }

    for (block_pa = 4096; block_pa + BLOCK_SIZE < vmi->max_physical_address; block_pa += BLOCK_SIZE) {
        if ( VMI_FAILURE == vmi_read_pa(vmi, block_pa, BLOCK_SIZE, block_buffer, NULL) ) {
            continue;
        }

        for (offset = 0; offset < BLOCK_SIZE; offset += 8) {
            memcpy(&value, block_buffer + offset, 4);

            if (check(value)) { // look for specific magic #
                dbprint
                    (VMI_DEBUG_MISC, "--%s: found magic value 0x%.8"PRIx32" @ offset 0x%.8"PRIx64"\n",
                     __FUNCTION__, value, block_pa + offset);

                unsigned char haystack[0x500];

                if ( VMI_FAILURE == vmi_read_pa(vmi, block_pa + offset, 0x500, haystack, NULL) ) {
                    continue;
                }

                int i = boyer_moore2(bm, haystack, 0x500);

                if (-1 == i) {
                    continue;
                }
                else {
                    vmi->init_task = block_pa + offset;
                    dbprint
                        (VMI_DEBUG_MISC, "--%s: found Idle process at 0x%.8"PRIx64" + 0x%x\n",
                         __FUNCTION__, block_pa + offset, i);
                    boyer_moore_fini(bm);
                    return i;
                }
            }
        }
    }
    boyer_moore_fini(bm);
    return 0;
}
Exemple #3
0
status_t
find_kdbg_address_faster(
    vmi_instance_t vmi,
    addr_t *kdbg_pa,
    addr_t *kernel_pa,
    addr_t *kernel_va)
{

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

    status_t ret = VMI_FAILURE;

    // This scan requires the location of the KPCR
    // which we get from the GS/FS register on live machines.
    // For file mode this needs to be further investigated.
    if (VMI_FILE == vmi->mode) {
        return ret;
    }

    void *bm = boyer_moore_init((unsigned char *)"KDBG", 4);
    int find_ofs = 0x10;

    reg_t cr3 = 0, fsgs = 0;
    if (VMI_FAILURE == driver_get_vcpureg(vmi, &cr3, CR3, 0)) {
        goto done;
    }

    switch ( vmi->page_mode ) {
        case VMI_PM_IA32E:
            if (VMI_FAILURE == driver_get_vcpureg(vmi, &fsgs, GS_BASE, 0))
                goto done;
            break;
        case VMI_PM_LEGACY: /* Fall-through */
        case VMI_PM_PAE:
            if (VMI_FAILURE == driver_get_vcpureg(vmi, &fsgs, FS_BASE, 0))
                goto done;
            break;
        default:
            goto done;
    };

    // We start the search from the KPCR, which has to be mapped into the kernel.
    // We further know that the Windows kernel is page aligned
    // so we are just checking if the page has a valid PE header
    // and if the first item in the export table is "ntoskrnl.exe".
    // Once the kernel is found, we find the .data section
    // and limit the string search for "KDBG" into that region.

    // start searching at the lower part from the kpcr
    // then switch to the upper part if needed
    int step = -VMI_PS_4KB;
    addr_t page_paddr;
    access_context_t ctx = {
        .translate_mechanism = VMI_TM_NONE,
    };

scan:
    if ( VMI_FAILURE == vmi_pagetable_lookup(vmi, cr3, fsgs, &page_paddr) )
        goto done;

    page_paddr &= ~VMI_BIT_MASK(0,11);

    for (; page_paddr + step < vmi->max_physical_address; page_paddr += step) {

        uint8_t page[VMI_PS_4KB];
        ctx.addr = page_paddr;
        status_t rc = peparse_get_image(vmi, &ctx, VMI_PS_4KB, page);
        if (VMI_FAILURE == rc) {
            continue;
        }

        struct pe_header *pe_header = NULL;
        struct dos_header *dos_header = NULL;
        void *optional_pe_header = NULL;
        uint16_t optional_header_type = 0;
        struct export_table et;

        peparse_assign_headers(page, &dos_header, &pe_header, &optional_header_type, &optional_pe_header, NULL, NULL);
        addr_t export_header_offset =
            peparse_get_idd_rva(IMAGE_DIRECTORY_ENTRY_EXPORT, &optional_header_type, optional_pe_header, NULL, NULL);

        if (!export_header_offset || page_paddr + export_header_offset >= vmi->max_physical_address)
            continue;

        if ( VMI_SUCCESS == vmi_read_pa(vmi, page_paddr + export_header_offset, sizeof(struct export_table), &et, NULL)) {
            if ( !(et.export_flags || !et.name) && page_paddr + et.name + 12 >= vmi->max_physical_address)
                continue;

            unsigned char name[13] = {0};
            if ( VMI_FAILURE == vmi_read_pa(vmi, page_paddr + et.name, 12, name, NULL) )
                continue;

            if (strcmp("ntoskrnl.exe", (const char *)name)) {
                continue;
            }
        } else {
            continue;
        }

        uint32_t c;
        for (c=0; c < pe_header->number_of_sections; c++) {

            struct section_header section;
            addr_t section_addr = page_paddr
                                  + dos_header->offset_to_pe
                                  + sizeof(struct pe_header)
                                  + pe_header->size_of_optional_header
                                  + c*sizeof(struct section_header);

            // Read the section header from memory
            if ( VMI_FAILURE == vmi_read_pa(vmi, section_addr, sizeof(struct section_header), (uint8_t *)&section, NULL) )
                continue;

            // .data check
            if (memcmp(section.short_name, "\x2E\x64\x61\x74\x61", 5) != 0) {
                continue;
            }

            uint8_t *haystack = alloca(section.size_of_raw_data);
            if ( VMI_FAILURE == vmi_read_pa(vmi, page_paddr + section.virtual_address, section.size_of_raw_data, haystack, NULL) )
                continue;

            int match_offset = boyer_moore2(bm, haystack, section.size_of_raw_data);

            if (-1 != match_offset) {
                // We found the structure, but let's verify it.
                // The kernel is always mapped into VA at the same offset
                // it is found on physical memory + the kernel boundary.

                // Read "KernBase" from the haystack
                uint64_t *kernbase = (uint64_t *)&haystack[(unsigned int) match_offset + sizeof(uint64_t)];
                int zeroes = __builtin_clzll(page_paddr);

                if ((*kernbase) << zeroes == page_paddr << zeroes) {

                    *kernel_pa = page_paddr;
                    *kernel_va = *kernbase;
                    *kdbg_pa = page_paddr + section.virtual_address + (unsigned int) match_offset - find_ofs;

                    ret = VMI_SUCCESS;

                    dbprint(VMI_DEBUG_MISC,
                            "--Found KdDebuggerDataBlock at PA %.16"PRIx64"\n", *kdbg_pa);

                    goto done;
                } else {
                    dbprint(VMI_DEBUG_MISC,
                            "--WARNING: KernBase in KdDebuggerDataBlock at PA %.16"PRIx64" doesn't point back to this page.\n",
                            page_paddr + section.virtual_address + (unsigned int) match_offset - find_ofs);
                }
            }

            break;
        }
    }

    if (step<0) {
        step = VMI_PS_4KB;
        goto scan;
    }

done:
    boyer_moore_fini(bm);
    return ret;
}
Exemple #4
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;
}
Exemple #5
0
status_t find_kdbg_address(
    vmi_instance_t vmi,
    addr_t *kdbg_pa,
    addr_t *kernel_va)
{

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

    status_t ret = VMI_FAILURE;
    *kdbg_pa = 0;
    addr_t paddr = 0;
    unsigned char haystack[VMI_PS_4KB];
    addr_t memsize = vmi_get_max_physical_address(vmi);

    void *bm64 = boyer_moore_init((unsigned char *)"\x00\xf8\xff\xffKDBG", 8);
    void *bm32 = boyer_moore_init((unsigned char *)"\x00\x00\x00\x00\x00\x00\x00\x00KDBG",
                                  12);
    uint32_t find_ofs_64 = 0xc, find_ofs_32 = 0x8, find_ofs = 0;

    for (; paddr<memsize; paddr+=VMI_PS_4KB) {

        find_ofs = 0;

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

        int match_offset = boyer_moore2(bm64, haystack, VMI_PS_4KB);
        if (-1 != match_offset) {
            find_ofs = find_ofs_64;
        } else {
            match_offset = boyer_moore2(bm32, haystack, VMI_PS_4KB);
        }

        if (-1 != match_offset) {

            if (!find_ofs) {
                find_ofs = find_ofs_32;
            }

            // Read "KernBase" from the haystack
            long unsigned int kernbase_offset = 0;
            kdbg_symbol_offset("KernBase", &kernbase_offset);

            if ( match_offset - find_ofs + kernbase_offset + sizeof(uint64_t) >= VMI_PS_4KB )
                continue;

            memcpy(kernel_va, &haystack[(unsigned int) match_offset - find_ofs + kernbase_offset], sizeof(uint64_t));
            *kdbg_pa = paddr + (unsigned int) match_offset - find_ofs;

            ret = VMI_SUCCESS;

            break;
        }
    }

    dbprint(VMI_DEBUG_MISC, "--Found KdDebuggerDataBlock at PA %.16"PRIx64"\n", *kdbg_pa);

    boyer_moore_fini(bm32);
    boyer_moore_fini(bm64);
    return ret;
}
int
find_pname_offset(
    vmi_instance_t vmi,
    check_magic_func check)
{
    addr_t block_pa = 0;
    addr_t offset = 0;
    uint32_t value = 0;
    size_t read = 0;
    void *bm = 0;

    bm = boyer_moore_init("Idle", 4);

#define BLOCK_SIZE 1024 * 1024 * 1
    unsigned char block_buffer[BLOCK_SIZE];

    if (NULL == check) {
        check = get_check_magic_func(vmi);
    }

    for (block_pa = 4096; block_pa < vmi->size; block_pa += BLOCK_SIZE) {
        read = vmi_read_pa(vmi, block_pa, block_buffer, BLOCK_SIZE);
        if (BLOCK_SIZE != read) {
            continue;
        }

        for (offset = 0; offset < BLOCK_SIZE; offset += 8) {
            memcpy(&value, block_buffer + offset, 4);

            if (check(value)) { // look for specific magic #
                dbprint
                    ("--%s: found magic value 0x%.8"PRIx32" @ offset 0x%.8"PRIx64"\n",
                     __FUNCTION__, value, block_pa + offset);

                unsigned char haystack[0x500];

                read =
                    vmi_read_pa(vmi, block_pa + offset, haystack,
                                0x500);
                if (0x500 != read) {
                    continue;
                }

                int i = boyer_moore2(bm, haystack, 0x500);

                if (-1 == i) {
                    continue;
                }
                else {
                    vmi->init_task =
                        block_pa + offset +
                        vmi->os.windows_instance.tasks_offset;
                    dbprint
                        ("--%s: found Idle process at 0x%.8"PRIx64" + 0x%x\n",
                         __FUNCTION__, block_pa + offset, i);
                    boyer_moore_fini(bm);
                    return i;
                }
            }
        }
    }
    boyer_moore_fini(bm);
    return 0;
}