示例#1
0
文件: peparse.c 项目: bentau/libvmi
/* 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;
}
示例#2
0
文件: peparse.c 项目: bentau/libvmi
// 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;
}
示例#3
0
文件: peparse.c 项目: bentau/libvmi
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);
            }
        }
    }
}
示例#4
0
文件: peparse.c 项目: bentau/libvmi
// 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;
}
示例#5
0
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;
}
示例#6
0
文件: peparse.c 项目: bentau/libvmi
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;
}
示例#7
0
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 ;
}
示例#8
0
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);
}
示例#9
0
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;
}
示例#10
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;
}
示例#11
0
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*)&params[0]) )
            goto done;

        ctx.addr = info->regs->rsp + 0xc;
        if ( VMI_FAILURE == vmi_read_32(vmi, &ctx, (uint32_t*)&params[1]) )
            goto done;

        ctx.addr = info->regs->rsp + 0x10;
        if ( VMI_FAILURE == vmi_read_32(vmi, &ctx, (uint32_t*)&params[2]) )
            goto done;

        ctx.addr = info->regs->rsp + 0x14;
        if ( VMI_FAILURE == vmi_read_32(vmi, &ctx, (uint32_t*)&params[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*)&params[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;
}