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