Esempio n. 1
0
bool drakvuf_add_trap(drakvuf_t drakvuf, drakvuf_trap_t *trap) {

    bool ret = 0;
    vmi_pause_vm(drakvuf->vmi);

    if (!trap)
        goto done;

    if(g_hash_table_lookup(drakvuf->remove_traps, &trap)) {
        g_hash_table_remove(drakvuf->remove_traps, &trap);
        ret = 1;
        goto done;
    }

    switch(trap->type) {
        case BREAKPOINT:
            ret = inject_trap_breakpoint(drakvuf, trap);
            break;
        case MEMACCESS:
            ret = inject_trap_mem(drakvuf, trap);
            break;
        case REGISTER:
            ret = inject_trap_reg(drakvuf, trap);
            break;
        default:
            break;
    }

done:
    vmi_resume_vm(drakvuf->vmi);
    return ret;
}
void resume_vm(vmi_instance_t *vmi)
{
    /* resume the vm */
    /* cleanup any memory associated with the LibVMI instance */
    vmi_resume_vm(*vmi);
    vmi_destroy(*vmi);
}
Esempio n. 3
0
int start_app(honeymon_clone_t *clone, vmi_pid_t pid, const char *app) {

    vmi_pause_vm(clone->vmi);

    struct injector injector = {
        .clone = clone,
        .target_cr3 = vmi_pid_to_dtb(clone->vmi, pid),
        .target_pid = pid,
        .target_proc = app,
        .winver = clone->winver,
        .pm = vmi_get_page_mode(clone->vmi)
    };

    if (!injector.target_cr3)
        return 0;

    printf("Target PID %u with DTB 0x%lx to start '%s'\n", pid,
            injector.target_cr3, app);

    injector.cr3_event.type = VMI_EVENT_REGISTER;
    injector.cr3_event.reg_event.reg = CR3;
    injector.cr3_event.reg_event.in_access = VMI_REGACCESS_W;
    injector.cr3_event.callback = cr3_callback;
    injector.cr3_event.data = &injector;
    vmi_register_event(clone->vmi, &injector.cr3_event);

    vmi_event_t interrupt_event;
    memset(&interrupt_event, 0, sizeof(vmi_event_t));
    interrupt_event.type = VMI_EVENT_INTERRUPT;
    interrupt_event.interrupt_event.intr = INT3;
    interrupt_event.callback = injector_int3_cb;
    interrupt_event.data = &injector;
    vmi_register_event(clone->vmi, &interrupt_event);

    printf("Starting injection loop\n");
    vmi_resume_vm(clone->vmi);

    status_t status = VMI_FAILURE;
    while (!clone->interrupted) {
        //printf("Waiting for events...\n");
        status = vmi_events_listen(clone->vmi, 500);
        if (status != VMI_SUCCESS) {
            printf("Error waiting for events, quitting...\n");
            clone->interrupted = -1;
        }
    }

    vmi_clear_event(clone->vmi, &injector.cr3_event);
    vmi_clear_event(clone->vmi, &injector.mm_event);
    vmi_clear_event(clone->vmi, &injector.ss_event);
    vmi_clear_event(clone->vmi, &interrupt_event);

    printf("Finished with injection.\n");
    return injector.ret;
}
Esempio n. 4
0
File: hvm.c Progetto: 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;
}
Esempio n. 5
0
File: vmi6.c Progetto: allewwaly/HI
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;
		}
	}
Esempio n. 6
0
int introspect_process_list (char *name) {
    vmi_instance_t vmi;
    addr_t list_head = 0, next_list_entry = 0, current_process = 0;
    vmi_pid_t pid = 0;
    char *procname = NULL;

    if (vmi_init(&vmi, VMI_XEN | VMI_INIT_COMPLETE, name) == VMI_FAILURE) {
        printf("Failed to init LibVMI library.\n");
        return 1;
    }

    vmi_pause_vm(vmi);

    /**
     * get offsets of the kernel data structures
     * get the head of the task_struct 
     */

    switch(vmi_get_ostype(vmi)) {
        case VMI_OS_LINUX:
            tasks_offset = vmi_get_offset(vmi, "linux_tasks");
            name_offset = vmi_get_offset(vmi, "linux_name");
            pid_offset = vmi_get_offset(vmi, "linux_pid");

            list_head = vmi_translate_ksym2v(vmi, "init_task") + tasks_offset;

            break;
        case VMI_OS_WINDOWS:
            tasks_offset = vmi_get_offset(vmi, "win_tasks");
            name_offset = vmi_get_offset(vmi, "win_pname");
            pid_offset = vmi_get_offset(vmi, "win_pid");

            list_head = vmi_translate_ksym2v(vmi, "PsActiveProcessHead");

            break;
        default:
            goto exit;
    }


    if (tasks_offset == 0 || pid_offset == 0 || name_offset == 0) {
        printf("Failed to find offsets\n");
        goto exit;
    }

    next_list_entry = list_head;

    /** 
     * traverse the task lists and print out each process 
     */
    do {
        current_process = next_list_entry - tasks_offset;
        vmi_read_32_va(vmi, current_process + pid_offset, 0, (uint32_t*)&pid);
        procname = vmi_read_str_va(vmi, current_process + name_offset, 0);
        if (!procname) {
            printf("Failed to find procname\n");
            goto exit;
        }

        printf("[%5d] %s\n", pid, procname);

        free(procname);
        procname = NULL;

        if (vmi_read_addr_va(vmi, next_list_entry, 0, &next_list_entry) == VMI_FAILURE) {
            printf("Failed to read next pointer in loop at %"PRIx64"\n", next_list_entry);
            goto exit;
        }

    } while(next_list_entry != list_head);

exit:
    vmi_resume_vm(vmi);
    vmi_destroy(vmi);

    return 0;
}
Esempio n. 7
0
int main (int argc, char **argv)
{
    vmi_instance_t vmi;
    unsigned char *memory = NULL;
    uint32_t offset;
    addr_t list_head = 0, next_list_entry = 0;
    addr_t current_process = 0;
    addr_t tmp_next = 0;
    char *procname = NULL;
    vmi_pid_t pid = 0;
    unsigned long tasks_offset = 0, pid_offset = 0, name_offset = 0;
    status_t status;

    /* this is the VM or file that we are looking at */
    if (argc != 2) {
        printf("Usage: %s <vmname>\n", argv[0]);
        return 1;
    } // if

    char *name = argv[1];

    /* initialize the libvmi library */
    if (vmi_init(&vmi, VMI_AUTO | VMI_INIT_COMPLETE, name) == VMI_FAILURE) {
        printf("Failed to init LibVMI library.\n");
        return 1;
    }

    /* init the offset values */
    if (VMI_OS_LINUX == vmi_get_ostype(vmi)) {
        tasks_offset = vmi_get_offset(vmi, "linux_tasks");
        name_offset = vmi_get_offset(vmi, "linux_name");
        pid_offset = vmi_get_offset(vmi, "linux_pid");
    }
    else if (VMI_OS_WINDOWS == vmi_get_ostype(vmi)) {
        tasks_offset = vmi_get_offset(vmi, "win_tasks");
        name_offset = vmi_get_offset(vmi, "win_pname");
        pid_offset = vmi_get_offset(vmi, "win_pid");
    }

    if (0 == tasks_offset) {
        printf("Failed to find win_tasks\n");
        goto error_exit;
    }
    if (0 == pid_offset) {
        printf("Failed to find win_pid\n");
        goto error_exit;
    }
    if (0 == name_offset) {
        printf("Failed to find win_pname\n");
        goto error_exit;
    }

    /* pause the vm for consistent memory access */
    if (vmi_pause_vm(vmi) != VMI_SUCCESS) {
        printf("Failed to pause VM\n");
        goto error_exit;
    } // if

    /* demonstrate name and id accessors */
    char *name2 = vmi_get_name(vmi);

    if (VMI_FILE != vmi_get_access_mode(vmi)) {
        unsigned long id = vmi_get_vmid(vmi);

        printf("Process listing for VM %s (id=%lu)\n", name2, id);
    }
    else {
        printf("Process listing for file %s\n", name2);
    }
    free(name2);

    /* get the head of the list */
    if (VMI_OS_LINUX == vmi_get_ostype(vmi)) {
        /* Begin at PID 0, the 'swapper' task. It's not typically shown by OS
         *  utilities, but it is indeed part of the task list and useful to
         *  display as such.
         */
        list_head = vmi_translate_ksym2v(vmi, "init_task") + tasks_offset;
    }
    else if (VMI_OS_WINDOWS == vmi_get_ostype(vmi)) {

        // find PEPROCESS PsInitialSystemProcess
        if(VMI_FAILURE == vmi_read_addr_ksym(vmi, "PsActiveProcessHead", &list_head)) {
            printf("Failed to find PsActiveProcessHead\n");
            goto error_exit;
        }
    }

    next_list_entry = list_head;

    /* walk the task list */
    do {

        current_process = next_list_entry - tasks_offset;

        /* Note: the task_struct that we are looking at has a lot of
         * information.  However, the process name and id are burried
         * nice and deep.  Instead of doing something sane like mapping
         * this data to a task_struct, I'm just jumping to the location
         * with the info that I want.  This helps to make the example
         * code cleaner, if not more fragile.  In a real app, you'd
         * want to do this a little more robust :-)  See
         * include/linux/sched.h for mode details */

        /* NOTE: _EPROCESS.UniqueProcessId is a really VOID*, but is never > 32 bits,
         * so this is safe enough for x64 Windows for example purposes */
        vmi_read_32_va(vmi, current_process + pid_offset, 0, (uint32_t*)&pid);

        procname = vmi_read_str_va(vmi, current_process + name_offset, 0);

        if (!procname) {
            printf("Failed to find procname\n");
            goto error_exit;
        }

        /* print out the process name */
        printf("[%5d] %s (struct addr:%"PRIx64")\n", pid, procname, current_process);
        if (procname) {
            free(procname);
            procname = NULL;
        }

        /* follow the next pointer */

        status = vmi_read_addr_va(vmi, next_list_entry, 0, &next_list_entry);
        if (status == VMI_FAILURE) {
            printf("Failed to read next pointer in loop at %"PRIx64"\n", next_list_entry);
            goto error_exit;
        }

    } while(next_list_entry != list_head);

error_exit:
    /* resume the vm */
    vmi_resume_vm(vmi);

    /* cleanup any memory associated with the LibVMI instance */
    vmi_destroy(vmi);

    return 0;
}
Esempio n. 8
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;
}
extern proc_info *process_list (char *name, image_offset *img_offsets, 
                                char *config_string)
{
    vmi_instance_t vmi;
    addr_t list_head = 0, next_list_entry = 0;
    addr_t current_process_addr = 0;
    char *procname = NULL;
    status_t status;
    int image_offsets_provided = 0;

    printf("config_string: \n%s\n", config_string);

    /* initialize the libvmi library */
    if (vmi_init(&vmi, VMI_AUTO | VMI_INIT_PARTIAL, name) == VMI_FAILURE)
    {
        printf("Failed to init Libvmi Library on the first time.");
        return NULL;
    }
    if(vmi_init_complete_custom(&vmi, VMI_CONFIG_STRING, config_string) == VMI_FAILURE)
    {
        printf("Failed to init LibVMI library on the second time.\n");
        return NULL;
    }


    printf("1\n");
    /* initialize the offsets */
    if(img_offsets == NULL)
    {
        img_offsets = (image_offset*)malloc(sizeof(image_offset));

        if (get_vm_offsets(vmi, img_offsets) == VMI_FAILURE)
        {
            printf("Failed to load offsets.\n");
            vmi_destroy(vmi);
            free(img_offsets);
            return NULL;
        }
        
    }
    else
    {
        image_offsets_provided = 1;
        printf("Using provided image offsets\n");
    }

    printf("2\n");
    /* pause the vm for consistent memory access */
    if (vmi_pause_vm(vmi) != VMI_SUCCESS)
    {
        printf("Failed to pause VM\n");
        resume_vm(&vmi);
        if(!image_offsets_provided)
            free(img_offsets);
        return NULL;
    }

    /* demonstrate name and id accessors */
    char *name2 = vmi_get_name(vmi);

    if (VMI_FILE != vmi_get_access_mode(vmi))
    {
        uint64_t id = vmi_get_vmid(vmi);
        printf("Process listing for VM %s (id=%"PRIu64")\n", name2, id);
    }
    else
    {
        printf("Process listing for file %s\n", name2);
    }
    free(name2);

    /* get the head of the list */
    if (VMI_OS_LINUX == vmi_get_ostype(vmi))
    {
        /* Begin at PID 0, the 'swapper' task. It's not typically shown by OS
         *  utilities, but it is indeed part of the task list and useful to
         *  display as such.
         */
        list_head = vmi_translate_ksym2v(vmi, "init_task") + img_offsets->tasks_offset;
    }
    else if (VMI_OS_WINDOWS == vmi_get_ostype(vmi))
    {

        /* find PEPROCESS PsInitialSystemProcess */
        if(VMI_FAILURE == vmi_read_addr_ksym(vmi, "PsActiveProcessHead", &list_head))
        {
            printf("Failed to find PsActiveProcessHead\n");
            resume_vm(&vmi);
            if(!image_offsets_provided)
                free(img_offsets);
            return NULL;
        }
    }
    next_list_entry = list_head;

    /*
     * Run process analyse for two rounds.
     * The first round:
     *    - Collect basic process information: name, pid, etc;
     *    - Collect the initial s_time, u_time, mm for calculating
     *         cpu and memory usage;
     *    - Construct our own process-info struct (process-info linked list).
     * The second round:
     *    - Read current s_time, u_time, mm, etc. and calculate
     *         cpu and memory usage;
     *    - Finalize process-info struct;
     */

    /* The first round */
    /* walk the task list and create  */
    printf("First round.\n");
    proc_info *process_info_list_head = NULL, *previous_process_ptr = NULL, *current_process_ptr = NULL;
    int is_head = 1;
    time_t calculation_start_time, calculation_end_time;

    vmi_read_64_va(vmi, vmi_translate_ksym2v(vmi, "jiffies"), 0, &calculation_start_time);
    do {
        current_process_ptr = (proc_info*)malloc(sizeof(proc_info));
        current_process_addr = next_list_entry - img_offsets->tasks_offset;

        /* NOTE: _EPROCESS.UniqueProcessId is a really VOID*, but is never > 32 bits,
         * so this is safe enough for x64 Windows for example purposes */
        vmi_read_32_va(vmi, current_process_addr + img_offsets->pid_offset, 0, (uint32_t*)&(current_process_ptr->pid));
        current_process_ptr->name = vmi_read_str_va(vmi, current_process_addr + img_offsets->name_offset, 0);
        vmi_read_64_va(vmi, current_process_addr + img_offsets->utime_offset, 0, &(current_process_ptr->r_utime));
        vmi_read_64_va(vmi, current_process_addr + img_offsets->stime_offset, 0, &(current_process_ptr->r_stime));
        
        /* current_process_ptr->name == NULL implies reading process info is not successful */
        if (!current_process_ptr->name) {
            printf("Failed to find process name\n");
            resume_vm(&vmi);
            if(!image_offsets_provided)
                free(img_offsets);
            return NULL;
        }

        /* follow the next pointer and load the entry of next process*/
        status = vmi_read_addr_va(vmi, next_list_entry, 0, &next_list_entry);
        if (status == VMI_FAILURE) {
            printf("Failed to read next pointer in loop at %"PRIx64"\n", next_list_entry);
            resume_vm(&vmi);
            if(!image_offsets_provided)
                free(img_offsets);
            return NULL;
        }
        if(is_head){
            is_head = 0;
            process_info_list_head = current_process_ptr;
            previous_process_ptr = current_process_ptr;
        }else{
            previous_process_ptr->next = current_process_ptr;
            previous_process_ptr = current_process_ptr;
        }
    } while(next_list_entry != list_head);
    current_process_ptr->next = NULL;
    vmi_resume_vm(vmi);
    sleep(3);

    /* The second round */
    printf("Second round.\n");
    uint64_t total_memory_size = vmi_get_memsize(vmi) / 1024;                           // total_memory_size unit: KB
    int dont_read_next_process = 0;
    vmi_pause_vm(vmi);
    is_head = 1;
    int old_list_has_ended = 0;
    proc_info* old_list_ptr = process_info_list_head;
    current_process_ptr = process_info_list_head;
    previous_process_ptr = process_info_list_head;
    next_list_entry = list_head;

    vmi_pid_t proc_pid;
    uint64_t new_utime, new_stime, sum_process_time_before, sum_process_time_after;
    /* walk the task list */

    vmi_read_64_va(vmi, vmi_translate_ksym2v(vmi, "jiffies"), 0, &calculation_end_time);
    do {
        
        if (old_list_ptr == NULL)
        {
            old_list_has_ended = 1;
        }
        current_process_addr = next_list_entry - img_offsets->tasks_offset;

        /* NOTE: _EPROCESS.UniqueProcessId is a really VOID*, but is never > 32 bits,
         * so this is safe enough for x64 Windows for example purposes */
        vmi_read_32_va(vmi, current_process_addr + img_offsets->pid_offset, 0, (uint32_t*)&proc_pid);
        
        if(old_list_has_ended || proc_pid < old_list_ptr->pid)
        {
            /* new process was created between sleep time
             * and pid is smaller than current process pid
             */
            proc_info *new_process_ptr = (proc_info*)malloc(sizeof(proc_info));
            new_process_ptr->name = vmi_read_str_va(vmi, current_process_addr + img_offsets->name_offset, 0);
            new_process_ptr->type = P_NEW_PROCESS;
            vmi_read_32_va(vmi, current_process_addr + img_offsets->pid_offset, 0, (uint32_t*)&(new_process_ptr->pid));
            
            /* pointer related operations */
            if(is_head)
            {
                process_info_list_head = new_process_ptr;
                current_process_ptr = new_process_ptr;
                previous_process_ptr = new_process_ptr;
                is_head = 0;
            }
            else
            {
                current_process_ptr = new_process_ptr;
                previous_process_ptr->next = current_process_ptr;
                previous_process_ptr = current_process_ptr;
            }
        }
        else if (proc_pid > old_list_ptr->pid)
        {
            /* previous process has ended between sleep time */
            old_list_ptr->type = P_ENDED_PROCESS;
            dont_read_next_process = 1;

            if(is_head)
            {
                is_head = 0;
                old_list_ptr = old_list_ptr->next;
                continue;
            }

            current_process_ptr = old_list_ptr;
            previous_process_ptr->next = current_process_ptr;
            previous_process_ptr = current_process_ptr;
            old_list_ptr = old_list_ptr->next;
        }
        else
        {
            /* the process still exists. cpu% and mem% can be calculated*/
            current_process_ptr = old_list_ptr;
            current_process_ptr->type = P_EXIST_PROCESS;

            /* get priority and state */
            vmi_read_64_va(vmi, current_process_addr + img_offsets->state_offset, 0, (uint64_t*)&(current_process_ptr->state));
            vmi_read_32_va(vmi, current_process_addr + img_offsets->rt_priority_offset, 0, (uint32_t*)&(current_process_ptr->priority));

            /* read process cpu time */
            vmi_read_64_va(vmi, current_process_addr + img_offsets->utime_offset, 0, &new_utime);
            vmi_read_64_va(vmi, current_process_addr + img_offsets->stime_offset, 0, &new_stime);

            /* calculate cpu usage */
            sum_process_time_after = new_utime + new_stime;
            sum_process_time_before = current_process_ptr->r_stime + current_process_ptr->r_utime;
            current_process_ptr->cpu_percent = (double)(sum_process_time_after - sum_process_time_before) / (calculation_end_time - calculation_start_time) * 100.0;

            /* get total vm pages for calculating virtual memory usage */
            addr_t mm_addr = NULL;
            uint32_t total_vm_pages = 0;
            vmi_read_addr_va(vmi, current_process_addr + img_offsets->mm_offset, 0, &mm_addr);
            vmi_read_32_va(vmi, mm_addr + img_offsets->total_vm_offset,0, &total_vm_pages);
            current_process_ptr->virtual_memory_usage = total_vm_pages * PAGE_SIZE_KB;

            /* get rss count for calculating physical memory usage*/
            int i = 0;
            uint64_t rss_count = 0, temp = 0;
            for(i = 0; i < NR_MM_COUNTERS; i++)
            {
                vmi_read_64_va(vmi, mm_addr + img_offsets->rss_stat_offset + i * img_offsets->element_offset, 0, (uint64_t*)&temp);
                rss_count += temp;
            }
            current_process_ptr->physical_memory_usage = rss_count * PAGE_SIZE_KB;
            
            /* calculate memory usage (percent) */
            current_process_ptr->memory_percent = (double)rss_count * PAGE_SIZE_KB / total_memory_size * 100.0;
            
            
            /* deal with pointer */
            if(is_head)
                is_head = 0;
            else
            {    
                previous_process_ptr->next = current_process_ptr;
                previous_process_ptr = current_process_ptr;
            }
            old_list_ptr = old_list_ptr->next;
        }

        if(!dont_read_next_process)
        {
            /* follow the next pointer and load the entry of next process*/
            status = vmi_read_addr_va(vmi, next_list_entry, 0, &next_list_entry);
            if (status == VMI_FAILURE) 
            {
                printf("Failed to read next pointer in loop at %"PRIx64"\n", next_list_entry);
                resume_vm(&vmi);
                free(img_offsets);
                return NULL;
            }
        }
        else
            dont_read_next_process = 0;

    } while(next_list_entry != list_head);
    if(!old_list_has_ended)
        current_process_ptr->next = old_list_ptr;
    else if(current_process_ptr != NULL)
        current_process_ptr->next = NULL;

    if(!image_offsets_provided)
        free(img_offsets);
    vmi_resume_vm(vmi);
    vmi_destroy(vmi);

    //current_process_ptr = process_info_list_head;
    //while(current_process_ptr != NULL)
    //{
    //current_process_ptr = process_info_list_head;
    //while(current_process_ptr != NULL)
    //{
    //    printf("%d | %s | %04.2lf \n", current_process_ptr->pid, current_process_ptr->name, current_process_ptr->cpu_percent);
    //    current_process_ptr = current_process_ptr->next;
    //}

    return process_info_list_head;
}
Esempio n. 10
0
int
main(
    int argc,
    char **argv)
{
    vmi_instance_t vmi;
    uint32_t offset;
    addr_t next_module, list_head;

    /* this is the VM or file that we are looking at */
    char *name = argv[1];

    /* initialize the libvmi library */
    if (vmi_init(&vmi, VMI_AUTO | VMI_INIT_COMPLETE, name) ==
        VMI_FAILURE) {
        printf("Failed to init LibVMI library.\n");
        return 1;
    }

    /* pause the vm for consistent memory access */
    vmi_pause_vm(vmi);

    /* get the head of the module list */
    if (VMI_OS_LINUX == vmi_get_ostype(vmi)) {
        vmi_read_addr_ksym(vmi, "modules", &next_module);
    }
    else if (VMI_OS_WINDOWS == vmi_get_ostype(vmi)) {
        vmi_read_addr_ksym(vmi, "PsLoadedModuleList", &next_module);
    }
    list_head = next_module;

    /* walk the module list */
    while (1) {

        /* follow the next pointer */
        addr_t tmp_next = 0;

        vmi_read_addr_va(vmi, next_module, 0, &tmp_next);

        /* if we are back at the list head, we are done */
        if (list_head == tmp_next) {
            break;
        }

        /* print out the module name */

        /* Note: the module struct that we are looking at has a string
         * directly following the next / prev pointers.  This is why you
         * can just add the length of 2 address fields to get the name.
         * See include/linux/module.h for mode details */
        if (VMI_OS_LINUX == vmi_get_ostype(vmi)) {
            char *modname = NULL;

            if (VMI_PM_IA32E == vmi_get_page_mode(vmi)) {   // 64-bit paging
                modname = vmi_read_str_va(vmi, next_module + 16, 0);
            }
            else {
                modname = vmi_read_str_va(vmi, next_module + 8, 0);
            }
            printf("%s\n", modname);
            free(modname);
        }
        else if (VMI_OS_WINDOWS == vmi_get_ostype(vmi)) {
            /*TODO don't use a hard-coded offsets here */
            /* this offset works with WinXP SP2 */
            unicode_string_t *us =
                vmi_read_unicode_str_va(vmi, next_module + 0x2c, 0);
            unicode_string_t out = { 0 };
            //         both of these work
            if (us &&
                VMI_SUCCESS == vmi_convert_str_encoding(us, &out,
                                                        "UTF-8")) {
                printf("%s\n", out.contents);
                //            if (us && 
                //                VMI_SUCCESS == vmi_convert_string_encoding (us, &out, "WCHAR_T")) {
                //                printf ("%ls\n", out.contents);
                free(out.contents);
            }   // if
            if (us)
                vmi_free_unicode_str(us);
        }
        next_module = tmp_next;
    }

error_exit:
    /* resume the vm */
    vmi_resume_vm(vmi);

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

    return 0;
}
Esempio n. 11
0
int main (int argc, char **argv)
{
	// local variables
	vmi_instance_t vmi;
	int ret_val = 0; // return code for after goto
	struct sigaction signal_action;

	// process list vars
	vmi_pid_t pid = 0;
	char *procname = NULL;
	addr_t list_head = 0;
	addr_t next_list_entry = 0;
	addr_t current_process = 0;
	addr_t tmp_next = 0;
	status_t status;

	// breakpoint vars
	char*			*sym;
	uint16_t	*off;
	vmi_pid_t *bpid;
	addr_t		*add;
	uint8_t		*byt;

	addr_t lib_map_addr = 0;
	addr_t BN_rand_addr = 0;
	int bnrand_jump_offset = 0;
	addr_t bnrand_addr = 0;

	// this is the VM or file that we are looking at
	if (argc < 2) {
		printf("Usage: %s <vmname>\n", argv[0]);
		return 1;
	}
	
	char *name = argv[1];

	////////////////////
	// Initialization // 
	////////////////////

	// initialize the libvmi library
	printf("Initializing libvmi for VM \"%s\"\n", name);
	if (vmi_init(&vmi, VMI_XEN|VMI_INIT_COMPLETE|VMI_INIT_EVENTS, name) == VMI_FAILURE) {
		printf("Failed to init LibVMI library.\n");
		ret_val = 2;
		goto error_exit;
	}

	// verify OS is Linux
	printf("Verifying the VM is running Linux...");
	// TODO: verify that the VM is running a *supported* Linux kernel
	// if kernel is not one we recognize, don't run because we'll be mucking around in memory we don't understand
	if (VMI_OS_LINUX != vmi_get_ostype(vmi)) { // this only checks if /etc/libvmi.conf says it's "Linux"
		printf("\nVM is running %s, exiting...\n", vmi_get_ostype(vmi));
		ret_val = 3;
		goto error_exit;
	}
	printf(" Yup. Good to go.\n");

	// pause the vm for consistent memory access
	printf("Pausing the VM\n");
	if (vmi_pause_vm(vmi) != VMI_SUCCESS) {
		printf("Failed to pause VM\n");
		ret_val = 4;
		goto error_exit; // don't return directly, do cleanup first
	}

	tasks_offset					= vmi_get_offset(vmi, "linux_tasks");
	name_offset						= vmi_get_offset(vmi, "linux_name");
	pid_offset						= vmi_get_offset(vmi, "linux_pid");
	mm_offset							= vmi_get_offset(vmi, "linux_mm");
	// hardcoded because config_parser doesn't support dynamic config vars
	mmap_offset						= 0x0;
	vm_area_file_offset		= 0xa0;
	vm_area_next_offset		= 0x10;
	vm_area_start_offset	= 0x0;
	file_path_offset			= 0x10;
	dentry_offset					= 0x8;
	iname_offset					= 0x38;
	//mmap_offset = vmi_get_offset(vmi, "linux_mmap");
	//vm_area_file_offset = vmi_get_offset(vmi, "linux_vm_file");
	//vm_area_next_offset = vmi_get_offset(vmi, "linux_vm_next");
	//vm_area_start_offset = vmi_get_offset(vmi, "linux_vm_start");
	//file_path_offset = vmi_get_offset(vmi, "linux_f_path");
	//dentry_offset = vmi_get_offset(vmi, "linux_dentry");
	//iname_offset = vmi_get_offset(vmi, "linux_d_iname");

	if (0 == tasks_offset) {
		printf("Failed to find tasks_offset\n");
		goto error_exit;
	}   
	if (0 == pid_offset) {
		printf("Failed to find pid_offset\n");
		goto error_exit;
	}   
	if (0 == name_offset) {
		printf("Failed to find name_offset\n");
		goto error_exit;
	}   
	if (0 == mm_offset) {
		printf("Failed to find mm_offset\n");
		goto error_exit;
	}   
	//if (0 == mmap_offset) {
	//	printf("Failed to find mmap_offset\n");
	//	goto error_exit;
	//}   
	//if (0 == vm_area_file_offset) {
	//	printf("Failed to find vm_area_file_offset\n");
	//	goto error_exit;
	//}   
	//if (0 == vm_area_next_offset) {
	//	printf("Failed to find vm_area_next_offset\n");
	//	goto error_exit;
	//}   
	//if (0 == vm_area_start_offset) {
	//	printf("Failed to find vm_area_start_offset\n");
	//	goto error_exit;
	//}   
	//if (0 == file_path_offset) {
	//	printf("Failed to find file_path_offset\n");
	//	goto error_exit;
	//}   
	//if (0 == dentry_offset) {
	//	printf("Failed to find dentry_offset\n");
	//	goto error_exit;
	//}   
	//if (0 == iname_offset) {
	//	printf("Failed to find iname_offset\n");
	//	goto error_exit;
	//}   

	// Set up breakpoints
	breakpoints = (breakpoint_t*)calloc(MAX_BREAKPOINTS, sizeof(breakpoint_t)); // allocate space for each breakpoint, zero memory
	//add_breakpoint("extract_entropy_user", 155, 0, 0xe8, before_extract_buf);
	//add_breakpoint("extract_entropy_user", 160, 0, 0x83, after_extract_buf);
	// new breakpoints created below

	//////////////////////////
	// Find apache2 process //
	//////////////////////////

	// find pid of apache2 processes
	// for each process, read symbol table and find BN_rand function
	// at offset +13 bytes from BN_rand, we find an offset from the instruction at BN_rand+17 (probably around -700 bytes)
	// +570 bytes from the offset above, we find the instruction at which we want a breakpoint
	// so, breakpoint at BN_rand+17+[BN_rand+13]+570
	// then, at callback, read r13 for address of buffer, overwrite with TODO bytes

	// find pid of apache2 processes
	list_head = vmi_translate_ksym2v(vmi, "init_task") + tasks_offset; // find init_task struct and move to first linked list entry
	next_list_entry = list_head; // iterator
	do {
		current_process = next_list_entry - tasks_offset; // subtract tasks_offset back off to get to head of struct
		vmi_read_32_va(vmi, current_process + pid_offset, 0, (uint32_t*)&pid); // get pid of this process
		procname = vmi_read_str_va(vmi, current_process + name_offset, 0); // get process name of this process
		if (strncmp(procname,"apache2",sizeof("apache2")) == 0) {
			printf("Finding library address in %s [pid %d]\n",procname,pid);
			lib_map_addr = walk_vmmap_for_lib(vmi, current_process, "libcrypto.so.1.0.2");
			if (lib_map_addr == 0) { // if failed to find lib
				printf("Failed to find library in %s\n",procname);
				ret_val = 9;
				goto error_exit;
			}
			printf("Found library address: 0x%llx\n", lib_map_addr);
			// for each process, read symbol table and find BN_rand function
			BN_rand_addr = lib_map_addr + 0xd5a50; // static offset for BN_rand function
			// at offset +13 bytes from BN_rand, we find an offset from the instruction at BN_rand+17 (probably around -700 bytes)
			vmi_read_32_va(vmi, BN_rand_addr+13, pid, &bnrand_jump_offset); // get jump offset to bnrand function
			//printf("jump offset: %d\n",bnrand_jump_offset);
			bnrand_addr = BN_rand_addr+17+bnrand_jump_offset; // get address of bnrand function
			//printf("bnrand: 0x%llx\n", bnrand_addr);
			// +570 bytes from the offset above, we find the instruction at which we want a breakpoint
			add_breakpoint_addr(bnrand_addr + 570, pid, 0x31, bnrand_callback);
			//printf("Added breakpoint at 0x%llx\n",bnrand_addr+570);
		}
		status = vmi_read_addr_va(vmi, next_list_entry, 0, &next_list_entry); // follow linked-list->next to next element
		if (status == VMI_FAILURE) {
			printf("Failed to read next pointer in loop at %"PRIx64"\n", next_list_entry);
			goto error_exit;
		}

	} while(next_list_entry != list_head);




	for (int i = 0; i < num_breakpoints; i++) { // iterate over breakpoints and find the right addresses for them

		////////////////////////////////////////////
		// Find memory location to put breakpoint //
		////////////////////////////////////////////

		// assign short names (note: modifying these modifies the breakpoint struct)
		sym = &breakpoints[i].symbol;
		off = &breakpoints[i].offset;
		bpid = &breakpoints[i].pid;
		add = &breakpoints[i].addr;
		byt = &breakpoints[i].inst_byte; // remember that if this is not set above, it should be zeroed from calloc

		if (breakpoints[i].addr == 0) { // if don't have address, find symbol
			// find address to break on
			printf("Accessing System Map for %s symbol\n", *sym);
			*add = vmi_translate_ksym2v(vmi, *sym) + *off;
			printf("%s + %u is at 0x%llx\n", *sym, *off, *add);
		}

		// either verify the byte there is correct, or record which byte is there for later replacing
		if (*byt == 0) { // if this byte was not set, we need to get it
			vmi_read_8_va(vmi, *add, *bpid, byt); // read it directly into byt
			printf("[pid %d] Saving byte at address 0x%llx: %x\n", *bpid, *add, *byt);
		} else { // if the byte was set, verify that it's currently set to that value
			uint8_t temp_byte = 0;
			vmi_read_8_va(vmi, *add, *bpid, &temp_byte); // read it temporarily
			printf("[pid %d] Checking byte at address 0x%llx is set to %x: %x\n", *bpid, *add, *byt, temp_byte);
			if (*byt != temp_byte) { // uh oh, we have an error
				ret_val = 8;
				goto error_exit;
			}
		}
	} // end first for loop after breakpoints are constructed properly

	///////////////////
	// Main gameplan //
	//               //
	// https://groups.google.com/forum/#!topic/vmitools/jNGxM0LBEDM
	// Based on the google groups discussion above (which I wish I found earlier, meh), it looks like the way people trap on instructions is to:
	//	1) actually *modify* the memory to have the 0xcc (interrupt 3, aka breakpoint) instruction in place of the instruction it would have executed
	//	2) register an event on receiving the INT3 signal and receive the callback
	//	3) at the end of the callback, fix the memory to its original instruction,
	//	4) single-step one instruction forward, executing the one instruction, then getting another callback
	//	5) replace the previous instruction with to 0xcc, "resetting" the breakpoint, then clearing the event and continuing
	//               //
	///////////////////

	for (int i = 0; i < num_breakpoints; i++) { // iterate over breakpoints and insert them all

		// assign short names (note: modifying these modifies the breakpoint struct)
		add = &breakpoints[i].addr;
		bpid = &breakpoints[i].pid;
		byt = &breakpoints[i].inst_byte;

		// Step 1: modify memory in the VM with an INT3 instruction (0xcc)
		printf("[pid %d] Setting breakpoint at address 0x%llx.\n", *bpid, *add);
		uint8_t int3 = INT3_INST; // create temporary variable because we can't use an address to a static #defined int
		if (VMI_SUCCESS != vmi_write_8_va(vmi, *add, *bpid, &int3)) {
			printf("[pid %d] Couldn't write INT3 instruction to memory... exiting.\n", *bpid);
			ret_val = 5;
			goto error_exit;
		}

		// debug: check memory is now an INT3 instruction
		uint8_t temp_byte = 0;
		vmi_read_8_va(vmi, *add, 0, &temp_byte);
		printf("[pid %d] This should be an INT3 instruction (0xcc): 0x%x\n", *bpid, temp_byte);


	} // end second for loop after breakpoints are all inserted and callback is registered

	// Step 2: register an event on receiving INT3 signal
	printf("Creating event for callback when breakpoint is reached.\n");
	memset(&rng_event, 0, sizeof(vmi_event_t)); // clear rng_event so we can set everything fresh
	rng_event.type = VMI_EVENT_INTERRUPT; // interrupt event -- trigger when interrupt occurs
	rng_event.interrupt_event.intr = INT3; // trigger on INT3 instruction
	rng_event.interrupt_event.reinject = 0; // swallow interrupt silently without passing it on to guest
	rng_event.callback = rng_int3_event_callback; // reference to our callback function
	printf("Registering event...\n");
	if (VMI_SUCCESS == vmi_register_event(vmi, &rng_event)) {; // register the event!
		printf("Event Registered!\n");
	} else { // uh oh, event failed
		printf("Problem registering event... exiting.\n");
		ret_val = 6;
		goto error_exit; // don't return directly, do cleanup first
	}

	// resume the VM
	printf("Resuming the VM\n");
	vmi_resume_vm(vmi);

	//////////////////////////////////////
	// Spin and wait for event callback // 
	//////////////////////////////////////

	// for a clean exit, catch signals (from host, not VM), set "interrupted" to non-zero, exit while loop at end of main()
	signal_action.sa_handler = close_handler;
	signal_action.sa_flags = 0;
	sigemptyset(&signal_action.sa_mask);
	sigaction(SIGHUP,  &signal_action, NULL);
	sigaction(SIGTERM, &signal_action, NULL);
	sigaction(SIGINT,  &signal_action, NULL);
	sigaction(SIGALRM, &signal_action, NULL);

	while(!interrupted) { // until an interrupt happens
		printf("Waiting for events...\n");
		if (VMI_SUCCESS != vmi_events_listen(vmi, 500)) { // listen for events for 500ms (no event = VMI_SUCCESS)
			printf("Error waiting for events... exiting.\n");
			interrupted = -1;
		}
	}
	printf("Finished with test.\n");

	//////////////////
	// Exit cleanly // 
	//////////////////

error_exit:
	// attempt to remove breakpoints
	for (int i = 0; i < num_breakpoints; i++) { // iterate over breakpoints and insert them all

		// assign short names (note: modifying these modifies the breakpoint struct)
		add = &breakpoints[i].addr;
		bpid = &breakpoints[i].pid;
		byt = &breakpoints[i].inst_byte;

		printf("[pid %d] Removing breakpoint %d at 0x%llx.\n", *bpid, i, *add);
		if (VMI_SUCCESS != vmi_write_8_va(vmi, *add, *bpid, byt)) {
			printf("Couldn't write to memory... exiting.\n");
			ret_val = 7;
		}
	}

	// resume the vm
	printf("Resuming the VM\n");
	vmi_resume_vm(vmi);

	// cleanup any memory associated with the LibVMI instance
	printf("Cleaning up\n");
	vmi_destroy(vmi);

	return ret_val;
}
Esempio n. 12
0
int main (int argc, char **argv)
{
    vmi_instance_t vmi;
    unsigned char *memory = NULL;
    uint32_t offset;
    addr_t next_process, list_head;
    char *procname = NULL;
    int pid = 0;
    int tasks_offset, pid_offset, name_offset;
    status_t status;

    /* this is the VM or file that we are looking at */
    if (argc != 2) {
        printf ("Usage: %s <vmname>\n", argv[0]);
        return 1;
    } // if

    char *name = argv[1];

    /* initialize the libvmi library */
    if (vmi_init(&vmi, VMI_AUTO | VMI_INIT_COMPLETE, name) == VMI_FAILURE){
        printf("Failed to init LibVMI library.\n");
        goto error_exit;
    }

    /* init the offset values */
    if (VMI_OS_LINUX == vmi_get_ostype(vmi)){
        tasks_offset = vmi_get_offset(vmi, "linux_tasks");
        name_offset = vmi_get_offset(vmi, "linux_name");
        pid_offset = vmi_get_offset(vmi, "linux_pid");
	
        /* NOTE: 
         *  name_offset is no longer hard-coded. Rather, it is now set 
         *  via libvmi.conf.
         */
    }
    else if (VMI_OS_WINDOWS == vmi_get_ostype(vmi)){
        tasks_offset = vmi_get_offset(vmi, "win_tasks");
        if (0 == tasks_offset) {
            printf("Failed to find win_tasks\n");
            goto error_exit;
        }
        name_offset = vmi_get_offset(vmi, "win_pname");
        if (0 == tasks_offset) {
            printf("Failed to find win_pname\n");
            goto error_exit;
        }
        pid_offset = vmi_get_offset(vmi, "win_pid");
        if (0 == tasks_offset) {
            printf("Failed to find win_pid\n");
            goto error_exit;
        }
    }

    /* pause the vm for consistent memory access */
    if (vmi_pause_vm(vmi) != VMI_SUCCESS) {
        printf("Failed to pause VM\n");
        goto error_exit;
    } // if

    /* demonstrate name and id accessors */
    char *name2 = vmi_get_name(vmi);
    if (VMI_FILE != vmi_get_access_mode(vmi)){
        unsigned long id = vmi_get_vmid(vmi);
        printf("Process listing for VM %s (id=%lu)\n", name2, id);
    }
    else{
        printf("Process listing for file %s\n", name2);
    }
    free(name2);

    /* get the head of the list */
    if (VMI_OS_LINUX == vmi_get_ostype(vmi)){
        addr_t init_task_va = vmi_translate_ksym2v(vmi, "init_task");
        vmi_read_addr_va(vmi, init_task_va + tasks_offset, 0, &next_process);
    }
    else if (VMI_OS_WINDOWS == vmi_get_ostype(vmi)){

        uint32_t pdbase = 0;

        // find PEPROCESS PsInitialSystemProcess
        vmi_read_addr_ksym(vmi, "PsInitialSystemProcess", &list_head); 
        
        vmi_read_addr_va(vmi, list_head + tasks_offset, 0, &next_process);
        vmi_read_32_va(vmi, list_head + pid_offset, 0, &pid);

        vmi_read_32_va(vmi, list_head + pid_offset, 0, &pid);
        procname = vmi_read_str_va(vmi, list_head + name_offset, 0);
        if (!procname) {
            printf ("Failed to find first procname\n");
            goto error_exit;
        }

        printf("[%5d] %s\n", pid, procname);
        if (procname){
            free(procname);
            procname = NULL;
        }
    }

    list_head = next_process;

    /* walk the task list */
    while (1){

        /* follow the next pointer */
        addr_t tmp_next = 0;
        vmi_read_addr_va(vmi, next_process, 0, &tmp_next);

        /* if we are back at the list head, we are done */
        if (list_head == tmp_next){
            break;
        }

        /* print out the process name */

        /* Note: the task_struct that we are looking at has a lot of
           information.  However, the process name and id are burried
           nice and deep.  Instead of doing something sane like mapping
           this data to a task_struct, I'm just jumping to the location
           with the info that I want.  This helps to make the example
           code cleaner, if not more fragile.  In a real app, you'd
           want to do this a little more robust :-)  See
           include/linux/sched.h for mode details */
        procname = vmi_read_str_va(vmi, next_process + name_offset - tasks_offset, 0);

        if (!procname) {
            printf ("Failed to find procname\n");
        } // if

        vmi_read_32_va(vmi, next_process + pid_offset - tasks_offset, 0, &pid);

        /* trivial sanity check on data */
        if (pid >= 0 && procname){
            printf("cr3: %lx [%5d] %s\n", vmi_pid_to_dtb(vmi, pid), pid, procname);
        }
        if (procname){
            free(procname);
            procname = NULL;
        }
        next_process = tmp_next;
    }

error_exit:
    if (procname) free(procname);

    /* resume the vm */
    vmi_resume_vm(vmi);

    /* cleanup any memory associated with the LibVMI instance */
    vmi_destroy(vmi);

    return 0;
}