void ss_callback(vmi_instance_t vmi, vmi_event_t *event) { reg_t rip, cr3; vmi_get_vcpureg(vmi, &rip, RIP, event->vcpu_id); vmi_get_vcpureg(vmi, &cr3, CR3, event->vcpu_id); page_mode_t pm = vmi_get_page_mode(vmi); vmi_pid_t pid = vmi_dtb_to_pid(vmi, cr3); printf("----- Singlestep: CR3 0x%lx PID %u executing RIP 0x%lx\n", cr3, pid, rip); if ((PM2BIT(pm) == BIT32 && rip < KERNEL32) || (PM2BIT(pm) == BIT64 && rip < KERNEL64)) { printf("Good RIP: 0x%lx\n", rip); struct injector *injector = event->data; injector->ss_enabled = 0; injector->target_pid = pid; injector->target_rip = vmi_pagetable_lookup(vmi, cr3, rip); hijack_thread(injector, vmi, event->vcpu_id, pid); vmi_clear_event(vmi, event); vmi_clear_event(vmi, &injector->cr3_event); injector->mm_count++; uint8_t trap = 0xCC; vmi_read_8_pa(vmi, injector->target_rip, &injector->backup); vmi_write_8_pa(vmi, injector->target_rip, &trap); } }
void mm_callback(vmi_instance_t vmi, vmi_event_t *event) { struct injector *injector = event->data; reg_t rip, cr3, rsp; vmi_get_vcpureg(vmi, &rip, RIP, event->vcpu_id); vmi_get_vcpureg(vmi, &cr3, CR3, event->vcpu_id); vmi_get_vcpureg(vmi, &rsp, RSP, event->vcpu_id); vmi_pid_t pid = vmi_dtb_to_pid(vmi, cr3); printf("----- Memevent: PID %u executing RIP 0x%lx. Target PID: %u. Target RIP: 0x%lx. My event count: %u\n", pid, ((event->mem_event.gfn<<12) + event->mem_event.offset), injector->target_pid, injector->target_rip, injector->mm_count); if ((PM2BIT(injector->pm) == BIT32 && rip < KERNEL32) || (PM2BIT(injector->pm) == BIT64 && rip < KERNEL64)) { injector->target_pid = pid; injector->target_rip = (event->mem_event.gfn << 12) + event->mem_event.offset; hijack_thread(injector, vmi, event->vcpu_id, pid); vmi_clear_event(vmi, event); vmi_clear_event(vmi, &injector->cr3_event); injector->mm_count++; uint8_t trap = 0xCC; vmi_read_8_pa(vmi, injector->target_rip, &injector->backup); vmi_write_8_pa(vmi, injector->target_rip, &trap); return; } vmi_clear_event(vmi, event); vmi_step_event(vmi, event, event->vcpu_id, 1, NULL); }
event_response_t mm_callback(vmi_instance_t vmi, vmi_event_t *event) { vmi_get_vcpureg(vmi, &cr3, CR3, 0); vmi_pid_t current_pid = vmi_dtb_to_pid(vmi, cr3); reg_t rip_test; vmi_get_vcpureg(vmi, &rip_test, RIP, 0); printf("Memevent: {\n\tPID %u. RIP 0x%lx:\n", current_pid, rip_test); print_event(event); if( current_pid == pid && event->mem_event.gla == rip) { printf("\tCought the original RIP executing again!"); vmi_clear_event(vmi, event, NULL); interrupted = 1; } else { printf("\tEvent on same page, but not the same RIP"); vmi_clear_event(vmi, event, NULL); /* These two calls are equivalent */ //vmi_step_event(vmi, event, event->vcpu_id, 1, NULL); vmi_step_event(vmi, event, event->vcpu_id, 1, step_callback); } printf("\n}\n"); return 0; }
event_response_t cr3_one_task_callback(vmi_instance_t vmi, vmi_event_t *event){ vmi_pid_t pid = vmi_dtb_to_pid(vmi, event->reg_event.value); printf("one_task callback\n"); if(event->reg_event.value == cr3){ printf("My process with PID %"PRIi32", CR3=%"PRIx64" is executing on vcpu %"PRIu32". Previous CR3=%"PRIx64"\n", pid, event->reg_event.value, event->vcpu_id, event->reg_event.previous); msr_syscall_sysenter_event.mem_event.in_access = VMI_MEMACCESS_X; msr_syscall_sysenter_event.callback=msr_syscall_sysenter_cb; kernel_sysenter_target_event.mem_event.in_access = VMI_MEMACCESS_X; kernel_sysenter_target_event.callback=ia32_sysenter_target_cb; kernel_vsyscall_event.mem_event.in_access = VMI_MEMACCESS_X; kernel_vsyscall_event.callback=vsyscall_cb; if(vmi_register_event(vmi, &msr_syscall_sysenter_event) == VMI_FAILURE) fprintf(stderr, "Could not install sysenter syscall handler.\n"); if(vmi_register_event(vmi, &kernel_sysenter_target_event) == VMI_FAILURE) fprintf(stderr, "Could not install sysenter syscall handler.\n"); if(vmi_register_event(vmi, &kernel_vsyscall_event) == VMI_FAILURE) fprintf(stderr, "Could not install sysenter syscall handler.\n"); } else{ printf("PID %i is executing, not my process!\n", pid); vmi_clear_event(vmi, &msr_syscall_sysenter_event, NULL); } return 0; }
void cr3_one_task_callback(vmi_instance_t vmi, vmi_event_t *event){ vmi_pid_t pid = vmi_dtb_to_pid(vmi, event->reg_event.value); printf("one_task callback\n"); if(event->reg_event.value == cr3){ printf("My process (PID %i) is executing on vcpu %ud\n", pid, event->vcpu_id); msr_syscall_sysenter_event.mem_event.in_access = VMI_MEMACCESS_X; msr_syscall_sysenter_event.callback=msr_syscall_sysenter_cb; kernel_sysenter_target_event.mem_event.in_access = VMI_MEMACCESS_X; kernel_sysenter_target_event.callback=ia32_sysenter_target_cb; kernel_vsyscall_event.mem_event.in_access = VMI_MEMACCESS_X; kernel_vsyscall_event.callback=vsyscall_cb; if(vmi_register_event(vmi, &msr_syscall_sysenter_event) == VMI_FAILURE) fprintf(stderr, "Could not install sysenter syscall handler.\n"); if(vmi_register_event(vmi, &kernel_sysenter_target_event) == VMI_FAILURE) fprintf(stderr, "Could not install sysenter syscall handler.\n"); if(vmi_register_event(vmi, &kernel_vsyscall_event) == VMI_FAILURE) fprintf(stderr, "Could not install sysenter syscall handler.\n"); } else{ printf("PID %i is executing, not my process!\n", pid); vmi_clear_event(vmi, &msr_syscall_sysenter_event); } }
void cr3_all_tasks_callback(vmi_instance_t vmi, vmi_event_t *event){ vmi_pid_t pid = vmi_dtb_to_pid(vmi, event->reg_event.value); printf("PID %i with CR3=%"PRIx64" executing on vcpu %u.\n", pid, event->reg_event.value, event->vcpu_id); msr_syscall_sysenter_event.mem_event.in_access = VMI_MEMACCESS_X; msr_syscall_sysenter_event.callback=msr_syscall_sysenter_cb; if(vmi_register_event(vmi, &msr_syscall_sysenter_event) == VMI_FAILURE) fprintf(stderr, "Could not install sysenter syscall handler.\n"); vmi_clear_event(vmi, &msr_syscall_sysenter_event); }
event_response_t cr3_callback(vmi_instance_t vmi, vmi_event_t *event){ vmi_pid_t current_pid = vmi_dtb_to_pid(vmi, event->reg_event.value); printf("PID %i with CR3=%"PRIx64" executing on vcpu %u.\n", current_pid, event->reg_event.value, event->vcpu_id); if(current_pid == pid) { if(!mm_enabled) { mm_enabled = 1; printf(" -- Enabling mem-event\n"); vmi_register_event(vmi, &mm_event); } } else { if(mm_enabled) { mm_enabled = 0; printf(" -- Disabling mem-event\n"); vmi_clear_event(vmi, &mm_event, NULL); } } return 0; }
event_response_t bnrand_callback(vmi_instance_t vmi, vmi_event_t *event) { uint64_t nbytes; addr_t buf_addr; uint8_t* buffer; vmi_pid_t pid = vmi_dtb_to_pid(vmi, event->regs.x86->cr3); printf("Called bnrand_callback from pid %d!\n"); // look at args printf("Reading RDI register (*buf): 0x%llx\n", event->regs.x86->rdi); printf("Reading RSI register (bytes): 0x%llx\n", event->regs.x86->rsi); printf("Reading RDX register (*rnd): 0x%llx\n", event->regs.x86->rdx); // read in all the bytes at buf nbytes = event->regs.x86->rsi; buf_addr = event->regs.x86->rdi; buffer = malloc(nbytes); // allocate buffer vmi_read_va(vmi, buf_addr, pid, buffer, nbytes); printf("old buf: "); for (unsigned int i = 0; i < nbytes; i++) { printf("%02x ",buffer[i]); } printf("\n"); // modify rng buffer! vmi_write_va(vmi, buf_addr, pid, RNG_VALUE, nbytes); // read in all the bytes at buf again (sanity check) vmi_read_va(vmi, buf_addr, pid, buffer, nbytes); printf("new buf: "); for (unsigned int i = 0; i < nbytes; i++) { printf("%02x ",buffer[i]); } printf("\n"); return VMI_SUCCESS; }
void injector_int3_cb(vmi_instance_t vmi, vmi_event_t *event) { struct injector *injector = event->data; addr_t pa = (event->interrupt_event.gfn << 12) + event->interrupt_event.offset; reg_t cr3; vmi_get_vcpureg(vmi, &cr3, CR3, event->vcpu_id); vmi_pid_t pid = vmi_dtb_to_pid(vmi, cr3); printf("INT3 @ 0x%lx. PID %u\n", pa, pid); if (pa == injector->userspace_return) { event->interrupt_event.reinject = 0; if (pid != injector->target_pid) { printf("Userspace return trap hit by another PID, not the target (%u)\n", injector->target_pid); vmi_write_8_pa(vmi, pa, &injector->userspace_return_backup); vmi_step_event(vmi, event, event->vcpu_id, 1, reset_return_trap); return; } injector->target_pid = pid; injector->target_rip = pa; injector->backup = injector->userspace_return_backup; injector->userspace_return = 0; hijack_thread(injector, vmi, event->vcpu_id, pid); /* injector->ss_enabled = 1; memset(&injector->ss_event, 0, sizeof(vmi_event_t)); injector->ss_event.type = VMI_EVENT_SINGLESTEP; injector->ss_event.callback = ss_callback; injector->ss_event.data = injector; SET_VCPU_SINGLESTEP(injector->ss_event.ss_event, event->vcpu_id); vmi_register_event(vmi, &injector->ss_event); */ vmi_clear_event(vmi, &injector->cr3_event); injector->mm_count++; return; } if (pa == injector->target_rip) { event->interrupt_event.reinject = 0; if (pid != injector->target_pid) { printf("Return trap hit by another PID, not the target (%u)\n", injector->target_pid); vmi_write_8_pa(vmi, pa, &injector->backup); vmi_step_event(vmi, event, event->vcpu_id, 1, reset_return_trap); return; } reg_t rax; vmi_get_vcpureg(vmi, &rax, RAX, event->vcpu_id); vmi_pid_t pid = vmi_dtb_to_pid(vmi, cr3); printf("RAX: 0x%lx\n", rax); printf("Restoring RSP to 0x%lx\n", injector->saved_rsp); printf("Restoring RAX to 0x%lx\n", injector->saved_rax); printf("Restoring RCX to 0x%lx\n", injector->saved_rcx); printf("Restoring RDX to 0x%lx\n", injector->saved_rdx); printf("Restoring R8 to 0x%lx\n", injector->saved_r8); printf("Restoring R9 to 0x%lx\n", injector->saved_r9); vmi_set_vcpureg(vmi, injector->saved_rsp, RSP, event->vcpu_id); vmi_set_vcpureg(vmi, injector->saved_rax, RAX, event->vcpu_id); vmi_set_vcpureg(vmi, injector->saved_rcx, RCX, event->vcpu_id); vmi_set_vcpureg(vmi, injector->saved_rdx, RDX, event->vcpu_id); vmi_set_vcpureg(vmi, injector->saved_r8, R8, event->vcpu_id); vmi_set_vcpureg(vmi, injector->saved_r9, R9, event->vcpu_id); if (rax) { printf("-- CreateProcessA SUCCESS --\n"); if (PM2BIT(injector->pm) == BIT32) { struct process_information_32 pip; vmi_read_va(vmi, injector->process_info, pid, &pip, sizeof(struct process_information_32)); printf("\tProcess handle: 0x%x. Thread handle: 0x%x\n", pip.hProcess, pip.hThread); printf("\tPID: %u. TID: %u\n", pip.dwProcessId, pip.dwThreadId); injector->pid = pip.dwProcessId; injector->tid = pip.dwThreadId; injector->hProc = pip.hProcess; injector->hThr = pip.hThread; } else { struct process_information_64 pip; vmi_read_va(vmi, injector->process_info, pid, &pip, sizeof(struct process_information_64)); printf("\tProcess handle: 0x%lx. Thread handle: 0x%lx\n", pip.hProcess, pip.hThread); printf("\tPID: %u. TID: %u\n", pip.dwProcessId, pip.dwThreadId); injector->pid = pip.dwProcessId; injector->tid = pip.dwThreadId; injector->hProc = pip.hProcess; injector->hThr = pip.hThread; } if (injector->pid && injector->tid) { injector->ret = rax; injector->cr3_event.callback = waitfor_cr3_callback; injector->cr3_event.reg_event.equal = vmi_pid_to_dtb(vmi, injector->pid); injector->cr3_event.data = injector; vmi_register_event(vmi, &injector->cr3_event); printf("\tInjected process CR3: 0x%lx\n", injector->cr3_event.reg_event.equal); } } else { injector->clone->interrupted = 1; } vmi_write_8_pa(vmi, pa, &injector->backup); vmi_clear_event(vmi, event); } else { event->interrupt_event.reinject = 1; } }
void cr3_callback(vmi_instance_t vmi, vmi_event_t *event) { //printf("CR3 changed to 0x%lx\n", event->reg_event.value); struct injector *injector = event->data; addr_t thread = 0, kpcrb_offset = 0, trapframe = 0; addr_t userspace_return_va = 0, userspace_return_pa = 0; reg_t fsgs = 0; if (event->reg_event.value == injector->target_cr3) { if (!injector->target_rip) { /* TODO: Trap frame approach only works on 64-bit */ if (PM2BIT(injector->pm) == BIT32) { if(!injector->mm_enabled) { vmi_pid_t pid = vmi_dtb_to_pid(vmi, event->reg_event.value); addr_t waitfor = sym2va(vmi, pid, "kernel32.dll", "WaitForMultipleObjects"); //printf("PID %u waitfor 0x%lx\n", pid, waitfor); if (!waitfor) { //injector->clone->interrupted = 1; printf("Target process doesn't have kernel32.dll mapped!\n"); return; } injector->mm_enabled=1; memset(&injector->mm_event, 0, sizeof(vmi_event_t)); injector->mm_event.type = VMI_EVENT_MEMORY; injector->mm_event.mem_event.physical_address = vmi_translate_uv2p(vmi, waitfor, pid); injector->mm_event.mem_event.npages = 1; injector->mm_event.mem_event.granularity=VMI_MEMEVENT_PAGE; injector->mm_event.mem_event.in_access = VMI_MEMACCESS_X; injector->mm_event.callback=mm_callback; injector->mm_event.data = injector; vmi_register_event(vmi, &injector->mm_event); } return; } /* Read return to userspace RIP out of the stack trap frame. */ if (PM2BIT(injector->pm) == BIT32) { vmi_get_vcpureg(vmi, &fsgs, FS_BASE, event->vcpu_id); kpcrb_offset = offsets[KPCR_PRCBDATA]; } else { vmi_get_vcpureg(vmi, &fsgs, GS_BASE, event->vcpu_id); kpcrb_offset = offsets[KPCR_PRCB]; } vmi_read_addr_va(vmi, fsgs + kpcrb_offset + offsets[KPRCB_CURRENTTHREAD], 0, &thread); vmi_read_addr_va(vmi, thread + offsets[KTHREAD_TRAPFRAME], 0, &trapframe); //printf("Trap frame @ 0x%lx\n", trapframe); if (PM2BIT(injector->pm) == BIT32) { vmi_read_addr_va(vmi, trapframe + offsets[KTRAP_FRAME_EIP], 0, &userspace_return_va); } else { vmi_read_addr_va(vmi, trapframe + offsets[KTRAP_FRAME_RIP], 0, &userspace_return_va); } injector->userspace_return = vmi_pagetable_lookup(vmi, event->reg_event.value, userspace_return_va); //printf("Userspace return @ VA 0x%lx -> PA 0x%lx\n", userspace_return_va, injector->userspace_return); uint8_t trap = 0xCC; vmi_read_8_pa(vmi, injector->userspace_return, &injector->userspace_return_backup); vmi_write_8_pa(vmi, injector->userspace_return, &trap); /*if (!injector->ss_enabled) { printf("My target process is executing, registering singlestep\n"); injector->ss_enabled = 1; memset(&injector->ss_event, 0, sizeof(vmi_event_t)); injector->ss_event.type = VMI_EVENT_SINGLESTEP; injector->ss_event.callback = ss_callback; injector->ss_event.data = injector; SET_VCPU_SINGLESTEP(injector->ss_event.ss_event, event->vcpu_id); vmi_register_event(vmi, &injector->ss_event); }*/ } } else { //printf("CR3 0x%lx is executing, not my process!\n", // event->reg_event.value); if (injector->mm_enabled) { injector->mm_enabled = 0; vmi_clear_event(vmi, &injector->mm_event); } if (injector->ss_enabled) { //printf("\tDisabling singlestep\n"); injector->ss_enabled = 0; vmi_clear_event(vmi, &injector->ss_event); } if (injector->userspace_return) { vmi_write_8_pa(vmi, injector->userspace_return, &injector->userspace_return_backup); injector->userspace_return_backup = 0; injector->userspace_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; }