/* returns a windows PE export from an RVA*/ char* windows_rva_to_export( vmi_instance_t vmi, addr_t rva, const access_context_t *ctx) { access_context_t _ctx = *ctx; struct export_table et; addr_t et_rva; size_t et_size; // get export table structure if (peparse_get_export_table(vmi, ctx, &et, &et_rva, &et_size) != VMI_SUCCESS) { dbprint(VMI_DEBUG_PEPARSE, "--PEParse: failed to get export table\n"); return NULL; } if (rva>=et_rva && rva < et_rva+et_size) { dbprint(VMI_DEBUG_PEPARSE, "--PEParse: symbol @ 0x%"PRIx64" is forwarded\n", ctx->addr+rva); return NULL; } addr_t base1 = ctx->addr + et.address_of_names; addr_t base2 = ctx->addr + et.address_of_name_ordinals; addr_t base3 = ctx->addr + et.address_of_functions; uint32_t i = 0; for (; i < et.number_of_functions; ++i) { uint32_t name_rva = 0; uint16_t ordinal = 0; uint32_t loc = 0; _ctx.addr = base2 + i * sizeof(uint16_t); if (VMI_FAILURE==vmi_read_16(vmi, &_ctx, &ordinal)) continue; _ctx.addr = base3 + ordinal * sizeof(uint32_t); if (VMI_FAILURE==vmi_read_32(vmi, &_ctx, &loc)) continue; if (loc==rva) { _ctx.addr = base1 + i * sizeof(uint32_t); if (i < et.number_of_names && VMI_SUCCESS==vmi_read_32(vmi, &_ctx, &name_rva) && name_rva) { _ctx.addr = ctx->addr + name_rva; return vmi_read_str(vmi, &_ctx); } dbprint(VMI_DEBUG_PEPARSE, "--PEParse: symbol @ 0x%"PRIx64" is exported by ordinal only\n", ctx->addr+rva); break; } } return NULL; }
// Finds the index of the exported symbol specified - linear search int get_aon_index_linear( vmi_instance_t vmi, const char *symbol, struct export_table *et, const access_context_t *ctx) { access_context_t _ctx = *ctx; uint32_t i = 0; for (; i < et->number_of_names; ++i) { _ctx.addr = ctx->addr + et->address_of_names + i * sizeof(uint32_t); uint32_t str_rva = 0; if (VMI_SUCCESS == vmi_read_32(vmi, &_ctx, &str_rva) && str_rva) { _ctx.addr = ctx->addr+str_rva; char *rva = vmi_read_str(vmi, &_ctx); if (NULL != rva) { if (strncmp(rva, symbol, strlen(rva)) == 0) { free(rva); return (int) i; } } free(rva); } } /* didn't find anything that matched */ return -1; }
void dump_exports( vmi_instance_t vmi, struct export_table *et, const access_context_t *ctx) { access_context_t _ctx = *ctx; addr_t base_addr = ctx->addr; addr_t base1 = base_addr + et->address_of_names; addr_t base2 = base_addr + et->address_of_name_ordinals; addr_t base3 = base_addr + et->address_of_functions; uint32_t i = 0; /* print names */ for (; i < et->number_of_names; ++i) { uint32_t rva = 0; uint16_t ordinal = 0; uint32_t loc = 0; char *str = NULL; _ctx.addr = base1 + i * sizeof(uint32_t); if (VMI_FAILURE == vmi_read_32(vmi, &_ctx, &rva)) continue; if (rva) { _ctx.addr = base_addr + rva; str = vmi_read_str(vmi, &_ctx); if (str) { _ctx.addr = base2 + i * sizeof(uint16_t); if (VMI_FAILURE == vmi_read_16(vmi, &_ctx, &ordinal)) { free(str); continue; } _ctx.addr = base3 + ordinal + sizeof(uint32_t); if (VMI_FAILURE == vmi_read_32(vmi, &_ctx, &loc)) { free(str); continue; } printf("%s:%d:0x%"PRIx32"\n", str, ordinal, loc); free(str); } } } }
// binary search function for get_aon_index_binary() static int find_aon_idx_bin( vmi_instance_t vmi, const char *symbol, addr_t aon_base_va, int low, int high, const access_context_t *ctx) { access_context_t _ctx = *ctx; int mid, cmp; uint32_t str_rva = 0; // RVA of curr name char *name = 0; // curr name if (high < low) goto not_found; // calc the current index ("mid") mid = (low + high) / 2; _ctx.addr = aon_base_va + mid * sizeof(uint32_t); if (VMI_FAILURE == vmi_read_32(vmi, &_ctx, &str_rva) || !str_rva) goto not_found; // get the curr string & compare to symbol _ctx.addr = ctx->addr + str_rva; name = vmi_read_str(vmi, &_ctx); if (!name) goto not_found; cmp = strcmp(symbol, name); free(name); if (cmp < 0) { // symbol < name ==> try lower region return find_aon_idx_bin(vmi, symbol, aon_base_va, low, mid - 1, ctx); } else if (cmp > 0) { // symbol > name ==> try higher region return find_aon_idx_bin(vmi, symbol, aon_base_va, mid + 1, high, ctx); } else { // symbol == name return mid; // found } not_found: return -1; }
static bool get_file_object_flags(drakvuf_t drakvuf, drakvuf_trap_info_t* info, vmi_instance_t vmi, filedelete* f, handle_t handle, uint64_t* flags) { addr_t obj = drakvuf_get_obj_by_handle(drakvuf, info->proc_data.base_addr, handle); if (!obj) return false; // Break operatioin to not crash VM addr_t file = obj + f->offsets[OBJECT_HEADER_BODY]; addr_t fileflags = file + f->offsets[FILE_OBJECT_FLAGS]; access_context_t ctx; ctx.translate_mechanism = VMI_TM_PROCESS_DTB; ctx.addr = fileflags; ctx.dtb = info->regs->cr3; uint32_t flags_value; bool success = (VMI_SUCCESS == vmi_read_32(vmi, &ctx, &flags_value)); if (success && flags) *flags = flags_value; return success; }
status_t get_export_rva( vmi_instance_t vmi, addr_t *rva, int aof_index, struct export_table *et, const access_context_t *ctx) { access_context_t _ctx = *ctx; _ctx.addr += et->address_of_functions + aof_index * sizeof(uint32_t); uint32_t tmp = 0; if (VMI_SUCCESS == vmi_read_32(vmi, &_ctx, &tmp)) { *rva = (addr_t) tmp; return VMI_SUCCESS; } return VMI_FAILURE; }
addr_t linux_get_current_process(drakvuf_t drakvuf, uint64_t vcpu_id) { addr_t process = 0; vmi_instance_t vmi = drakvuf->vmi; access_context_t ctx = { .translate_mechanism = VMI_TM_PROCESS_DTB, .dtb = drakvuf->regs[vcpu_id]->cr3, .addr = drakvuf->regs[vcpu_id]->gs_base + drakvuf->offsets[CURRENT_TASK], }; if ( VMI_FAILURE == vmi_read_addr(vmi, &ctx, &process) || process < MIN_KERNEL_BOUNDARY ) { /* * The kernel stack also has a structure called thread_info that points * to a task_struct but it doesn't seem to always agree with current_task. * However, when current_task obviously is wrong (for example during a CPUID) * we can fall back to it to find the correct process. * On most newer kernels the kernel stack size is 16K. This is just a guess * so for older kernels this may not work as well if the VA happens to map * something that resembles a kernel-address. * See https://www.cs.columbia.edu/~smb/classes/s06-4118/l06.pdf for more info. */ ctx.addr = drakvuf->kpcr[vcpu_id] & ~STACK_SIZE_16K; if ( VMI_FAILURE == vmi_read_addr(vmi, &ctx, &process) || process < MIN_KERNEL_BOUNDARY ) { ctx.addr = drakvuf->kpcr[vcpu_id] & ~STACK_SIZE_8K; if ( VMI_FAILURE == vmi_read_addr(vmi, &ctx, &process) || process < MIN_KERNEL_BOUNDARY ) process = 0; } } return process; } /* * Threads are really just processes on Linux. */ addr_t linux_get_current_thread(drakvuf_t drakvuf, uint64_t vcpu_id) { return linux_get_current_process(drakvuf, vcpu_id); } char* linux_get_process_name(drakvuf_t drakvuf, addr_t process_base) { access_context_t ctx = { .translate_mechanism = VMI_TM_PROCESS_PID, .pid = 0, .addr = process_base + drakvuf->offsets[TASK_STRUCT_COMM] }; return vmi_read_str(drakvuf->vmi, &ctx); } status_t linux_get_process_pid(drakvuf_t drakvuf, addr_t process_base, vmi_pid_t* pid ) { /* * On Linux PID is actually a thread ID, while the TGID (Thread Group-ID) is * what getpid() would return. Because THAT makes sense. */ access_context_t ctx = { .translate_mechanism = VMI_TM_PROCESS_PID, .pid = 0, .addr = process_base + drakvuf->offsets[TASK_STRUCT_TGID] }; return vmi_read_32(drakvuf->vmi, &ctx, (uint32_t*)pid); } char* linux_get_current_process_name(drakvuf_t drakvuf, uint64_t vcpu_id) { addr_t process_base = linux_get_current_process(drakvuf, vcpu_id); if ( !process_base ) return NULL; access_context_t ctx = { .translate_mechanism = VMI_TM_PROCESS_DTB, .dtb = drakvuf->regs[vcpu_id]->cr3, .addr = process_base + drakvuf->offsets[TASK_STRUCT_COMM] }; return vmi_read_str(drakvuf->vmi, &ctx); } int64_t linux_get_process_userid(drakvuf_t drakvuf, addr_t process_base) { access_context_t ctx = { .translate_mechanism = VMI_TM_PROCESS_PID, .pid = 0, .addr = process_base + drakvuf->offsets[TASK_STRUCT_CRED] }; addr_t cred; if ( VMI_FAILURE == vmi_read_addr(drakvuf->vmi, &ctx, &cred) ) return -1; uint32_t uid; ctx.addr = cred + drakvuf->offsets[CRED_UID]; if ( VMI_FAILURE == vmi_read_32(drakvuf->vmi, &ctx, &uid) ) return -1; return uid; }; int64_t linux_get_current_process_userid(drakvuf_t drakvuf, uint64_t vcpu_id) { addr_t process_base = linux_get_current_process(drakvuf, vcpu_id); if ( !process_base ) return -1; access_context_t ctx = { .translate_mechanism = VMI_TM_PROCESS_DTB, .dtb = drakvuf->regs[vcpu_id]->cr3, .addr = process_base + drakvuf->offsets[TASK_STRUCT_CRED] }; addr_t cred; if ( VMI_FAILURE == vmi_read_addr(drakvuf->vmi, &ctx, &cred) ) return -1; uint32_t uid; ctx.addr = cred + drakvuf->offsets[CRED_UID]; if ( VMI_FAILURE == vmi_read_32(drakvuf->vmi, &ctx, &uid) ) return -1; return uid; } bool linux_get_current_thread_id( drakvuf_t drakvuf, uint64_t vcpu_id, uint32_t* thread_id ) { /* * On Linux PID is actually the thread ID....... ... ... */ addr_t process_base = linux_get_current_process(drakvuf, vcpu_id); if ( !process_base ) return false; access_context_t ctx = { .translate_mechanism = VMI_TM_PROCESS_DTB, .dtb = drakvuf->regs[vcpu_id]->cr3, .addr = process_base + drakvuf->offsets[TASK_STRUCT_PID] }; uint32_t _thread_id; if ( VMI_FAILURE == vmi_read_32(drakvuf->vmi, &ctx, &_thread_id) ) return false; *thread_id = _thread_id; return true; } status_t linux_get_process_ppid( drakvuf_t drakvuf, addr_t process_base, vmi_pid_t* ppid ) { status_t ret ; addr_t parent_proc_base = 0 ; access_context_t ctx = { .translate_mechanism = VMI_TM_PROCESS_PID, .pid = 0, .addr = process_base + drakvuf->offsets[TASK_STRUCT_REALPARENT] }; ret = vmi_read_addr( drakvuf->vmi, &ctx, &parent_proc_base ); /* If we were unable to get the "proc->real_parent *" get "proc->parent *"... */ /* Assuming a parent_proc_base == 0 is a fail... */ if ( (ret == VMI_FAILURE ) || ! parent_proc_base ) { ctx.addr = process_base + drakvuf->offsets[TASK_STRUCT_PARENT]; ret = vmi_read_addr( drakvuf->vmi, &ctx, &parent_proc_base ); } /* Get pid from parent/real_parent...*/ if ( ( ret == VMI_SUCCESS ) && parent_proc_base ) { ctx.addr = parent_proc_base + drakvuf->offsets[TASK_STRUCT_TGID]; return vmi_read_32( drakvuf->vmi, &ctx, (uint32_t*)ppid ); } return VMI_FAILURE ; } bool linux_get_current_process_data( drakvuf_t drakvuf, uint64_t vcpu_id, proc_data_t* proc_data ) { proc_data->base_addr = linux_get_current_process( drakvuf, vcpu_id ); if ( proc_data->base_addr ) { if ( linux_get_process_pid( drakvuf, proc_data->base_addr, &proc_data->pid ) == VMI_SUCCESS ) { proc_data->name = linux_get_process_name( drakvuf, proc_data->base_addr ); if ( proc_data->name ) { proc_data->userid = linux_get_process_userid( drakvuf, proc_data->base_addr ); linux_get_process_ppid( drakvuf, proc_data->base_addr, &proc_data->ppid ); return true ; } } } return false ; }
static void extract_ca_file(filedelete* f, drakvuf_t drakvuf, const drakvuf_trap_info_t* info, vmi_instance_t vmi, addr_t control_area, access_context_t* ctx, const char* filename, uint64_t fo_flags) { addr_t subsection = control_area + f->control_area_size; addr_t segment = 0; addr_t test = 0; addr_t test2 = 0; size_t filesize = 0; /* Check whether subsection points back to the control area */ ctx->addr = control_area + f->offsets[CONTROL_AREA_SEGMENT]; if ( VMI_FAILURE == vmi_read_addr(vmi, ctx, &segment) ) return; ctx->addr = segment + f->offsets[SEGMENT_CONTROLAREA]; if ( VMI_FAILURE == vmi_read_addr(vmi, ctx, &test) || test != control_area ) return; ctx->addr = segment + f->offsets[SEGMENT_SIZEOFSEGMENT]; if ( VMI_FAILURE == vmi_read_64(vmi, ctx, &test) ) return; ctx->addr = segment + f->offsets[SEGMENT_TOTALNUMBEROFPTES]; if ( VMI_FAILURE == vmi_read_32(vmi, ctx, (uint32_t*)&test2) ) return; if ( test != (test2 * 4096) ) return; const int curr_sequence_number = ++f->sequence_number; char* file = NULL; if ( asprintf(&file, "%s/file.%06d.mm", f->dump_folder, curr_sequence_number) < 0 ) return; FILE* fp = fopen(file, "w"); free(file); if (!fp) return; while (subsection) { /* Check whether subsection points back to the control area */ ctx->addr = subsection + f->offsets[SUBSECTION_CONTROLAREA]; if ( VMI_FAILURE == vmi_read_addr(vmi, ctx, &test) || test != control_area ) break; addr_t base = 0; addr_t start = 0; uint32_t ptes = 0; ctx->addr = subsection + f->offsets[SUBSECTION_SUBSECTIONBASE]; if ( VMI_FAILURE == vmi_read_addr(vmi, ctx, &base) ) break; ctx->addr = subsection + f->offsets[SUBSECTION_PTESINSUBSECTION]; if ( VMI_FAILURE == vmi_read_32(vmi, ctx, &ptes) ) break; ctx->addr = subsection + f->offsets[SUBSECTION_STARTINGSECTOR]; if ( VMI_FAILURE == vmi_read_32(vmi, ctx, (uint32_t*)&start) ) break; /* * The offset into the file is stored implicitely * based on the PTE's location within the Subsection. */ addr_t subsection_offset = start * 0x200; addr_t ptecount; for (ptecount=0; ptecount < ptes; ptecount++) { addr_t pteoffset = base + f->mmpte_size * ptecount; addr_t fileoffset = subsection_offset + ptecount * 0x1000; addr_t pte = 0; ctx->addr = pteoffset; if ( VMI_FAILURE == vmi_read(vmi, ctx, f->mmpte_size, &pte, NULL) ) break; if ( ENTRY_PRESENT(1, pte) ) { uint8_t page[4096]; if ( VMI_FAILURE == vmi_read_pa(vmi, VMI_BIT_MASK(12,48) & pte, 4096, &page, NULL) ) continue; if ( !fseek ( fp, fileoffset, SEEK_SET ) ) { if ( fwrite(page, 4096, 1, fp) ) filesize = MAX(filesize, fileoffset + 4096); } } } ctx->addr = subsection + f->offsets[SUBSECTION_NEXTSUBSECTION]; if ( !vmi_read_addr(vmi, ctx, &subsection) ) break; } fclose(fp); print_extraction_information(f, drakvuf, info, filename, filesize, fo_flags, curr_sequence_number); save_file_metadata(f, info, curr_sequence_number, control_area, filename, filesize, fo_flags); }
static event_response_t cb(drakvuf_t drakvuf, drakvuf_trap_info_t* info) { poolmon* p = (poolmon*)info->trap->data; page_mode_t pm = drakvuf_get_page_mode(drakvuf); reg_t pool_type, size; char tag[5] = { [0 ... 4] = '\0' }; struct pooltag* s = NULL; const char* pool_type_str; access_context_t ctx; ctx.translate_mechanism = VMI_TM_PROCESS_DTB; ctx.dtb = info->regs->cr3; if (pm == VMI_PM_IA32E) { pool_type = info->regs->rcx; size = info->regs->rdx; *(reg_t*)tag = info->regs->r8; } else { vmi_lock_guard vmi_lg(drakvuf); vmi_instance_t& vmi = vmi_lg.vmi; ctx.addr = info->regs->rsp+12; if ( VMI_FAILURE == vmi_read_32(vmi, &ctx, (uint32_t*)tag) ) return 0; ctx.addr = info->regs->rsp+8; if ( VMI_FAILURE == vmi_read_32(vmi, &ctx, (uint32_t*)&size) ) return 0; ctx.addr = info->regs->rsp+4; if ( VMI_FAILURE == vmi_read_32(vmi, &ctx, (uint32_t*)&pool_type) ) return 0; } s = (struct pooltag*)g_tree_lookup(p->pooltag_tree, tag); pool_type_str = pool_type<MaxPoolType ? pool_types[pool_type] : "unknown_pool_type"; switch (p->format) { case OUTPUT_CSV: printf("poolmon," FORMAT_TIMEVAL ",%" PRIu32 ",0x%" PRIx64 ",\"%s\",%" PRIi64 ",%s,%s,%" PRIu64 "", UNPACK_TIMEVAL(info->timestamp), info->vcpu, info->regs->cr3, info->proc_data.name, info->proc_data.userid, tag, pool_type_str, size); if (s) printf(",%s,%s", s->source, s->description); break; case OUTPUT_KV: printf("poolmon Time=" FORMAT_TIMEVAL ",PID=%d,PPID=%d,ProcessName=\"%s\"," "Tag=%s,Type=%s,Size=%" PRIu64, UNPACK_TIMEVAL(info->timestamp), info->proc_data.pid, info->proc_data.ppid, info->proc_data.name, tag, pool_type_str, size); if (s) printf(",Source=%s,Description=%s", s->source, s->description); break; default: case OUTPUT_DEFAULT: printf("[POOLMON] TIME:" FORMAT_TIMEVAL " VCPU:%" PRIu32 " CR3:0x%" PRIx64 ",\"%s\" %s:%" PRIi64 " %s (type: %s, size: %" PRIu64 ")", UNPACK_TIMEVAL(info->timestamp), info->vcpu, info->regs->cr3, info->proc_data.name, USERIDSTR(drakvuf), info->proc_data.userid, tag, pool_type_str, size); if (s) printf(": %s,%s", s->source, s->description); break; } printf("\n"); return 0; }
static status_t init_task_kaslr_test(vmi_instance_t vmi, addr_t page_vaddr) { status_t ret = VMI_FAILURE; uint32_t pid; addr_t init_task = page_vaddr + (vmi->init_task & VMI_BIT_MASK(0,11)); linux_instance_t linux_instance = vmi->os_data; access_context_t ctx = { .translate_mechanism = VMI_TM_PROCESS_DTB, .dtb = vmi->kpgd }; ctx.addr = init_task + linux_instance->pid_offset; if ( VMI_FAILURE == vmi_read_32(vmi, &ctx, &pid) ) return ret; if ( pid ) return ret; ctx.addr = init_task + linux_instance->name_offset; char* init_task_name = vmi_read_str(vmi, &ctx); if ( init_task_name && !strncmp("swapper", init_task_name, 7) ) ret = VMI_SUCCESS; free(init_task_name); return ret; } status_t init_kaslr(vmi_instance_t vmi) { /* * Let's check if we can translate init_task first as is. */ uint32_t test; access_context_t ctx = { .translate_mechanism = VMI_TM_PROCESS_DTB, .dtb = vmi->kpgd, .addr = vmi->init_task }; if ( VMI_SUCCESS == vmi_read_32(vmi, &ctx, &test) ) return VMI_SUCCESS; status_t ret = VMI_FAILURE; linux_instance_t linux_instance = vmi->os_data; GSList *loop, *pages = vmi_get_va_pages(vmi, vmi->kpgd); loop = pages; while (loop) { page_info_t *info = loop->data; if ( !linux_instance->kaslr_offset ) { switch(vmi->page_mode) { case VMI_PM_AARCH64: case VMI_PM_IA32E: if ( VMI_GET_BIT(info->vaddr, 47) ) ret = init_task_kaslr_test(vmi, info->vaddr); break; default: ret = init_task_kaslr_test(vmi, info->vaddr); break; }; if ( VMI_SUCCESS == ret ) { linux_instance->kaslr_offset = info->vaddr - (vmi->init_task & ~VMI_BIT_MASK(0,11)); vmi->init_task += linux_instance->kaslr_offset; dbprint(VMI_DEBUG_MISC, "**calculated KASLR offset: 0x%"PRIx64"\n", linux_instance->kaslr_offset); } } g_free(info); loop = loop->next; } g_slist_free(pages); return ret; } status_t linux_init(vmi_instance_t vmi) { status_t rc; os_interface_t os_interface = NULL; if (vmi->config == NULL) { errprint("No config table found\n"); return VMI_FAILURE; } if (vmi->os_data != NULL) { errprint("os data already initialized, reinitializing\n"); free(vmi->os_data); } vmi->os_data = safe_malloc(sizeof(struct linux_instance)); bzero(vmi->os_data, sizeof(struct linux_instance)); linux_instance_t linux_instance = vmi->os_data; g_hash_table_foreach(vmi->config, (GHFunc)linux_read_config_ghashtable_entries, vmi); if(linux_instance->rekall_profile) rc = init_from_rekall_profile(vmi); else rc = linux_symbol_to_address(vmi, "init_task", NULL, &vmi->init_task); if (VMI_FAILURE == rc) { errprint("Could not get init_task from Rekall profile or System.map\n"); goto _exit; } vmi->init_task = canonical_addr(vmi->init_task); #if defined(ARM32) || defined(ARM64) rc = driver_get_vcpureg(vmi, &vmi->kpgd, TTBR1, 0); #elif defined(I386) || defined(X86_64) rc = driver_get_vcpureg(vmi, &vmi->kpgd, CR3, 0); #endif /* * The driver failed to get us a pagetable. * As a fall-back, try to init using heuristics. * This path is taken in FILE mode as well. */ if (VMI_FAILURE == rc) if (VMI_FAILURE == linux_filemode_init(vmi)) goto _exit; if ( VMI_FAILURE == init_kaslr(vmi) ) { dbprint(VMI_DEBUG_MISC, "**failed to determine KASLR offset\n"); goto _exit; } dbprint(VMI_DEBUG_MISC, "**set vmi->kpgd (0x%.16"PRIx64").\n", vmi->kpgd); os_interface = safe_malloc(sizeof(struct os_interface)); bzero(os_interface, sizeof(struct os_interface)); os_interface->os_get_offset = linux_get_offset; os_interface->os_pid_to_pgd = linux_pid_to_pgd; os_interface->os_pgd_to_pid = linux_pgd_to_pid; os_interface->os_ksym2v = linux_symbol_to_address; os_interface->os_usym2rva = NULL; os_interface->os_v2sym = linux_system_map_address_to_symbol; os_interface->os_read_unicode_struct = NULL; os_interface->os_teardown = linux_teardown; vmi->os_interface = os_interface; return VMI_SUCCESS; _exit: free(vmi->os_data); vmi->os_data = NULL; return VMI_FAILURE; }
static event_response_t hook_cb(drakvuf_t drakvuf, drakvuf_trap_info_t* info) { bsodmon* f = static_cast<bsodmon*>(info->trap->data); vmi_instance_t vmi = drakvuf_lock_and_get_vmi(drakvuf); access_context_t ctx; ctx.translate_mechanism = VMI_TM_PROCESS_DTB; ctx.dtb = info->regs->cr3; uint64_t code = 0; uint64_t params[4] = { 0 }; const char* bugcheck_name = "UNKNOWN_CODE" ; gchar* escaped_pname = NULL; bool is32bit = drakvuf_get_page_mode(drakvuf) != VMI_PM_IA32E; if (is32bit) { ctx.addr = info->regs->rsp + 4; if ( VMI_FAILURE == vmi_read_32(vmi, &ctx, (uint32_t*)&code) ) goto done; ctx.addr = info->regs->rsp + 8; if ( VMI_FAILURE == vmi_read_32(vmi, &ctx, (uint32_t*)¶ms[0]) ) goto done; ctx.addr = info->regs->rsp + 0xc; if ( VMI_FAILURE == vmi_read_32(vmi, &ctx, (uint32_t*)¶ms[1]) ) goto done; ctx.addr = info->regs->rsp + 0x10; if ( VMI_FAILURE == vmi_read_32(vmi, &ctx, (uint32_t*)¶ms[2]) ) goto done; ctx.addr = info->regs->rsp + 0x14; if ( VMI_FAILURE == vmi_read_32(vmi, &ctx, (uint32_t*)¶ms[3]) ) goto done; } else { code = info->regs->rcx; params[0] = info->regs->rdx; params[1] = info->regs->r8; params[2] = info->regs->r9; ctx.addr = info->regs->rsp + 0x20; if ( VMI_FAILURE == vmi_read_32(vmi, &ctx, (uint32_t*)¶ms[3]) ) goto done; } if ( f->bugcheck_map.find( code ) != f->bugcheck_map.end() ) bugcheck_name = f->bugcheck_map[ code ]; switch (f->format) { case OUTPUT_CSV: printf("bsodmon," FORMAT_TIMEVAL ",%" PRIu32 ",0x%" PRIx64 ",\"%s\",%" PRIi64 ",%" PRIx64 ",\"%s\",%" PRIx64 ",%" PRIx64 ",%" PRIx64 ",%" PRIx64 "\n", UNPACK_TIMEVAL(info->timestamp), info->vcpu, info->regs->cr3, info->proc_data.name, info->proc_data.userid, code, bugcheck_name, params[0], params[1], params[2], params[3]); break; case OUTPUT_KV: printf("bsodmon Time=" FORMAT_TIMEVAL ",PID=%d,PPID=%d,ProcessName=\"%s\",BugCheckCode=%" PRIx64 ",BugCheckName=\"%s\",BugCheckParameter1=%" PRIx64 ",BugCheckParameter2=%" PRIx64 ",BugCheckParameter2=%" PRIx64 ",BugCheckParameter4=%" PRIx64 "\n", UNPACK_TIMEVAL(info->timestamp), info->proc_data.pid, info->proc_data.ppid, info->proc_data.name, code, bugcheck_name, params[0], params[1], params[2], params[3]); break; case OUTPUT_JSON: escaped_pname = drakvuf_escape_str(info->proc_data.name); printf( "{" "\"Plugin\" : \"bsodmon\"," "\"TimeStamp\" :" "\"" FORMAT_TIMEVAL "\"," "\"VCPU\": %" PRIu32 "," "\"CR3\": %" PRIu64 "," "\"ProcessName\": %s," "\"UserId\": %" PRIu64 "," "\"PID\" : %d," "\"PPID\": %d," "\"BugCheckCode\": %" PRIu64 "," "\"BugCheckName\": \"%s\"," "\"BugCheckParameter1\": %" PRIu64 "," "\"BugCheckParameter2\": %" PRIu64 "," "\"BugCheckParameter3\": %" PRIu64 "," "\"BugCheckParameter4\": %" PRIu64 "}\n", UNPACK_TIMEVAL(info->timestamp), info->vcpu, info->regs->cr3, escaped_pname, info->proc_data.userid, info->proc_data.pid, info->proc_data.ppid, code, bugcheck_name, params[0], params[1], params[2], params[3]); g_free(escaped_pname); break; default: case OUTPUT_DEFAULT: printf("[BSODMON] TIME:" FORMAT_TIMEVAL " VCPU:%" PRIu32 " CR3:0x%" PRIx64 ",\"%s\" %s:%" PRIi64 " BugCheckCode:%" PRIx64 " BugCheckName:%s BugCheckParameter1:%" PRIx64 " BugCheckParameter2:%" PRIx64 " BugCheckParameter3:%" PRIx64 " BugCheckParameter4:%" PRIx64 "\n", UNPACK_TIMEVAL(info->timestamp), info->vcpu, info->regs->cr3, info->proc_data.name, USERIDSTR(drakvuf), info->proc_data.userid, code, bugcheck_name, params[0], params[1], params[2], params[3]); break; } done: drakvuf_release_vmi(drakvuf); if ( f->abort_on_bsod ) drakvuf_interrupt( drakvuf, SIGDRAKVUFERROR); return 0; }