END_TEST /* test determine mode and init function */ START_TEST (test_libvmi_init2) { vmi_instance_t vmi = NULL; vmi_mode_t mode; status_t ret = vmi_get_access_mode(vmi, (void*)get_testvm(), VMI_INIT_DOMAINNAME, NULL, &mode); fail_unless(ret == VMI_SUCCESS, "vmi_get_access_mode failed to identify the hypervisor"); ret = vmi_init(&vmi, mode, (void*)get_testvm(), VMI_INIT_DOMAINNAME, NULL, NULL); fail_unless(ret == VMI_SUCCESS, "vmi_init failed"); fail_unless(vmi != NULL, "vmi_init failed to initialize vmi instance struct"); vmi_destroy(vmi); }
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; }
void list_processes(vmi_instance_t vmi, addr_t current_process, addr_t list_head, unsigned long tasks_offset, addr_t current_list_entry, addr_t next_list_entry, unsigned long pid_offset, vmi_pid_t pid, char* procname, unsigned long name_offset) { /* 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. */ current_process = vmi_translate_ksym2v(vmi, "init_task"); } else if (VMI_OS_WINDOWS == vmi_get_ostype(vmi)) { // find PEPROCESS PsInitialSystemProcess vmi_read_addr_ksym(vmi, "PsInitialSystemProcess", ¤t_process); } /* walk the task list */ list_head = current_process + tasks_offset; current_list_entry = list_head; status_t status = vmi_read_addr_va(vmi, current_list_entry, 0, &next_list_entry); if (status == VMI_FAILURE) { printf("Failed to read next pointer at 0x%"PRIx64" before entering loop\n", current_list_entry); goto error_exit; } printf("Next list entry is at: %"PRIx64"\n", next_list_entry); do { /* 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; } current_list_entry = next_list_entry; current_process = current_list_entry - tasks_offset; /* follow the next pointer */ status = vmi_read_addr_va(vmi, current_list_entry, 0, &next_list_entry); if (status == VMI_FAILURE) { printf("Failed to read next pointer in loop at %"PRIx64"\n", current_list_entry); goto error_exit; } } while (next_list_entry != list_head); error_exit: if (procname) free(procname); }
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; }
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; }
int main(int argc, char **argv) { vmi_instance_t vmi = NULL; vmi_mode_t mode; /* this is the VM that we are looking at */ if (argc != 3) { printf("Usage: %s name|domid <domain name|domain id>\n", argv[0]); return 1; } // if void *domain; uint64_t domid = VMI_INVALID_DOMID; uint64_t init_flags = 0; if(strcmp(argv[1],"name")==0) { domain = (void*)argv[2]; init_flags |= VMI_INIT_DOMAINNAME; } else if(strcmp(argv[1],"domid")==0) { domid = strtoull(argv[2], NULL, 0); domain = (void*)&domid; init_flags |= VMI_INIT_DOMAINID; } else { printf("You have to specify either name or domid!\n"); return 1; } if (VMI_FAILURE == vmi_get_access_mode(vmi, domain, init_flags, NULL, &mode) ) return 1; /* initialize the libvmi library */ if (VMI_FAILURE == vmi_init(&vmi, mode, domain, init_flags, NULL, NULL)) { printf("Failed to init LibVMI library.\n"); return 1; } max_mem = vmi_get_max_physical_address(vmi); /* the nice thing about the windows kernel is that it's page aligned */ uint32_t found = 0; access_context_t ctx = { .translate_mechanism = VMI_TM_NONE, }; for(ctx.addr = 0; ctx.addr < max_mem; ctx.addr += PAGE_SIZE) { uint8_t pe[MAX_HEADER_SIZE]; if(VMI_SUCCESS == peparse_get_image(vmi, &ctx, MAX_HEADER_SIZE, pe)) { if(VMI_SUCCESS == is_WINDOWS_KERNEL(vmi, ctx.addr, pe)) { printf("Windows Kernel found @ 0x%" PRIx64 "\n", ctx.addr); print_os_version(pe); print_guid(vmi, ctx.addr, pe); print_pe_header(vmi, ctx.addr, pe); found=1; break; } } } /* cleanup any memory associated with the LibVMI instance */ vmi_destroy(vmi); if(found) return 0; return 1; }