Пример #1
0
status_t
windows_kpcr_lookup(
    vmi_instance_t vmi,
    char *symbol,
    addr_t *address)
{
    unsigned long offset = 0;

    if (!vmi->os.windows_instance.kdversion_block) {
        if (VMI_FAILURE == init_kdversion_block(vmi)) {
            goto error_exit;
        }
    }

    // Use heuristic to find windows version
    addr_t kdvb_p = vmi_translate_kv2p(vmi, vmi->os.windows_instance.kdversion_block);
    vmi->os.windows_instance.version =
        find_windows_version(vmi, kdvb_p);

    if (VMI_FAILURE == kpcr_symbol_offset(vmi, symbol, &offset)) {
        goto error_exit;
    }
    if (VMI_FAILURE == kpcr_symbol_resolve(vmi, offset, address)) {
        goto error_exit;
    }

    return VMI_SUCCESS;
error_exit:
    return VMI_FAILURE;
}
Пример #2
0
/* finds the address of the page global directory for a given pid */
addr_t
linux_pid_to_pgd(
    vmi_instance_t vmi,
    int pid)
{
    addr_t ts_addr = 0, pgd = 0, ptr = 0;
    int mm_offset = vmi->os.linux_instance.mm_offset;
    int tasks_offset = vmi->os.linux_instance.tasks_offset;
    int pgd_offset = vmi->os.linux_instance.pgd_offset;

    /* first we need a pointer to this pid's task_struct */
    ts_addr = linux_get_taskstruct_addr(vmi, pid);
    if (!ts_addr) {
        errprint("Could not find task struct for pid = %d.\n", pid);
        goto error_exit;
    }

    /* now follow the pointer to the memory descriptor and grab the pgd value */
    vmi_read_addr_va(vmi, ts_addr + mm_offset - tasks_offset, 0, &ptr);
    vmi_read_addr_va(vmi, ptr + pgd_offset, 0, &pgd);

    /* convert pgd into a machine address */
    pgd = vmi_translate_kv2p(vmi, pgd);

error_exit:
    return pgd;
}
Пример #3
0
char *
vmi_read_str_va(
    vmi_instance_t vmi,
    addr_t vaddr,
    vmi_pid_t pid)
{
    unsigned char *memory = NULL;
    char *rtnval = NULL;
    addr_t paddr = 0;
    addr_t pfn = 0;
    addr_t offset = 0;
    int len = 0;
    size_t read_len = 0;
    int read_more = 1;
 
    rtnval = NULL;

    while (read_more) {
        if (pid) {
            paddr = vmi_translate_uv2p(vmi, vaddr + len, pid);
        }
        else {
            paddr = vmi_translate_kv2p(vmi, vaddr + len);
        }

        if (!paddr) {
            return rtnval;
        }

        /* access the memory */
        pfn = paddr >> vmi->page_shift;
        offset = (vmi->page_size - 1) & paddr;
        memory = vmi_read_page(vmi, pfn);
        if (NULL == memory) {
            return rtnval;
        }

        /* Count new non-null characters */
        read_len = 0;
        while (offset + read_len < vmi->page_size) {
            if (memory[offset + read_len] == '\0') {
                read_more = 0;
                break;
            }

            read_len++;
        }

        /* Otherwise, realloc, tack on the '\0' in case of errors and
         * get ready to read the next page.
         */
        rtnval = realloc(rtnval, len + 1 + read_len);
        memcpy(&rtnval[len], &memory[offset], read_len);
        len += read_len;
        rtnval[len] = '\0';
    }

    return rtnval;
}
Пример #4
0
int main(int argc, char **argv) {

	vmi_instance_t vmi;
	addr_t start_address;
	struct timeval ktv_start;
	struct timeval ktv_end;

	char *vm = argv[1];
	int buf_size = atoi(argv[2]);
	int loops = atoi(argv[3]);
	int mode = atoi(argv[4]);
	unsigned char *buf = malloc(buf_size);

	int i = 0;
	long int diff;
	long int *data = malloc(loops * sizeof(long int));

	int j = 0;
	uint32_t value = 0;

	if (mode != 1 && mode != 2) {
		printf("invalid mode\n");
		return 1;
	}

	/* initialize the xen access library */
	vmi_init(&vmi, VMI_AUTO | VMI_INIT_COMPLETE, vm);

	/* find address to work from */
	start_address = vmi_translate_ksym2v(vmi, "PsInitialSystemProcess");
	start_address = vmi_translate_kv2p(vmi, start_address);

	for (i = 0; i < loops; ++i) {
		if (mode == 1) {
			gettimeofday(&ktv_start, 0);
			vmi_read_pa(vmi, start_address, buf, buf_size);
			gettimeofday(&ktv_end, 0);
		} else {
			gettimeofday(&ktv_start, 0);
			for (j = 0; j < buf_size / 4; ++j) {
				vmi_read_32_pa(vmi, start_address + j * 4, &value);
			}
			gettimeofday(&ktv_end, 0);
		}

		print_measurement(ktv_start, ktv_end, &diff);
		data[i] = diff;
		memset(buf, 0, buf_size);
		sleep(1);
	}

	avg_measurement(data, loops);

	vmi_destroy(vmi);
	free(buf);
	return 0;
}
Пример #5
0
static status_t
get_kpgd_method0(
    vmi_instance_t vmi)
{
    addr_t sysproc = 0;
    windows_instance_t windows = NULL;

    if (vmi->os_data == NULL) {
        errprint("VMI_ERROR: No OS data initialized\n");
        return VMI_FAILURE;
    }

    windows = vmi->os_data;

    if (VMI_FAILURE == vmi_read_addr_ksym(vmi, "PsActiveProcessHead", &sysproc)) {
        dbprint(VMI_DEBUG_MISC, "--failed to resolve PsActiveProcessHead\n");
        goto error_exit;
    }
    if (VMI_FAILURE == vmi_read_addr_va(vmi, sysproc, 0, &sysproc)) {
        dbprint(VMI_DEBUG_MISC, "--failed to translate PsActiveProcessHead\n");
        goto error_exit;
    }
    sysproc = vmi_translate_kv2p(vmi, sysproc) - windows->tasks_offset;
    dbprint(VMI_DEBUG_MISC, "--got PA to PsActiveProcessHead (0x%.16"PRIx64").\n", sysproc);

    if (VMI_FAILURE ==
        vmi_read_addr_pa(vmi,
                         sysproc +
                         windows->pdbase_offset,
                         &vmi->kpgd)) {
        dbprint(VMI_DEBUG_MISC, "--failed to resolve pointer for system process\n");
        goto error_exit;
    }

    if (!vmi->kpgd) {
        dbprint(VMI_DEBUG_MISC, "--kpgd was zero\n");
        goto error_exit;
    }
    dbprint(VMI_DEBUG_MISC, "**set kpgd (0x%.16"PRIx64").\n", vmi->kpgd);

    if (VMI_FAILURE ==
        vmi_read_addr_pa(vmi,
                     sysproc + windows->tasks_offset,
                     &vmi->init_task)){
        dbprint(VMI_DEBUG_MISC, "--failed to resolve address of System process\n");
        goto error_exit;
    }
    vmi->init_task -= windows->tasks_offset;
    dbprint(VMI_DEBUG_MISC, "**set init_task (0x%.16"PRIx64").\n", vmi->init_task);

    return VMI_SUCCESS;

error_exit:
    return VMI_FAILURE;
}
Пример #6
0
status_t linux_init (vmi_instance_t vmi)
{
    status_t ret = VMI_FAILURE;

    if (vmi->cr3){
        vmi->kpgd = vmi->cr3;
    }
    else if (VMI_SUCCESS == linux_system_map_symbol_to_address(vmi, "swapper_pg_dir", &vmi->kpgd)){
        dbprint("--got vaddr for swapper_pg_dir (0x%.16llx).\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.\n");
                goto _exit;
            }
        }
        else{
            vmi->kpgd = vmi_translate_kv2p(vmi, vmi->kpgd);
        }
    }
    else{
        errprint("swapper_pg_dir not found and CR3 not set, exiting\n");
        goto _exit;
    }

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

    addr_t address = vmi_translate_ksym2v(vmi, "init_task");
    address += vmi->os.linux_instance.tasks_offset;
    if (VMI_FAILURE == vmi_read_addr_va(vmi, address, 0, &(vmi->init_task))){
        errprint("Failed to get task list head 'init_task'.\n");
        goto _exit;
    }

    ret = VMI_SUCCESS;
_exit:
    return ret;
}
Пример #7
0
size_t vmi_write_va (vmi_instance_t vmi, addr_t vaddr, int pid, void *buf, size_t count)
{
    addr_t paddr = 0;
    addr_t pfn = 0;
    addr_t offset = 0;
    size_t buf_offset = 0;

    if (NULL == buf){
        dbprint("--%s: buf passed as NULL, returning without write\n", __FUNCTION__);
        return 0;
    }

    while (count > 0){
        size_t write_len = 0;
        if (pid){
            paddr = vmi_translate_uv2p(vmi, vaddr + buf_offset, pid);
        }
        else{
            paddr = vmi_translate_kv2p(vmi, vaddr + buf_offset);
        }

        if (!paddr){
            return buf_offset;
        }

        /* determine how much we can write to this page */
        offset = (vmi->page_size - 1) & paddr;
        if ((offset + count) > vmi->page_size){
            write_len = vmi->page_size - offset;
        }
        else{
            write_len = count;
        }

        /* do the write */
        if (VMI_FAILURE == driver_write(vmi, paddr, ((char *) buf + (addr_t) buf_offset), write_len)){
            return buf_offset;
        }

        /* set variables for next loop */
        count -= write_len;
        buf_offset += write_len;
    }

    return buf_offset;
}
Пример #8
0
Файл: hvm.c Проект: allewwaly/HI
int main(int argc, char **argv)
{
        vmi_instance_t vmi = NULL;
        status_t status = VMI_SUCCESS;
        if (argc != 2) {
                printf("Usage: %s <vmname>\n", argv[0]);
                return 1;
        }
        char *name=argv[1];
	//vmi_pid_t pid=atoi(argv[3]);
        if (vmi_init(&vmi, VMI_AUTO | VMI_INIT_COMPLETE | VMI_INIT_EVENTS, name) == VMI_FAILURE) {
                printf("Failed to init LibVMI library.\n");
                return 1;
        }
        printf("success to init LibVMI\n");
	int i;
	vmi_pause_vm(vmi);
	for (i = 0; i < num; i++) {
		char *vaddr_str=hypercall_address[i][1];
		char *hypercall_name=hypercall_address[i][0];
	        vaddr[i] =(addr_t) strtoul(vaddr_str, NULL, 16);
		printf("virtual address is:%lx\n",vaddr[i]);
		//printf("pid is: %d\n",pid);
        	paddr[i] = vmi_translate_kv2p(vmi,vaddr[i]);
	        printf("physical address is::%lx\n",paddr[i]);
		mm_event[i].mem_event.gla2 = vaddr[i];//add comparing gla to memory event structure
		mm_event[i].mem_event.hypercall=hypercall_name;
		printf("Preparing memory event to catch HYPERCALL %s at PA 0x%lx, page 0x%lx\n\n",
	            hypercall_name, paddr[i], paddr[i] >> 12);
		SETUP_MEM_EVENT(&mm_event[i], paddr[i], VMI_MEMEVENT_PAGE,
        	            VMI_MEMACCESS_RWX, mm_callback);
		vmi_register_event(vmi,&mm_event[i]);
	}
	vmi_resume_vm(vmi);
	while(!interrupted){
        	status = vmi_events_listen(vmi,500);
	        if (status != VMI_SUCCESS) {
        	    printf("Error waiting for events, quitting...\n");
	            interrupted = -1;
		}
        }
	printf("Finished with test.\n");
        vmi_destroy(vmi);
        return 1;
}
Пример #9
0
END_TEST

/* test vmi_translate_kv2p */
START_TEST (test_libvmi_kv2p)
{
    vmi_instance_t vmi = NULL;
    vmi_init(&vmi, VMI_AUTO | VMI_INIT_COMPLETE, get_testvm());
    addr_t va = 0;
    if (VMI_OS_WINDOWS == vmi_get_ostype(vmi)){
        va = vmi_translate_ksym2v(vmi, "PsInitialSystemProcess");
    }
    else if (VMI_OS_LINUX == vmi_get_ostype(vmi)){
        va = vmi_translate_ksym2v(vmi, "init_task");
    }
    else{
        fail_unless(0, "vmi set to invalid os type");
    }
    addr_t pa = vmi_translate_kv2p(vmi, va);
    fail_unless(pa != 0, "kv2p translation failed");
    vmi_destroy(vmi);
}
Пример #10
0
int main(int argc, char **argv)
{
        vmi_instance_t vmi = NULL;
        status_t status = VMI_SUCCESS;
        if (argc != 3) {
                printf("Usage: %s <vmname> <hypercall-name>\n", argv[0]);
                return 1;
        }
        char *name=argv[1];
	//vmi_pid_t pid=atoi(argv[3]);
        if (vmi_init(&vmi, VMI_AUTO | VMI_INIT_COMPLETE | VMI_INIT_EVENTS, name) == VMI_FAILURE) {
                printf("Failed to init LibVMI library.\n");
                return 1;
        }
        printf("success to init LibVMI\n");
	int i;
	char *hypercall_name=argv[2];
	for (i = 0; i < num; i++) {
		if (strcmp(hypercall_address[i][0],hypercall_name)==0) {
			vmi_pause_vm(vmi);
			char *vaddr_str=hypercall_address[i][1];
		        vaddr[i] =(addr_t) strtoul(vaddr_str, NULL, 16);
			printf("virtual address is:%lx\n",vaddr);
			paddr[i] = vmi_translate_kv2p(vmi,vaddr[i]);
	        	printf("physical address is::%lx\n",paddr[i]);
			mm_event[i].mem_event.gla2 = vaddr[i];//add comparing gla to memory event structure
			mm_event[i].mem_event.hypercall=hypercall_name;
			printf("Preparing memory event to catch HYPERCALL %s at PA 0x%lx, page 0x%lx\n\n",
	        	    hypercall_name, paddr, paddr[i] >> 12);
			SETUP_MEM_EVENT(&mm_event[i], paddr[i], VMI_MEMEVENT_PAGE,
        		            VMI_MEMACCESS_RWX, mm_callback);
			vmi_register_event(vmi,&mm_event[i]);
			vmi_resume_vm(vmi);
			break;
		}
		if (i>=(num-1)){
			printf("no hypercall found, please check the hypercall name!");
			break;
		}
	}
Пример #11
0
/* finds the address of the page global directory for a given pid */
addr_t
linux_pid_to_pgd(
    vmi_instance_t vmi,
    vmi_pid_t pid)
{
    addr_t ts_addr = 0, pgd = 0, ptr = 0;
    uint8_t width = 0;
    status_t rc = VMI_FAILURE;
    linux_instance_t linux_instance = NULL;
    int mm_offset = 0;
    int pgd_offset = 0;

    if (vmi->os_data == NULL) {
        errprint("VMI_ERROR: No os_data initialized\n");
        return 0;
    }

    linux_instance = vmi->os_data;

    mm_offset = linux_instance->mm_offset;
    pgd_offset = linux_instance->pgd_offset;

    /* first we the address of this PID's task_struct */
    ts_addr = linux_get_taskstruct_addr_from_pid(vmi, pid);
    if (!ts_addr) {
        errprint("Could not find task struct for pid = %d.\n", pid);
        goto error_exit;
    }

    /* now follow the pointer to the memory descriptor and grab the pgd value */
    vmi_read_addr_va(vmi, ts_addr + mm_offset, 0, &ptr);

    /* task_struct->mm is NULL when Linux is executing on the behalf
     * of a task, or if the task represents a kthread. In this context,
     * task_struct->active_mm is non-NULL and we can use it as
     * a fallback. task_struct->active_mm can be found very reliably
     * at task_struct->mm + 1 pointer width
     */
    if(!ptr)
    {
        switch(vmi->page_mode)
        {
            case VMI_PM_AARCH64:// intentional fall-through
            case VMI_PM_IA32E:
                width = 8;
                break;
            case VMI_PM_AARCH32:// intentional fall-through
            case VMI_PM_LEGACY: // intentional fall-through
            case VMI_PM_PAE:
                width = 4;
                break;
            default:
                goto error_exit;
        };

        rc = vmi_read_addr_va(vmi, ts_addr + mm_offset + width, 0, &ptr);

        if( rc == VMI_FAILURE || !ptr )
        {
            goto error_exit;
        }
    }

    vmi_read_addr_va(vmi, ptr + pgd_offset, 0, &pgd);

    /* convert pgd into a machine address */
    pgd = vmi_translate_kv2p(vmi, pgd);

error_exit:
    return pgd;
}
Пример #12
0
int main (int argc, char **argv)
{
    vmi_instance_t vmi = NULL;
    status_t status = VMI_SUCCESS;

    struct sigaction act;

    mm_enabled=0;

    char *name = NULL;

    if(argc < 2){
        fprintf(stderr, "Usage: %s <name of VM>\n", argv[0]);
        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");
    }

    vmi_pause_vm(vmi);

    SETUP_REG_EVENT(&cr3_event, CR3, VMI_REGACCESS_W, 0, cr3_callback);
    vmi_register_event(vmi, &cr3_event);

    // Setup a mem event for tracking memory at the current instruction's page
    // But don't install it; that will be done by the cr3 handler.

    vmi_get_vcpureg(vmi, &rip, RIP, 0);
    vmi_get_vcpureg(vmi, &cr3, CR3, 0);

    printf("Current value of RIP is 0x%lx\n", rip);
    rip -= 0x1;

    pid = vmi_dtb_to_pid(vmi, cr3);
    if(pid==4) {
        rip_pa = vmi_translate_uv2p(vmi, rip, pid);
    } else {
        rip_pa = vmi_translate_kv2p(vmi, rip);
    }

    printf("Preparing memory event to catch next RIP 0x%lx, PA 0x%lx, page 0x%lx for PID %u\n",
            rip, rip_pa, rip_pa >> 12, pid);
    SETUP_MEM_EVENT(&mm_event, rip_pa, VMI_MEMEVENT_PAGE, VMI_MEMACCESS_X, mm_callback);

    vmi_resume_vm(vmi);

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

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

    return 0;
}
Пример #13
0
size_t
vmi_read_va(
    vmi_instance_t vmi,
    addr_t vaddr,
    vmi_pid_t pid,
    void *buf,
    size_t count)
{
    unsigned char *memory = NULL;
    addr_t paddr = 0;
    addr_t pfn = 0;
    addr_t offset = 0;
    size_t buf_offset = 0;

    if (NULL == buf) {
        dbprint("--%s: buf passed as NULL, returning without read\n",
                __FUNCTION__);
        return 0;
    }

    while (count > 0) {
        size_t read_len = 0;

        if (pid) {
            paddr = vmi_translate_uv2p(vmi, vaddr + buf_offset, pid);
        }
        else {
            paddr = vmi_translate_kv2p(vmi, vaddr + buf_offset);
        }

        if (!paddr) {
            return buf_offset;
        }

        /* access the memory */
        pfn = paddr >> vmi->page_shift;
        offset = (vmi->page_size - 1) & paddr;
        memory = vmi_read_page(vmi, pfn);
        if (NULL == memory) {
            return buf_offset;
        }

        /* determine how much we can read */
        if ((offset + count) > vmi->page_size) {
            read_len = vmi->page_size - offset;
        }
        else {
            read_len = count;
        }

        /* do the read */
        memcpy(((char *) buf) + (addr_t) buf_offset,
               memory + (addr_t) offset, read_len);

        /* set variables for next loop */
        count -= read_len;
        buf_offset += read_len;
    }

    return buf_offset;
}
Пример #14
0
int main (int argc, char **argv)
{
    vmi_instance_t vmi = NULL;
    status_t status = VMI_SUCCESS;

    struct sigaction act;

    reg_t lstar = 0;
    addr_t phys_lstar = 0;
    reg_t cstar = 0;
    addr_t phys_cstar = 0;
    reg_t sysenter_ip = 0;
    addr_t phys_sysenter_ip = 0;

    addr_t ia32_sysenter_target = 0;
    addr_t phys_ia32_sysenter_target = 0;
    addr_t vsyscall = 0;
    addr_t phys_vsyscall = 0;

    char *name = NULL;
    vmi_pid_t pid = -1;

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

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

    // Arg 2 is the pid of the process to track.
    if(argc == 3)
        pid = (int) strtoul(argv[2], NULL, 0);

    /* 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");
    }

    // Get the cr3 for this process.
    if(pid != -1) {
        cr3 = vmi_pid_to_dtb(vmi, pid);
        printf("CR3 for process (%d) == %llx\n", pid, (unsigned long long)cr3);
    }

    // Get the value of lstar and cstar for the system.
    // NOTE: all vCPUs have the same value for these registers
    vmi_get_vcpureg(vmi, &lstar, MSR_LSTAR, 0);
    vmi_get_vcpureg(vmi, &cstar, MSR_CSTAR, 0);
    vmi_get_vcpureg(vmi, &sysenter_ip, SYSENTER_EIP, 0);
    printf("vcpu 0 MSR_LSTAR == %llx\n", (unsigned long long)lstar);
    printf("vcpu 0 MSR_CSTAR == %llx\n", (unsigned long long)cstar);
    printf("vcpu 0 MSR_SYSENTER_IP == %llx\n", (unsigned long long)sysenter_ip);

    ia32_sysenter_target = vmi_translate_ksym2v(vmi, "ia32_sysenter_target");
    printf("ksym ia32_sysenter_target == %llx\n", (unsigned long long)ia32_sysenter_target);

    /* Per Linux ABI, this VA represents the start of the vsyscall page 
     *  If vsyscall support is enabled (deprecated or disabled on many newer 
     *  3.0+ kernels), it is accessible at this address in every process.
     */ 
    vsyscall = 0xffffffffff600000;

    // Translate to a physical address.
    phys_lstar= vmi_translate_kv2p(vmi, lstar);
    printf("Physical LSTAR == %llx\n", (unsigned long long)phys_lstar);

    phys_cstar= vmi_translate_kv2p(vmi, cstar);
    printf("Physical CSTAR == %llx\n", (unsigned long long)phys_cstar);

    phys_sysenter_ip= vmi_translate_kv2p(vmi, sysenter_ip);
    printf("Physical SYSENTER_IP == %llx\n", (unsigned long long)phys_sysenter_ip);

    phys_ia32_sysenter_target = vmi_translate_kv2p(vmi,ia32_sysenter_target);
    printf("Physical ia32_sysenter_target == %llx\n", (unsigned long long)ia32_sysenter_target);
    phys_vsyscall = vmi_translate_kv2p(vmi,vsyscall);
    printf("Physical phys_vsyscall == %llx\n", (unsigned long long)phys_vsyscall);


    // Get only the page that the handler starts.
    printf("LSTAR Physical PFN == %llx\n", (unsigned long long)(phys_lstar >> 12));
    printf("CSTAR Physical PFN == %llx\n", (unsigned long long)(phys_cstar >> 12));
    printf("SYSENTER_IP Physical PFN == %llx\n", (unsigned long long)(phys_sysenter_ip >> 12));
    printf("phys_vsyscall Physical PFN == %llx\n", (unsigned long long)(phys_vsyscall >> 12));
    printf("phys_ia32_sysenter_target Physical PFN == %llx\n", (unsigned long long)(phys_ia32_sysenter_target >> 12));

    /* 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)
     */
    memset(&cr3_event, 0, sizeof(vmi_event_t));
    cr3_event.type = VMI_EVENT_REGISTER;
    cr3_event.reg_event.reg = CR3;

    /* Observe only write events to the given register. 
     *   NOTE: read events are unsupported at this time.
     */
    cr3_event.reg_event.in_access = VMI_REGACCESS_W;

    /* Optional (default = 0): Trigger on change 
     *  Causes events to be delivered by the hypervisor to this monitoring
     *   program if and only if the register value differs from that previously 
     *   observed.
     *  Usage: cr3_event.reg_event.onchange = 1;
     *
     * Optional (default = 0): Asynchronous event delivery
     *  Causes events to be delivered by the hypervisor to this monitoring
     *   program if and only if the register value differs from that previously
     *   observed.
     *  Usage: cr3_event.reg_event.async =1;
     */

    if(pid == -1){
        cr3_event.callback = cr3_all_tasks_callback;
        vmi_register_event(vmi, &cr3_event);
    } else {
        cr3_event.callback = cr3_one_task_callback;
        /* This acts as a filter: if the CR3 value at time of event == the CR3
         *  we wish to inspect, then the callback will be invoked. Otherwise,
         *  no action is taken.
         */
        cr3_event.reg_event.equal = cr3;
        vmi_register_event(vmi, &cr3_event);
    }

    // Setup a default event for tracking memory at the syscall handler.
    // But don't install it; that will be done by the cr3 handler.
    memset(&msr_syscall_sysenter_event, 0, sizeof(vmi_event_t));
    msr_syscall_sysenter_event.type = VMI_EVENT_MEMORY;
    msr_syscall_sysenter_event.mem_event.physical_address = phys_sysenter_ip;
    msr_syscall_sysenter_event.mem_event.npages = 1;
    msr_syscall_sysenter_event.mem_event.granularity=VMI_MEMEVENT_PAGE;

    memset(&kernel_sysenter_target_event, 0, sizeof(vmi_event_t));
    kernel_sysenter_target_event.type = VMI_EVENT_MEMORY;
    kernel_sysenter_target_event.mem_event.physical_address = phys_ia32_sysenter_target;
    kernel_sysenter_target_event.mem_event.npages = 1;
    kernel_sysenter_target_event.mem_event.granularity=VMI_MEMEVENT_PAGE;

    memset(&kernel_vsyscall_event, 0, sizeof(vmi_event_t));
    kernel_vsyscall_event.type = VMI_EVENT_MEMORY;
    kernel_vsyscall_event.mem_event.physical_address = phys_vsyscall;
    kernel_vsyscall_event.mem_event.npages = 1;
    kernel_vsyscall_event.mem_event.granularity=VMI_MEMEVENT_PAGE;

    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");

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

    return 0;
}
Пример #15
0
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;

}
Пример #16
0
static status_t
get_kpgd_method0(
    vmi_instance_t vmi)
{
    addr_t sysproc_va = 0;
    addr_t sysproc_pa = 0;
    addr_t active_process_head = 0;
    windows_instance_t windows = NULL;
    vmi_pid_t pid = 4;
    size_t len = sizeof(vmi_pid_t);
    addr_t kpgd = 0;

    if (vmi->os_data == NULL) {
        errprint("VMI_ERROR: No OS data initialized\n");
        return VMI_FAILURE;
    }

    windows = vmi->os_data;

    if (VMI_FAILURE == vmi_read_addr_ksym(vmi, "PsActiveProcessHead", &active_process_head)) {
        dbprint(VMI_DEBUG_MISC, "--failed to resolve PsActiveProcessHead\n");
        goto error_exit;
    }

    dbprint(VMI_DEBUG_MISC, "--starting search from PsActiveProcessHead (0x%.16"PRIx64") using kpgd (0x%.16"PRIx64").\n",
            active_process_head, vmi->kpgd);

    sysproc_va = eprocess_list_search(vmi, active_process_head - windows->tasks_offset, windows->pid_offset, len, &pid);

    if (sysproc_va == 0) {
        dbprint(VMI_DEBUG_MISC, "--failed to find system process with pid 4\n");
        goto error_exit;
    }

    sysproc_va -= windows->tasks_offset;
    dbprint(VMI_DEBUG_MISC, "--Found System process at %lx\n", sysproc_va);
    sysproc_pa = vmi_translate_kv2p(vmi, sysproc_va);

    if (sysproc_pa == 0) {
        dbprint(VMI_DEBUG_MISC, "--failed to translate System process\n");
        goto error_exit;
    }

    dbprint(VMI_DEBUG_MISC, "--Found System process physical address at %lx\n", sysproc_pa);

    if (VMI_FAILURE ==
        vmi_read_addr_pa(vmi,
                         sysproc_pa +
                         windows->pdbase_offset,
                         &kpgd)) {
        dbprint(VMI_DEBUG_MISC, "--failed to resolve pointer for system process\n");
        goto error_exit;
    }

    if (!kpgd) {
        dbprint(VMI_DEBUG_MISC, "--kpgd was zero\n");
        goto error_exit;
    }
    vmi->kpgd = kpgd;
    dbprint(VMI_DEBUG_MISC, "**set kpgd (0x%.16"PRIx64").\n", vmi->kpgd);

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

    return VMI_SUCCESS;

error_exit:
    return VMI_FAILURE;
}
Пример #17
0
int main (int argc, char **argv)
{
    vmi_instance_t vmi = NULL;
    status_t status = VMI_SUCCESS;

    struct sigaction act;

    reg_t lstar = 0;
    addr_t phys_lstar = 0;
    reg_t cstar = 0;
    addr_t phys_cstar = 0;
    reg_t sysenter_ip = 0;
    addr_t phys_sysenter_ip = 0;

    addr_t ia32_sysenter_target = 0;
    addr_t phys_ia32_sysenter_target = 0;
    addr_t vsyscall = 0;
    addr_t phys_vsyscall = 0;

    char *name = NULL;
    vmi_pid_t pid = -1;

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

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

    // Arg 2 is the pid of the process to track.
    if(argc == 3)
        pid = (int) strtoul(argv[2], NULL, 0);

    /* 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");
    }

    // Get the cr3 for this process.
    /*
addr_t vmi_pid_to_dtb (vmi_instance_t vmi, vmi_pid_t pid)
Given a pid, this function returns the virtual address of the directory table base for this process' address space. 
This value is effectively what would be in the CR3 register while this process is running.

Parameters

[in] vmi LibVMI instance
[in] pid Desired process id to lookup
Returns

OrderedDict([(u'emphasis', u'pid'), ('#text', u'The directory table base virtual address for')])
    */
    if(pid != -1) {
        cr3 = vmi_pid_to_dtb(vmi, pid);  //虚拟机句柄和进程id  进程基地址
        printf("CR3 for process (%d) == %llx\n", pid, (unsigned long long)cr3);
    }

    // Get the value of lstar and cstar for the system.
    // NOTE: all vCPUs have the same value for these registers
    //status_t vmi_get_vcpureg (vmi_instance_t vmi, reg_t *value, registers_t reg, unsigned long vcpu)
  
  //获取特定寄存器值
    vmi_get_vcpureg(vmi, &lstar, MSR_LSTAR, 0); 
    vmi_get_vcpureg(vmi, &cstar, MSR_CSTAR, 0);
    vmi_get_vcpureg(vmi, &sysenter_ip, SYSENTER_EIP, 0);
  
  //在调用SYSENTER指令前,软件必须通过下面的MSR寄存器,指定0层的代码段和代码指针,0层的堆栈段和堆栈指针:
    printf("vcpu 0 MSR_LSTAR == %llx\n", (unsigned long long)lstar);
    printf("vcpu 0 MSR_CSTAR == %llx\n", (unsigned long long)cstar);
    printf("vcpu 0 MSR_SYSENTER_IP == %llx\n", (unsigned long long)sysenter_ip);

/*
addr_t vmi_translate_ksym2v (vmi_instance_t vmi, const char *symbol)
Performs the translation from a kernel symbol to a virtual address.

Parameters

[in] vmi LibVMI instance
[in] symbol Desired kernel symbol to translate
Returns

Virtual address, or zero on error
*/
    ia32_sysenter_target = vmi_translate_ksym2v(vmi, "ia32_sysenter_target");
    printf("ksym ia32_sysenter_target == %llx\n", (unsigned long long)ia32_sysenter_target);
//??? 返回结果为0 岂不是发生了error


    /* Per Linux ABI, this VA represents the start of the vsyscall page 
     *  If vsyscall support is enabled (deprecated or disabled on many newer 
     *  3.0+ kernels), it is accessible at this address in every process.
     */ 
    vsyscall = 0xffffffffff600000;

    // Translate to a physical address.
    phys_lstar= vmi_translate_kv2p(vmi, lstar);
    printf("Physical LSTAR == %llx0\n", (unsigned long long)phys_lstar);

    phys_cstar= vmi_translate_kv2p(vmi, cstar);
    printf("Physical CSTAR == %llx\n", (unsigned long long)phys_cstar);

    phys_sysenter_ip= vmi_translate_kv2p(vmi, sysenter_ip);
    printf("Physical SYSENTER_IP == %llx\n", (unsigned long long)phys_sysenter_ip);

    phys_ia32_sysenter_target = vmi_translate_kv2p(vmi,ia32_sysenter_target);
    printf("Physical ia32_sysenter_target == %llx\n", (unsigned long long)ia32_sysenter_target);
    /*
http://www.longene.org/forum/viewtopic.php?f=5&t=8851
在x86结构中,较新的CPU都提供了sysenter/sysexit指令,专门用于系统调用的进入和退出,由于去掉了一些不必要的检查,它的速度比以前的int指令要快。
因此在新的Linux系统中,大部分系统调用都采用了sysenter代替原来的int 80。除了一些比较慢的系统调用,如clone、execve等少数几个,因为对于这种系统调用,
进入/退出内核空间所费的时钟周期,相对于其处理时间,几乎可以忽略不计。
考虑到和glibc的对接问题,现在glibc中不直接调用int 80或者sysenter。而是采用vdso方式,在内核中生成一个页面,用于系统调用,
叫做vsyscall,在load_elf_binary时,会将其映射到用户空间,glibc直接调用其中的函数。

关于sysenter的一些资料,可以看这里http://www.cnblogs.com/yangnas/archive/2010/04/28/1723232.html
    */
    phys_vsyscall = vmi_translate_kv2p(vmi,vsyscall);
    printf("Physical phys_vsyscall == %llx\n", (unsigned long long)phys_vsyscall);


    // Get only the page that the handler starts.
    printf("LSTAR Physical PFN == %llx\n", (unsigned long long)(phys_lstar >> 12));
    printf("CSTAR Physical PFN == %llx\n", (unsigned long long)(phys_cstar >> 12));
    printf("SYSENTER_IP Physical PFN == %llx\n", (unsigned long long)(phys_sysenter_ip >> 12));
    printf("phys_vsyscall Physical PFN == %llx\n", (unsigned long long)(phys_vsyscall >> 12));
    printf("phys_ia32_sysenter_target Physical PFN == %llx\n", (unsigned long long)(phys_ia32_sysenter_target >> 12));

    /* 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)
     */
    memset(&cr3_event, 0, sizeof(vmi_event_t));
    cr3_event.type = VMI_EVENT_REGISTER;
    cr3_event.reg_event.reg = CR3;

    /* Observe only write events to the given register. 
     *   NOTE: read events are unsupported at this time.
     */
    cr3_event.reg_event.in_access = VMI_REGACCESS_W;

    /* Optional (default = 0): Trigger on change 
     *  Causes events to be delivered by the hypervisor to this monitoring
     *   program if and only if the register value differs from that previously 
     *   observed.
     *  Usage: cr3_event.reg_event.onchange = 1;
     *
     * Optional (default = 0): Asynchronous event delivery
     *  Causes events to be delivered by the hypervisor to this monitoring
     *   program if and only if the register value differs from that previously
     *   observed.
     *  Usage: cr3_event.reg_event.async =1;
     */


//重要 注册事件 回调函数
    if(pid == -1){  //如果没加参数  就为-1
        cr3_event.callback = cr3_all_tasks_callback;
        vmi_register_event(vmi, &cr3_event);
    }
    else {
        cr3_event.callback = cr3_one_task_callback;
        /* This acts as a filter: if the CR3 value at time of event == the CR3
         *  we wish to inspect, then the callback will be invoked. Otherwise,
         *  no action is taken.
         */
         //只有当事件发生时,cr3的值等于我们一开始注册的进程的cr3值,才会调用回调函数
        cr3_event.reg_event.equal = cr3;            //保存原始的cr3的值
        vmi_register_event(vmi, &cr3_event);
    }


//设置内存事件,在cr3的事件处理函数中进行绑定
    // Setup a default event for tracking memory at the syscall handler.
    // But don't install it; that will be done by the cr3 handler.
    memset(&msr_syscall_sysenter_event, 0, sizeof(vmi_event_t));
    msr_syscall_sysenter_event.type = VMI_EVENT_MEMORY; 
    msr_syscall_sysenter_event.mem_event.physical_address = phys_sysenter_ip;
    msr_syscall_sysenter_event.mem_event.npages = 1;
    msr_syscall_sysenter_event.mem_event.granularity=VMI_MEMEVENT_PAGE;

    memset(&kernel_sysenter_target_event, 0, sizeof(vmi_event_t));
    kernel_sysenter_target_event.type = VMI_EVENT_MEMORY;
    kernel_sysenter_target_event.mem_event.physical_address = phys_ia32_sysenter_target;
    kernel_sysenter_target_event.mem_event.npages = 1;
    kernel_sysenter_target_event.mem_event.granularity=VMI_MEMEVENT_PAGE;

    memset(&kernel_vsyscall_event, 0, sizeof(vmi_event_t));
    kernel_vsyscall_event.type = VMI_EVENT_MEMORY;
    kernel_vsyscall_event.mem_event.physical_address = phys_vsyscall;
    kernel_vsyscall_event.mem_event.npages = 1;
    kernel_vsyscall_event.mem_event.granularity=VMI_MEMEVENT_PAGE;

    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");

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

    return 0;
}
Пример #18
0
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;

}
Пример #19
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;
}
Пример #20
0
static addr_t
linux_get_taskstruct_addr_from_pgd(
    vmi_instance_t vmi,
    addr_t pgd)
{
    addr_t list_head = 0, next_process = 0;
    addr_t task_pgd = 0;
    uint8_t width = 0;
    int tasks_offset = 0;
    int mm_offset = 0;
    int pgd_offset = 0;
    linux_instance_t os = NULL;

    if (vmi->os_data == NULL) {
        errprint("VMI_ERROR: No os_data initialized\n");
        return 0;
    }

    os = vmi->os_data;

    tasks_offset = os->tasks_offset;
    mm_offset = os->mm_offset;
    pgd_offset = os->pgd_offset;

    /* First we need a pointer to the initial entry in the tasks list.
     * Note that this is task_struct->tasks, not the base addr
     *  of task_struct: task_struct base = $entry - tasks_offset.
     */
    next_process = vmi->init_task;
    list_head = next_process;

    /* May fail for some drivers, but handle gracefully below by
     * testing width
     */
    if ( VMI_FAILURE == driver_get_address_width(vmi, &width) )
        return 0;

    do {
        addr_t ptr = 0;
        vmi_read_addr_va(vmi, next_process + mm_offset, 0, &ptr);

        /* task_struct->mm is NULL when Linux is executing on the behalf
         * of a task, or if the task represents a kthread. In this context,
         * task_struct->active_mm is non-NULL and we can use it as
         * a fallback. task_struct->active_mm can be found very reliably
         * at task_struct->mm + 1 pointer width
         */
        if(!ptr && width)
            vmi_read_addr_va(vmi, next_process + mm_offset + width, 0, &ptr);
        vmi_read_addr_va(vmi, ptr + pgd_offset, 0, &task_pgd);

        task_pgd = vmi_translate_kv2p(vmi, task_pgd);
        if (task_pgd == pgd) {
            return next_process;
        }

        vmi_read_addr_va(vmi, next_process + tasks_offset, 0, &next_process);
        next_process -= tasks_offset;

        /* if we are back at the list head, we are done */
    } while (list_head != next_process);

    return 0;
}
Пример #21
0
/*
 * This functions is responsible for setting up
 * Windows specific variables:
 *  - ntoskrnl (*)
 *  - ntoskrnl_va (*)
 *  - kdbg_offset (*)
 *  - kdbg_va (*)
 * The variables marked with (*) can be also specified
 * in the libvmi config.
 */
status_t
init_from_kdbg(
    vmi_instance_t vmi)
{
    status_t ret = VMI_FAILURE;
    addr_t kernbase_pa = 0;
    addr_t kernbase_va = 0;
    addr_t kdbg_pa = 0;

    if (vmi->os_data == NULL) {
        goto exit;
    }

    windows_instance_t windows = vmi->os_data;

    /* If all 3 values are specified in the config, we can calculate ntoskrnl_va,
     * but can't verify if there is no arch for doing translations.
     */
    if (windows->kdbg_va && windows->kdbg_offset && windows->ntoskrnl
            && !vmi->arch_interface) {
        /* All values were user specified, so set them, but we can't use
         * translations to verify them */
        windows->ntoskrnl_va = windows->kdbg_va - windows->kdbg_offset;
        goto done;
    }

    if (!vmi->arch_interface) {
        /* nothing that requires a virtual-to-physical translation will work
         * so skip straight to the physical only methods. */
        goto find_kdbg;
    }

    /* Otherwise, look up what we need and check for consistency */

    if (windows->kdbg_va) {
        dbprint(VMI_DEBUG_MISC, "**using KdDebuggerDataBlock address=0x%"PRIx64" from config\n",
                windows->kdbg_va);

        if (VMI_SUCCESS != windows_kdbg_lookup(vmi, "KernBase", &windows->ntoskrnl_va)) {
            dbprint(VMI_DEBUG_MISC, "**Error reading KernBase value, falling back to search methods\n");
            goto find_kdbg;
        }

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

        if (windows->kdbg_offset) {
            /* only needed ntoskrnl_va, verify the other values */
            if (windows->kdbg_va != (windows->ntoskrnl_va + windows->kdbg_offset)) {
                errprint("Invalid configuration values for win_kdvb and win_kdbg\n");
                goto exit;
            }

        } else {
            windows->kdbg_offset = windows->kdbg_va - windows->ntoskrnl_va;
        }
    } else if (windows->ntoskrnl && windows->kdbg_offset) {
        /* Calculate ntoskrnl_va and kdbg_va */
        unsigned long offset = 0;
        kdbg_symbol_offset("KernBase", &offset);
        if (VMI_FAILURE == vmi_read_addr_pa(vmi, windows->ntoskrnl + windows->kdbg_offset + offset, &windows->ntoskrnl_va)) {
            errprint("Inconsistent addresses passed in the config!\n");
            goto exit;
        }

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

        windows->kdbg_va = windows->ntoskrnl_va - windows->kdbg_offset;
        dbprint(VMI_DEBUG_MISC, "**set KdDebuggerDataBlock address=0x%"PRIx64"\n",
                windows->kdbg_va);
    } else {
        /* only ntoskrnl or kdbg_offset were given, which are not
         * enough to find and calculate the others, so fall back to search methods. */
        goto find_kdbg;
    }

    addr_t test = 0;

    if (!windows->ntoskrnl) {
        if ( VMI_FAILURE == vmi_translate_kv2p(vmi, windows->ntoskrnl_va, &windows->ntoskrnl) )
            goto find_kdbg;

        dbprint(VMI_DEBUG_MISC, "**set KernBase PA=0x%"PRIx64"\n", windows->ntoskrnl);
    } else if (VMI_FAILURE == vmi_translate_kv2p(vmi, windows->ntoskrnl_va, &test) || test != windows->ntoskrnl) {
        errprint("Invalid configuration values, win_ntoskrnl not match translated KernBase physical address\n");
        goto exit;
    }

    goto done;

    // We don't have the standard config informations
    // so lets try our kdbg search method
find_kdbg:
    dbprint(VMI_DEBUG_MISC, "**Attempting KdDebuggerDataBlock search methods\n");

    if (VMI_SUCCESS == find_kdbg_address_instant(vmi, &kdbg_pa, &kernbase_pa, &kernbase_va)) {
        goto found;
    }
    if (VMI_SUCCESS == find_kdbg_address_faster(vmi, &kdbg_pa, &kernbase_pa, &kernbase_va)) {
        goto found;
    }
    if (VMI_SUCCESS == find_kdbg_address_fast(vmi, &kdbg_pa, &kernbase_pa, &kernbase_va)) {
        goto found;
    }

    /* NOTE: This is the only method that does anything for VMI_FILE */
    if (VMI_SUCCESS == find_kdbg_address(vmi, &kdbg_pa, &kernbase_va)) {
        kernbase_pa = get_ntoskrnl_base(vmi, 0);
        goto found;
    }

    dbprint(VMI_DEBUG_MISC, "**All KdDebuggerDataBlock search methods failed\n");
    goto exit;

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

    if (!windows->ntoskrnl) {
        windows->ntoskrnl = kernbase_pa;
        printf("LibVMI Suggestion: set win_ntoskrnl=0x%"PRIx64" in libvmi.conf for faster startup.\n",
               windows->ntoskrnl);
    } else if (windows->ntoskrnl != kernbase_pa) {
        errprint("LibVMI found physical kernel base address 0x%"PRIx64" that conflicts with provided value from config file!\n",
                 kernbase_pa);
        goto exit;
    }

    if (!windows->kdbg_offset) {
        windows->kdbg_offset = kdbg_pa - windows->ntoskrnl;
        printf("LibVMI Suggestion: set win_kdbg=0x%"PRIx64" in libvmi.conf for faster startup.\n",
               windows->kdbg_offset);
    } else if (windows->kdbg_offset != kdbg_pa - kernbase_pa) {
        errprint("LibVMI found win_kdbg offset 0x%"PRIx64" that conflicts with provided value from config file!\n",
                 kdbg_pa - kernbase_pa);
        goto exit;
    }

    if (!windows->kdbg_va) {
        windows->kdbg_va = windows->ntoskrnl_va + windows->kdbg_offset;
        printf("LibVMI Suggestion: set win_kdvb=0x%"PRIx64" in libvmi.conf for faster startup.\n",
               windows->kdbg_va);
    } else if (windows->kdbg_va != windows->ntoskrnl_va + windows->kdbg_offset) {
        errprint("LibVMI found win_kdvb offset 0x%"PRIx64" that conflicts with provided value from config file!\n",
                 windows->ntoskrnl_va + windows->kdbg_offset);
        goto exit;
    }

done:
    if (!kdbg_pa) {
        kdbg_pa = windows->ntoskrnl + windows->kdbg_offset;
    }
    windows->version = find_windows_version(vmi, kdbg_pa);
    if (VMI_OS_WINDOWS_UNKNOWN == windows->version) {
        errprint("Unsupported Windows version or incorrect configuration\n");
    }

    ret = VMI_SUCCESS;
exit:
    return ret;
}