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); }
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 carve_file_from_memory(drakvuf_t *drakvuf, addr_t ph_base, addr_t block_size) { addr_t aligned_file_size = struct_sizes[FILE_OBJECT]; if(PM2BIT(drakvuf->pm) == BIT32) { // 8-byte alignment on 32-bit mode if(struct_sizes[FILE_OBJECT] % 8) { aligned_file_size += 8 - (struct_sizes[FILE_OBJECT] % 8); } } else { // 16-byte alignment on 64-bit mode if(struct_sizes[FILE_OBJECT] % 16) { aligned_file_size += 16 - (struct_sizes[FILE_OBJECT] % 16); } } addr_t file_base = ph_base + block_size - aligned_file_size; addr_t file_name = file_base + offsets[FILE_OBJECT_FILENAME]; addr_t file_name_str = 0; uint16_t length = 0; vmi_read_addr_pa(drakvuf->vmi, file_name + offsets[UNICODE_STRING_BUFFER], &file_name_str); vmi_read_16_pa(drakvuf->vmi, file_name + offsets[UNICODE_STRING_LENGTH], &length); if (file_name_str && length) { unicode_string_t str = { .contents = NULL }; str.length = length; str.encoding = "UTF-16"; str.contents = malloc(length); vmi_read_va(drakvuf->vmi, file_name, 0, str.contents, length); unicode_string_t str2 = { .contents = NULL }; status_t rc = vmi_convert_str_encoding(&str, &str2, "UTF-8"); if (VMI_SUCCESS == rc) { PRINT_DEBUG("\tFile closing: %s.\n", str2.contents); volatility_extract_file(drakvuf, file_base); g_free(str2.contents); } free(str.contents); }
void volatility_extract_file(drakvuf_t *drakvuf, addr_t file_object) { char* profile = NULL; if (PM2BIT(drakvuf->pm) == BIT32) { profile = PROFILE32; } else { profile = PROFILE64; } char *command = g_malloc0( snprintf(NULL, 0, VOL_DUMPFILES, PYTHON, VOLATILITY, drakvuf->domID, profile, file_object, (drakvuf->dump_folder ? drakvuf->dump_folder : "/tmp") ) + 1); sprintf(command, VOL_DUMPFILES, PYTHON, VOLATILITY, drakvuf->domID, profile, file_object, (drakvuf->dump_folder ? drakvuf->dump_folder : "/tmp")); PRINT_DEBUG("** RUNNING COMMAND: %s\n", command); g_spawn_command_line_sync(command, NULL, NULL, NULL, NULL); free(command); }
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; } } }