예제 #1
0
파일: accessors.c 프로젝트: Jack47/libvmi
status_t
vmi_get_vcpureg(
    vmi_instance_t vmi,
    reg_t *value,
    registers_t reg,
    unsigned long vcpu)
{
    return driver_get_vcpureg(vmi, value, reg, vcpu);
}
예제 #2
0
파일: memory.c 프로젝트: Chingliu/libvmi
status_t
windows_kernel_symbol_to_address(
    vmi_instance_t vmi,
    const char *symbol,
    addr_t *kernel_base_address,
    addr_t *address)
{
    /* see if we have a cr3 value */
    reg_t cr3 = 0;
    windows_instance_t windows = vmi->os_data;

    if (vmi->os_data == NULL) {
        return VMI_FAILURE;
    }

    if (vmi->kpgd) {
        cr3 = vmi->kpgd;
    }
    else {
        driver_get_vcpureg(vmi, &cr3, CR3, 0);
    }
    dbprint("--windows symbol lookup (%s)\n", symbol);

    if (kernel_base_address) {
        *kernel_base_address = windows->ntoskrnl_va;
    }

    /* check kpcr if we have a cr3 */
    if ( /*cr3 && */ VMI_SUCCESS ==
        windows_kpcr_lookup(vmi, symbol, address)) {
        dbprint("--got symbol from kpcr (%s --> 0x%"PRIx64").\n", symbol,
                *address);
        return VMI_SUCCESS;
    }
    dbprint("--kpcr lookup failed, trying kernel PE export table\n");

    /* check exports */
    if (VMI_SUCCESS
            == windows_export_to_rva(vmi, windows->ntoskrnl_va, 0, symbol,
                    address)) {
        addr_t rva = *address;

        *address = windows->ntoskrnl_va + rva;
        dbprint("--got symbol from PE export table (%s --> 0x%.16"PRIx64").\n",
             symbol, *address);
        return VMI_SUCCESS;
    }
    dbprint("--kernel PE export table failed, nothing left to try\n");

    return VMI_FAILURE;
}
예제 #3
0
파일: memory.c 프로젝트: LoongWin/libvmi
status_t probe_memory_layout_arm(vmi_instance_t vmi) {
    //Note: this will need to be a more comprehensive check when we start supporting AArch64
    status_t ret = VMI_FAILURE;
    page_mode_t pm = VMI_PM_UNKNOWN;

    reg_t ttbr1;
    if (VMI_SUCCESS == driver_get_vcpureg(vmi, &ttbr1, TTBR1, 0)) {
        pm = VMI_PM_AARCH32;
        ret = VMI_SUCCESS;
    }

    vmi->page_mode = pm;
    return ret;
}
예제 #4
0
파일: accessors.c 프로젝트: WaitXie/libvmi
/* expose virtual to physical mapping for kernel space via api call */
addr_t vmi_translate_kv2p (vmi_instance_t vmi, addr_t virt_address)
{
    reg_t cr3 = 0;

    if (vmi->kpgd) {
        cr3 = vmi->kpgd;
    }
    else {
        driver_get_vcpureg(vmi, &cr3, CR3, 0);
    }
    if (!cr3) {
        dbprint(VMI_DEBUG_PTLOOKUP, "--early bail on v2p lookup because cr3 is zero\n");
        return 0;
    }
    else {
        return vmi_pagetable_lookup(vmi, cr3, virt_address);
    }
}
예제 #5
0
파일: memory.c 프로젝트: LoongWin/libvmi
/*
 * check that this vm uses a paging method that we support
 * and set pm/cr3/pae/pse/lme flags optionally on the given pointers
 */
status_t probe_memory_layout_x86(vmi_instance_t vmi) {
    // To get the paging layout, the following bits are needed:
    // 1. CR0.PG
    // 2. CR4.PAE
    // 3. Either (a) IA32_EFER.LME, or (b) the guest's address width (32 or
    //    64). Not all backends allow us to read an MSR; in particular, Xen's PV
    //    backend doessn't.

    status_t ret = VMI_FAILURE;
    page_mode_t pm = VMI_PM_UNKNOWN;
    uint8_t dom_addr_width = 0; // domain address width (bytes)

    /* pull info from registers, if we can */
    reg_t cr0, cr3, cr4, efer;
    int pae = 0, pse = 0, lme = 0;
    uint8_t msr_efer_lme = 0;   // LME bit in MSR_EFER

    /* get the control register values */
    if (driver_get_vcpureg(vmi, &cr0, CR0, 0) == VMI_FAILURE) {
        errprint("**failed to get CR0\n");
        goto _exit;
    }

    /* PG Flag --> CR0, bit 31 == 1 --> paging enabled */
    if (!VMI_GET_BIT(cr0, 31)) {
        dbprint(VMI_DEBUG_CORE, "Paging disabled for this VM, only physical addresses supported.\n");
        vmi->page_mode = VMI_PM_UNKNOWN;
        vmi->pae = 0;
        vmi->pse = 0;
        vmi->lme = 0;

        ret = VMI_SUCCESS;
        goto _exit;
    }

    //
    // Paging enabled (PG==1)
    //
    if (driver_get_vcpureg(vmi, &cr4, CR4, 0) == VMI_FAILURE) {
        errprint("**failed to get CR4\n");
        goto _exit;
    }

    /* PSE Flag --> CR4, bit 5 */
    pae = VMI_GET_BIT(cr4, 5);
    dbprint(VMI_DEBUG_CORE, "**set pae = %d\n", pae);

    /* PSE Flag --> CR4, bit 4 */
    pse = VMI_GET_BIT(cr4, 4);
    dbprint(VMI_DEBUG_CORE, "**set pse = %d\n", pse);

    ret = driver_get_vcpureg(vmi, &efer, MSR_EFER, 0);
    if (VMI_SUCCESS == ret) {
        lme = VMI_GET_BIT(efer, 8);
        dbprint(VMI_DEBUG_CORE, "**set lme = %d\n", lme);
    } else {
        dbprint(VMI_DEBUG_CORE, "**failed to get MSR_EFER, trying method #2\n");

        // does this trick work in all cases?
        ret = driver_get_address_width(vmi, &dom_addr_width);
        if (VMI_FAILURE == ret) {
            errprint
                ("Failed to get domain address width. Giving up.\n");
            goto _exit;
        }
        lme = (8 == dom_addr_width);
        dbprint
            (VMI_DEBUG_CORE, "**found guest address width is %d bytes; assuming IA32_EFER.LME = %d\n",
             dom_addr_width, lme);
    }   // if
    // Get current cr3 for sanity checking
    if (driver_get_vcpureg(vmi, &cr3, CR3, 0) == VMI_FAILURE) {
        errprint("**failed to get CR3\n");
        goto _exit;
    }

    // now determine addressing mode
    if (0 == pae) {
        dbprint(VMI_DEBUG_CORE, "**32-bit paging\n");
        pm = VMI_PM_LEGACY;
        cr3 &= 0xFFFFF000ull;
    }
    // PAE == 1; determine IA-32e or PAE
    else if (lme) {    // PAE == 1, LME == 1
        dbprint(VMI_DEBUG_CORE, "**IA-32e paging\n");
        pm = VMI_PM_IA32E;
        cr3 &= 0xFFFFFFFFFFFFF000ull;
    } else {  // PAE == 1, LME == 0
        dbprint(VMI_DEBUG_CORE, "**PAE paging\n");
        pm = VMI_PM_PAE;
        cr3 &= 0xFFFFFFE0;
    }   // if-else
    dbprint(VMI_DEBUG_CORE, "**sanity checking cr3 = 0x%.16"PRIx64"\n", cr3);

    /* testing to see CR3 value */
    if (!driver_is_pv(vmi) && cr3 >= vmi->max_physical_address) {   // sanity check on CR3
        dbprint(VMI_DEBUG_CORE, "** Note cr3 value [0x%"PRIx64"] exceeds memsize [0x%"PRIx64"]\n",
                cr3, vmi->size);
    }

    vmi->page_mode = pm;
    vmi->pae = pae;
    vmi->pse = pse;
    vmi->lme = lme;

_exit:
    return ret;
}
예제 #6
0
파일: core.c 프로젝트: kittel/libvmi
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 defined(ARM)
    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;

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

    rc = linux_system_map_symbol_to_address(vmi, "init_task", NULL,
            &vmi->init_task);
    if (VMI_FAILURE == rc) {
        errprint("Could not get init_task from System.map\n");
        goto _exit;
    }

done:
    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_system_map_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;
}
예제 #7
0
파일: core.c 프로젝트: Matthewxie/libvmi
status_t linux_init(vmi_instance_t vmi) {
    status_t ret = VMI_FAILURE;
    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);

    addr_t boundary = 0, phys_start = 0, virt_start = 0;

    if(vmi->page_mode == VMI_PM_IA32E) {
        linux_system_map_symbol_to_address(vmi, "phys_startup_64", NULL, &phys_start);
        linux_system_map_symbol_to_address(vmi, "startup_64", NULL, &virt_start);
    } else if (vmi->page_mode == VMI_PM_LEGACY || vmi->page_mode == VMI_PM_PAE) {
        linux_system_map_symbol_to_address(vmi, "phys_startup_32", NULL, &phys_start);
        linux_system_map_symbol_to_address(vmi, "startup_32", NULL, &virt_start);
    } else if (vmi->page_mode == VMI_PM_UNKNOWN) {
        ret = linux_system_map_symbol_to_address(vmi, "phys_startup_64", NULL, &phys_start);
        if(VMI_SUCCESS == ret) {
            linux_system_map_symbol_to_address(vmi, "startup_64", NULL, &virt_start);
            vmi->page_mode = VMI_PM_IA32E;
        } else {
            linux_system_map_symbol_to_address(vmi, "phys_startup_32", NULL, &phys_start);
            linux_system_map_symbol_to_address(vmi, "startup_32", NULL, &virt_start);
            vmi->page_mode = VMI_PM_PAE; // it's just a guess
        }
    }

    if(phys_start && virt_start && phys_start < virt_start) {
        boundary = virt_start - phys_start;
    } else {
        // Just guess the boundary
        boundary = 0xc0000000UL;
    }

    linux_instance->kernel_boundary = boundary;
    dbprint(VMI_DEBUG_MISC, "--got kernel boundary (0x%.16"PRIx64").\n", boundary);

    if(VMI_FAILURE == driver_get_vcpureg(vmi, &vmi->kpgd, CR3, 0)) {

        if (VMI_SUCCESS == linux_system_map_symbol_to_address(vmi, "swapper_pg_dir", NULL, &vmi->kpgd)) {
            dbprint(VMI_DEBUG_MISC, "--got vaddr for swapper_pg_dir (0x%.16"PRIx64").\n",
                    vmi->kpgd);
            //We don't know if VMI_PM_LEGACY or VMI_PM_PAE yet
            //so we do some heuristics below
        } else if (VMI_SUCCESS == linux_system_map_symbol_to_address(vmi, "init_level4_pgt", NULL, &vmi->kpgd)) {
            dbprint(VMI_DEBUG_MISC, "--got vaddr for init_level4_pgt (0x%.16"PRIx64").\n",
                    vmi->kpgd);
            //Set page mode to VMI_PM_IA32E
            vmi->page_mode = VMI_PM_IA32E;
        } else {
            goto _exit;
        }

        vmi->kpgd -= boundary;
    }

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

    // We check if the page mode is known
    // and if no arch interface has been setup yet we do it now
    if(VMI_PM_UNKNOWN == vmi->page_mode) {

        //Try to check 32-bit paging modes
        vmi->page_mode = VMI_PM_LEGACY;
        if(VMI_SUCCESS == arch_init(vmi)) {
            if(phys_start == vmi_pagetable_lookup(vmi, vmi->kpgd, virt_start)) {
                // PM found
                goto done;
            }
        }

        vmi->page_mode = VMI_PM_PAE;
        if(VMI_SUCCESS == arch_init(vmi)) {
            if(phys_start == vmi_pagetable_lookup(vmi, vmi->kpgd, virt_start)) {
                // PM found
                goto done;
            }
        }

        errprint("VMI_ERROR: Page mode is still unknown\n");
        goto _exit;
    }

    if(!vmi->arch_interface) {
        if(VMI_FAILURE == arch_init(vmi)) {
            goto _exit;
        }
    }

done:
    ret = linux_system_map_symbol_to_address(vmi, "init_task", NULL,
            &vmi->init_task);
    if (ret != VMI_SUCCESS) {
        errprint("Could not get init_task from System.map\n");
        goto _exit;
    }

    if(!vmi_pagetable_lookup(vmi, vmi->kpgd, vmi->init_task)) {
        errprint("Failed to translate init_task VA using the kpgd!\n");
        goto _exit;
    }

    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_system_map_symbol_to_address;
    os_interface->os_usym2rva = NULL;
    os_interface->os_rva2sym = NULL;
    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;
}
예제 #8
0
파일: core.c 프로젝트: dalevy/libvmi
status_t
windows_init(
    vmi_instance_t vmi)
{
    status_t status = VMI_FAILURE;
    windows_instance_t windows = NULL;
    os_interface_t os_interface = NULL;
    status_t real_kpgd_found = VMI_FAILURE;

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

    if (vmi->os_data != NULL) {
        errprint("VMI_ERROR: os data already initialized, resetting\n");
    } else {
        vmi->os_data = safe_malloc(sizeof(struct windows_instance));
    }

    bzero(vmi->os_data, sizeof(struct windows_instance));
    windows = vmi->os_data;
    windows->version = VMI_OS_WINDOWS_UNKNOWN;

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

    /* Need to provide this functions so that find_page_mode will work */
    os_interface = safe_malloc(sizeof(struct os_interface));
    bzero(os_interface, sizeof(struct os_interface));
    os_interface->os_get_offset = windows_get_offset;
    os_interface->os_pid_to_pgd = windows_pid_to_pgd;
    os_interface->os_pgd_to_pid = windows_pgd_to_pid;
    os_interface->os_ksym2v = windows_kernel_symbol_to_address;
    os_interface->os_usym2rva = windows_export_to_rva;
    os_interface->os_v2sym = windows_rva_to_export;
    os_interface->os_read_unicode_struct = windows_read_unicode_struct;
    os_interface->os_teardown = windows_teardown;

    vmi->os_interface = os_interface;

    if(VMI_FAILURE == check_pdbase_offset(vmi)) {
        goto error_exit;
    }

    /* At this point we still don't have a directory table base,
     * so first we try to get it via the driver (fastest way).
     * If the driver gets us a dtb, it will be used _only_ during the init phase,
     * and will be replaced by the real kpgd later. */
    if(VMI_FAILURE == driver_get_vcpureg(vmi, &vmi->kpgd, CR3, 0)) {
        if(VMI_FAILURE == get_kpgd_method2(vmi)) {
            errprint("Could not get kpgd, will not be able to determine page mode\n");
            goto error_exit;
        } else {
            real_kpgd_found = VMI_SUCCESS;
        }
    }

    if(VMI_FAILURE == init_core(vmi)) {
        goto error_exit;
    }

    if (VMI_PM_UNKNOWN == vmi->page_mode) {
        if (VMI_FAILURE == find_page_mode(vmi)) {
            errprint("Failed to find correct page mode.\n");
            goto error_exit;
        }
    }

    if (VMI_SUCCESS == real_kpgd_found) {
        status = VMI_SUCCESS;
        goto done;
    }

    /* If we have a dtb via the driver we need to get the real kpgd */
    if (VMI_SUCCESS == get_kpgd_method0(vmi)) {
        dbprint(VMI_DEBUG_MISC, "--kpgd method0 success\n");
        status = VMI_SUCCESS;
        goto done;
    }
    if (VMI_SUCCESS == get_kpgd_method1(vmi)) {
        dbprint(VMI_DEBUG_MISC, "--kpgd method1 success\n");
        status = VMI_SUCCESS;
        goto done;
    }

    if (VMI_SUCCESS == get_kpgd_method2(vmi)) {
        dbprint(VMI_DEBUG_MISC, "--kpgd method2 success\n");
        status = VMI_SUCCESS;
        goto done;
    }

    vmi->kpgd = 0;
    errprint("Failed to find kernel page directory.\n");
    goto error_exit;

done:
    return status;

error_exit:
    windows_teardown(vmi);
    return VMI_FAILURE;
}
예제 #9
0
파일: core.c 프로젝트: dalevy/libvmi
static status_t
init_from_rekall_profile(vmi_instance_t vmi)
{

    status_t ret = VMI_FAILURE;
    windows_instance_t windows = vmi->os_data;
    dbprint(VMI_DEBUG_MISC, "**Trying to init from Rekall profile\n");

    reg_t kpcr = 0;
    addr_t kpcr_rva = 0;

    // try to find the kernel if we are not connecting to a file and the kernel pa/va were not already specified.
    if(vmi->mode != VMI_FILE && ! ( windows->ntoskrnl && windows->ntoskrnl_va ) ) {

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

        if (VMI_SUCCESS == rekall_profile_symbol_to_rva(windows->rekall_profile, "KiInitialPCR", NULL, &kpcr_rva)) {
            if ( kpcr <= kpcr_rva || vmi->page_mode == VMI_PM_IA32E && kpcr < 0xffff800000000000 ) {
                dbprint(VMI_DEBUG_MISC, "**vCPU0 doesn't seem to have KiInitialPCR mapped, can't init from Rekall profile.\n");
                goto done;
            }

            // If the Rekall profile has KiInitialPCR we have Win 7+
            windows->ntoskrnl_va = kpcr - kpcr_rva;
            windows->ntoskrnl = vmi_translate_kv2p(vmi, windows->ntoskrnl_va);
        } else if(kpcr == 0x00000000ffdff000) {
            // If we are in live mode without KiInitialPCR, the KPCR has to be
            // at this VA (XP/Vista) and the KPCR trick [1] is still valid.
            // [1] http://moyix.blogspot.de/2008/04/finding-kernel-global-variables-in.html
            addr_t kdvb = 0, kdvb_offset = 0, kernbase_offset = 0;
            rekall_profile_symbol_to_rva(windows->rekall_profile, "_KPCR", "KdVersionBlock", &kdvb_offset);
            rekall_profile_symbol_to_rva(windows->rekall_profile, "_DBGKD_GET_VERSION64", "KernBase", &kernbase_offset);
            vmi_read_addr_va(vmi, kpcr+kdvb_offset, 0, &kdvb);
            vmi_read_addr_va(vmi, kdvb+kernbase_offset, 0, &windows->ntoskrnl_va);
            windows->ntoskrnl = vmi_translate_kv2p(vmi, windows->ntoskrnl_va);
        } else {
            goto done;
        }

        dbprint(VMI_DEBUG_MISC, "**KernBase PA=0x%"PRIx64"\n", windows->ntoskrnl);

        /*
         * If the CR3 value points to a pagetable that hasn't been setup yet
         * we need to resort to finding a valid pagetable the old fashioned way.
         */
        if (windows->ntoskrnl_va && !windows->ntoskrnl)
        {
            windows_find_cr3(vmi);
            windows->ntoskrnl = vmi_translate_kv2p(vmi, windows->ntoskrnl_va);
        }
    }

    // This could happen if we are in file mode or for Win XP
    if (!windows->ntoskrnl) {

        windows->ntoskrnl = get_ntoskrnl_base(vmi, vmi->kpgd);

        // get KdVersionBlock/"_DBGKD_GET_VERSION64"->KernBase
        addr_t kdvb = 0, kernbase_offset = 0;
        rekall_profile_symbol_to_rva(windows->rekall_profile, "KdVersionBlock", NULL, &kdvb);
        rekall_profile_symbol_to_rva(windows->rekall_profile, "_DBGKD_GET_VERSION64", "KernBase", &kernbase_offset);

        dbprint(VMI_DEBUG_MISC, "**KdVersionBlock RVA 0x%lx. KernBase RVA: 0x%lx\n", kdvb, kernbase_offset);
        dbprint(VMI_DEBUG_MISC, "**KernBase PA=0x%"PRIx64"\n", windows->ntoskrnl);

        if (windows->ntoskrnl && kdvb && kernbase_offset) {
            vmi_read_addr_pa(vmi, windows->ntoskrnl + kdvb + kernbase_offset, &windows->ntoskrnl_va);

            if(!windows->ntoskrnl_va) {
                vmi_read_32_pa(vmi, windows->ntoskrnl + kdvb + kernbase_offset, (uint32_t*)&windows->ntoskrnl_va);
            }

            if(!windows->ntoskrnl_va) {
                dbprint(VMI_DEBUG_MISC, "**failed to find Windows kernel VA via KdVersionBlock\n");
                goto done;
            }
        } else {
            dbprint(VMI_DEBUG_MISC, "**Failed to find required offsets and/or kernel base PA\n");
            goto done;
        }
    }

    dbprint(VMI_DEBUG_MISC, "**KernBase VA=0x%"PRIx64"\n", windows->ntoskrnl_va);

    addr_t ntbuildnumber_rva;
    uint16_t ntbuildnumber = 0;

    // Let's do some sanity checking
    if (VMI_FAILURE == rekall_profile_symbol_to_rva(windows->rekall_profile, "NtBuildNumber", NULL, &ntbuildnumber_rva)) {
        goto done;
    }
    if (VMI_FAILURE == vmi_read_16_pa(vmi, windows->ntoskrnl + ntbuildnumber_rva, &ntbuildnumber)) {
        goto done;
    }

    if (ntbuild2version(ntbuildnumber) == VMI_OS_WINDOWS_UNKNOWN) {
        dbprint(VMI_DEBUG_MISC, "Unknown Windows NtBuildNumber: %u, the Rekall Profile may be incorrect for this Windows!\n", ntbuildnumber);
    }

    // The system map seems to be good, lets grab all the required offsets
    if(!windows->pdbase_offset) {
        if (VMI_FAILURE == rekall_profile_symbol_to_rva(windows->rekall_profile, "_KPROCESS", "DirectoryTableBase", &windows->pdbase_offset)) {
            goto done;
        }
    }
    if(!windows->tasks_offset) {
        if (VMI_FAILURE == rekall_profile_symbol_to_rva(windows->rekall_profile, "_EPROCESS", "ActiveProcessLinks", &windows->tasks_offset)) {
            goto done;
        }
    }
    if(!windows->pid_offset) {
        if (VMI_FAILURE == rekall_profile_symbol_to_rva(windows->rekall_profile, "_EPROCESS", "UniqueProcessId", &windows->pid_offset)) {
            goto done;
        }
    }
    if(!windows->pname_offset) {
        if (VMI_FAILURE == rekall_profile_symbol_to_rva(windows->rekall_profile, "_EPROCESS", "ImageFileName", &windows->pname_offset)) {
            goto done;
        }
    }

    ret = VMI_SUCCESS;
    dbprint(VMI_DEBUG_MISC, "**init from Rekall profile success\n");

    done: return ret;

}
예제 #10
0
파일: core.c 프로젝트: Zentific/libvmi
static status_t
init_from_sysmap(vmi_instance_t vmi)
{

    status_t ret = VMI_FAILURE;
    windows_instance_t windows = vmi->os_data;
    dbprint(VMI_DEBUG_MISC, "**Trying to init from sysmap\n");

    reg_t kpcr = 0;
    addr_t kpcr_rva = 0;

    if(vmi->mode != VMI_FILE) {

        if (vmi->page_mode == VMI_PM_IA32E) {
            if (VMI_FAILURE == driver_get_vcpureg(vmi, &kpcr, GS_BASE, 0)) {
                goto done;
            }
        } else if (vmi->page_mode == VMI_PM_LEGACY || vmi->page_mode == VMI_PM_PAE) {
            if (VMI_FAILURE == driver_get_vcpureg(vmi, &kpcr, FS_BASE, 0)) {
                goto done;
            }
        }

        if (VMI_SUCCESS == windows_system_map_symbol_to_address(vmi, "KiInitialPCR", NULL, &kpcr_rva)) {
            // If the sysmap has KiInitialPCR we have Win 7+
            windows->ntoskrnl_va = kpcr - kpcr_rva;
            windows->ntoskrnl = vmi_translate_kv2p(vmi, windows->ntoskrnl_va);
        } else if(kpcr == 0x00000000ffdff000) {
            // If we are in live mode without KiInitialPCR, the KPCR has to be
            // at this VA (XP/Vista) and the KPCR trick [1] is still valid.
            // [1] http://moyix.blogspot.de/2008/04/finding-kernel-global-variables-in.html
            addr_t kdvb = 0, kdvb_offset = 0, kernbase_offset = 0;
            windows_system_map_symbol_to_address(vmi, "_KPCR", "KdVersionBlock", &kdvb_offset);
            windows_system_map_symbol_to_address(vmi, "_DBGKD_GET_VERSION64", "KernBase", &kernbase_offset);
            vmi_read_addr_va(vmi, kpcr+kdvb_offset, 0, &kdvb);
            vmi_read_addr_va(vmi, kdvb+kernbase_offset, 0, &windows->ntoskrnl_va);
            windows->ntoskrnl = vmi_translate_kv2p(vmi, windows->ntoskrnl_va);
        } else {
            goto done;
        }

        dbprint(VMI_DEBUG_MISC, "**KernBase PA=0x%"PRIx64"\n", windows->ntoskrnl);

    }

    // This could happen if we are in file mode or for Win XP
    if (!windows->ntoskrnl) {

        windows->ntoskrnl = get_ntoskrnl_base(vmi, vmi->kpgd);

        // get KdVersionBlock/"_DBGKD_GET_VERSION64"->KernBase
        addr_t kdvb = 0, kernbase_offset = 0;
        windows_system_map_symbol_to_address(vmi, "KdVersionBlock", NULL, &kdvb);
        windows_system_map_symbol_to_address(vmi, "_DBGKD_GET_VERSION64", "KernBase", &kernbase_offset);

        dbprint(VMI_DEBUG_MISC, "**KdVersionBlock RVA 0x%lx. KernBase RVA: 0x%lx\n", kdvb, kernbase_offset);
        dbprint(VMI_DEBUG_MISC, "**KernBase PA=0x%"PRIx64"\n", windows->ntoskrnl);

        if (windows->ntoskrnl && kdvb && kernbase_offset) {
            vmi_read_addr_pa(vmi, windows->ntoskrnl + kdvb + kernbase_offset, &windows->ntoskrnl_va);

            if(!windows->ntoskrnl_va) {
                vmi_read_32_pa(vmi, windows->ntoskrnl + kdvb + kernbase_offset, (uint32_t*)&windows->ntoskrnl_va);
            }

            if(!windows->ntoskrnl_va) {
                dbprint(VMI_DEBUG_MISC, "**failed to find Windows kernel VA via KdVersionBlock\n");
                goto done;
            }
        } else {
            dbprint(VMI_DEBUG_MISC, "**Failed to find required offsets and/or kernel base PA\n");
            goto done;
        }
    }

    dbprint(VMI_DEBUG_MISC, "**KernBase VA=0x%"PRIx64"\n", windows->ntoskrnl_va);

    addr_t ntbuildnumber_rva;
    uint16_t ntbuildnumber = 0;

    // Let's do some sanity checking
    if (VMI_FAILURE == windows_system_map_symbol_to_address(vmi, "NtBuildNumber", NULL, &ntbuildnumber_rva)) {
        goto done;
    }
    if (VMI_FAILURE == vmi_read_16_pa(vmi, windows->ntoskrnl + ntbuildnumber_rva, &ntbuildnumber)) {
        goto done;
    }

    if (ntbuild2version(ntbuildnumber) == VMI_OS_WINDOWS_UNKNOWN) {
        dbprint(VMI_DEBUG_MISC, "Unknown Windows NtBuildNumber: %u. The Rekall Profile may be incorrect for this Windows!\n", ntbuildnumber);
        goto done;
    }

    // The system map seems to be good, lets grab all the required offsets
    if(!windows->pdbase_offset) {
        if (VMI_FAILURE == windows_system_map_symbol_to_address(vmi, "_KPROCESS", "DirectoryTableBase", &windows->pdbase_offset)) {
            goto done;
        }
    }
    if(!windows->tasks_offset) {
        if (VMI_FAILURE == windows_system_map_symbol_to_address(vmi, "_EPROCESS", "ActiveProcessLinks", &windows->tasks_offset)) {
            goto done;
        }
    }
    if(!windows->pid_offset) {
        if (VMI_FAILURE == windows_system_map_symbol_to_address(vmi, "_EPROCESS", "UniqueProcessId", &windows->pid_offset)) {
            goto done;
        }
    }
    if(!windows->pname_offset) {
        if (VMI_FAILURE == windows_system_map_symbol_to_address(vmi, "_EPROCESS", "ImageFileName", &windows->pname_offset)) {
            goto done;
        }
    }

    ret = VMI_SUCCESS;
    dbprint(VMI_DEBUG_MISC, "**init from sysmap success\n");

    done: return ret;

}
예제 #11
0
status_t linux_init(vmi_instance_t vmi) {
    status_t ret = VMI_FAILURE;
    os_interface_t os_interface = NULL;

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

    if (vmi->os_data != NULL) {
        errprint("VMI_ERROR: 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));

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

    if (VMI_SUCCESS
            == linux_system_map_symbol_to_address(vmi, "swapper_pg_dir", NULL,
                    &vmi->kpgd)) {
        dbprint("--got vaddr for swapper_pg_dir (0x%.16"PRIx64").\n",
                vmi->kpgd);
        if (driver_is_pv(vmi)) {
            vmi->kpgd = vmi_translate_kv2p(vmi, vmi->kpgd);
            if (vmi_read_addr_pa(vmi, vmi->kpgd, &(vmi->kpgd)) == VMI_FAILURE) {
                errprint(
                        "Failed to get physical addr for kpgd using swapper_pg_dir.\n");
            }
        }
    }

    if (!vmi->kpgd) {
        ret = driver_get_vcpureg(vmi, &vmi->kpgd, CR3, 0);
        if (ret != VMI_SUCCESS) {
            errprint(
                    "Driver does not support cr3 read and kpgd could not be set, exiting\n");
            goto _exit;
        }
    }

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

    ret = linux_system_map_symbol_to_address(vmi, "init_task", NULL,
            &vmi->init_task);
    if (ret != VMI_SUCCESS) {
        errprint("VMI_ERROR: Could not get init_task from System.map\n");
        return ret;
    }

    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_system_map_symbol_to_address;
    os_interface->os_usym2rva = NULL;
    os_interface->os_rva2sym = NULL;
    os_interface->os_teardown = linux_teardown;

    vmi->os_interface = os_interface;

    _exit: return ret;
}
예제 #12
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;
}
예제 #13
0
파일: kdbg.c 프로젝트: bentau/libvmi
status_t
find_kdbg_address_instant(
    vmi_instance_t vmi,
    addr_t *kdbg_pa,
    addr_t *kernel_pa,
    addr_t *kernel_va)
{

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

    status_t ret = VMI_FAILURE;
    windows_instance_t windows = NULL;
    if (vmi->os_data == NULL) {
        goto done;
    }

    windows = vmi->os_data;

    // If the kernel base is unknown this approach requires the
    // location of the KPCR which we get from the GS/FS register,
    // available only on live machines.
    if (VMI_FILE == vmi->mode) {
        goto done;
    }

    // We also need the config settings for the RVAs
    if (!windows->kdbg_offset || !windows->kpcr_offset) {
        goto done;
    }

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

    if (VMI_PM_IA32E == vmi->page_mode) {
        if (VMI_FAILURE == driver_get_vcpureg(vmi, &fsgs, GS_BASE, 0))
            goto done;
    } else {
        if (VMI_FAILURE == driver_get_vcpureg(vmi, &fsgs, FS_BASE, 0))
            goto done;
    }

    addr_t kernelbase_va = fsgs - windows->kpcr_offset;
    addr_t kernelbase_pa = 0;

    if ( VMI_FAILURE == vmi_pagetable_lookup(vmi, cr3, kernelbase_va, &kernelbase_pa) )
        goto done;

    if ( !kernelbase_pa )
        goto done;

    *kernel_pa = kernelbase_pa;
    *kernel_va = kernelbase_va;
    *kdbg_pa = kernelbase_pa + windows->kdbg_offset;

    ret = VMI_SUCCESS;

done:
    return ret;

}
예제 #14
0
파일: kdbg.c 프로젝트: bentau/libvmi
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;
}
예제 #15
0
파일: kdbg.c 프로젝트: bentau/libvmi
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;
}