Exemple #1
0
filedelete::filedelete(drakvuf_t drakvuf, const filedelete_config* c, output_format_t output)
    : sequence_number()
{
    this->pm = drakvuf_get_page_mode(drakvuf);

    vmi_instance_t vmi = drakvuf_lock_and_get_vmi(drakvuf);
    this->domid = vmi_get_vmid(vmi);
    drakvuf_release_vmi(drakvuf);

    this->dump_folder = c->dump_folder;
    this->format = output;
    this->use_injector = c->filedelete_use_injector;

    if (!this->use_injector)
    {
        assert(sizeof(traps)/sizeof(traps[0]) > 2);
        register_trap(drakvuf, "NtSetInformationFile", &traps[0], setinformation_cb);
        register_trap(drakvuf, "NtWriteFile",          &traps[1], writefile_cb);
        register_trap(drakvuf, "NtClose",              &traps[2], close_cb);
        /* TODO
        register_trap(drakvuf, "NtDeleteFile",            &traps[3], deletefile_cb);
        register_trap(drakvuf, "ZwDeleteFile",            &traps[4], deletefile_cb); */
    }
    else
    {
        this->queryobject_va = get_function_va(drakvuf, "ntoskrnl.exe", "ZwQueryVolumeInformationFile");
        this->readfile_va = get_function_va(drakvuf, "ntoskrnl.exe", "ZwReadFile");
        this->waitobject_va = get_function_va(drakvuf, "ntoskrnl.exe", "ZwWaitForSingleObject");
        this->exallocatepool_va = get_function_va(drakvuf, "ntoskrnl.exe", "ExAllocatePoolWithTag");
        this->exfreepool_va = get_function_va(drakvuf, "ntoskrnl.exe", "ExFreePoolWithTag");

        assert(sizeof(traps)/sizeof(traps[0]) > 3);
        register_trap(drakvuf, "NtSetInformationFile", &traps[0], setinformation_cb);
        register_trap(drakvuf, "NtWriteFile",          &traps[1], writefile_cb);
        register_trap(drakvuf, "NtClose",              &traps[2], close_cb);
        register_trap(drakvuf, "ZwCreateSection",      &traps[3], createsection_cb);
    }

    this->offsets = (size_t*)malloc(sizeof(size_t)*__OFFSET_MAX);

    if ( !drakvuf_get_struct_members_array_rva(drakvuf, offset_names, __OFFSET_MAX, this->offsets) )
        throw -1;

    if ( !drakvuf_get_struct_size(drakvuf, "_CONTROL_AREA", &this->control_area_size) )
        throw -1;

    if ( VMI_PM_LEGACY == this->pm )
        this->mmpte_size = 4;
    else
        this->mmpte_size = 8;
}
Exemple #2
0
static addr_t place_string_on_stack_32(vmi_instance_t vmi, drakvuf_trap_info_t* info, addr_t addr, void const* str, size_t str_len)
{
    if (!str) return 0;

    const uint32_t string_align = 64;
    const size_t len = str_len + 2;// null terminated string

    // the stack has to be aligned _not_ to 0x4 but to 64
    // for special instructions operating on strings to work correctly
    // this string has to be aligned as well!
    addr -= len + string_align - (len % string_align);

    access_context_t ctx =
    {
        .translate_mechanism = VMI_TM_PROCESS_DTB,
        .dtb = info->regs->cr3,
        .addr = addr,
    };

    if (VMI_FAILURE == vmi_write(vmi, &ctx, len, (void*) str, NULL))
        return 0;

    return addr;
}

static addr_t place_string_on_stack_64(vmi_instance_t vmi, drakvuf_trap_info_t* info, addr_t addr, void const* str, size_t str_len)
{
    if (!str) return addr;
    // String length with null terminator
    size_t len = str_len + 2;
    addr_t orig_addr = addr;

    addr -= len;
    // Align string address on 32B boundary (for SSE2 instructions).
    addr &= ~0x1f;

    size_t buf_len = orig_addr - addr;
    void* buf = g_malloc0(buf_len);
    if (!buf) return 0;
    memcpy(buf, str, str_len);

    access_context_t ctx =
    {
        .translate_mechanism = VMI_TM_PROCESS_DTB,
        .dtb = info->regs->cr3,
        .addr = addr,
    };

    status_t status = vmi_write(vmi, &ctx, buf_len, buf, NULL);
    g_free(buf);

    return status == VMI_FAILURE ? 0 : addr;
}

static addr_t place_struct_on_stack_32(vmi_instance_t vmi, drakvuf_trap_info_t* info, addr_t addr, void* data, size_t size)
{
    const uint32_t stack_align = 64;

    addr -= size;
    addr -= addr % stack_align;

    access_context_t ctx =
    {
        .translate_mechanism = VMI_TM_PROCESS_DTB,
        .dtb = info->regs->cr3,
        .addr = addr,
    };

    status_t status = vmi_write(vmi, &ctx, size, data, NULL);

    return status == VMI_FAILURE ? 0 : addr;
}

static addr_t place_struct_on_stack_64(vmi_instance_t vmi, drakvuf_trap_info_t* info, addr_t addr, void* data, size_t size)
{
    /* According to Microsoft Doc "Building C/C++ Programs":
     * > The alignment of the beginning of a structure or a union is the maximum
     * > alignment of any individual member.
     */
    addr -= size;
    addr &= ~0xf; // Align stack

    access_context_t ctx =
    {
        .translate_mechanism = VMI_TM_PROCESS_DTB,
        .dtb = info->regs->cr3,
        .addr = addr,
    };

    status_t status = vmi_write(vmi, &ctx, size, data, NULL);

    return status == VMI_FAILURE ? 0 : addr;
}

static bool setup_stack_32(vmi_instance_t vmi, drakvuf_trap_info_t* info, struct argument args[], int nb_args)
{
    addr_t addr = info->regs->rsp;

    // make room for strings and structs into guest's stack
    for (int i = 0; i < nb_args; i++)
    {
        switch (args[i].type)
        {
            case ARGUMENT_STRING:
                addr = place_string_on_stack_32(vmi, info, addr, args[i].data, args[i].size);
                if ( !addr ) goto err;
                args[i].data_on_stack = addr;
                break;
            case ARGUMENT_STRUCT:
                addr = place_struct_on_stack_32(vmi, info, addr, args[i].data, args[i].size);
                if ( !addr ) goto err;
                args[i].data_on_stack = addr;
                break;
            case ARGUMENT_INT:
                args[i].data_on_stack = (uint64_t)args[i].data;
                break;
            default:
                goto err;
        }
    }

    access_context_t ctx =
    {
        .translate_mechanism = VMI_TM_PROCESS_DTB,
        .dtb = info->regs->cr3,
    };

    // write parameters into guest's stack
    for (int i = nb_args-1; i >= 0; i--)
    {
        addr -= 0x4;
        ctx.addr = addr;
        if (VMI_FAILURE == vmi_write_32(vmi, &ctx, (uint32_t*)&args[i].data_on_stack))
            goto err;
    }

    // save the return address
    addr -= 0x4;
    ctx.addr = addr;
    if (VMI_FAILURE == vmi_write_32(vmi, &ctx, (uint32_t*) &info->regs->rip))
        goto err;

    // grow the stack
    info->regs->rsp = addr;

    return 1;

err:
    return 0;
}

static bool setup_stack_64(vmi_instance_t vmi, drakvuf_trap_info_t* info, struct argument args[], int nb_args)
{
    uint64_t nul64 = 0;

    access_context_t ctx =
    {
        .translate_mechanism = VMI_TM_PROCESS_DTB,
        .dtb = info->regs->cr3,
    };

    addr_t addr = info->regs->rsp;

    if ( args )
    {
        // make room for strings and structs into guest's stack
        for (int i = 0; i < nb_args; i++)
        {
            switch (args[i].type)
            {
                case ARGUMENT_STRING:
                    addr = place_string_on_stack_64(vmi, info, addr, args[i].data, args[i].size);
                    if ( !addr ) goto err;
                    args[i].data_on_stack = addr;
                    break;
                case ARGUMENT_STRUCT:
                    addr = place_struct_on_stack_64(vmi, info, addr, args[i].data, args[i].size);
                    if ( !addr ) goto err;
                    args[i].data_on_stack = addr;
                    break;
                case ARGUMENT_INT:
                    args[i].data_on_stack = (uint64_t)args[i].data;
                    break;
                default:
                    goto err;
            }
        }

        /* According to Microsoft Doc "Building C/C++ Programs":
         * > The stack will always be maintained 16-byte aligned, except within the prolog
         * > (for example, after the return address is pushed), and except where indicated
         * > in Function Types for a certain class of frame functions.
         *
         * So place one extra argument to achieve alignment just before CALL instruction.
         */
        if (nb_args % 2)
        {
            addr -= 0x8;
            ctx.addr = addr;
            if (VMI_FAILURE == vmi_write_64(vmi, &ctx, &nul64))
                goto err;
        }

        // http://www.codemachine.com/presentations/GES2010.TRoy.Slides.pdf
        //
        // First 4 parameters to functions are always passed in registers
        // P1=rcx, P2=rdx, P3=r8, P4=r9
        // 5th parameter onwards (if any) passed via the stack

        // write parameters (5th onwards) into guest's stack
        for (int i = nb_args-1; i > 3; i--)
        {
            addr -= 0x8;
            ctx.addr = addr;
            if (VMI_FAILURE == vmi_write_64(vmi, &ctx, &(args[i].data_on_stack)) )
                goto err;
        }

        switch (nb_args)
        {
            default:
                // p4
                info->regs->r9 = args[3].data_on_stack;
            // fall through
            case 3:
                // p3
                info->regs->r8 = args[2].data_on_stack;
            // fall through
            case 2:
                // p2
                info->regs->rdx = args[1].data_on_stack;
            // fall through
            case 1:
                // p1
                info->regs->rcx = args[0].data_on_stack;
            // fall through
            case 0:
                break;
        }
    }

    // allocate 0x20 "homing space"
    for (int i = 0; i < 4; i++)
    {
        addr -= 0x8;
        ctx.addr = addr;
        if (VMI_FAILURE == vmi_write_64(vmi, &ctx, &nul64))
            goto err;
    }

    // save the return address
    addr -= 0x8;
    ctx.addr = addr;
    if (VMI_FAILURE == vmi_write_64(vmi, &ctx, &info->regs->rip))
        goto err;

    // grow the stack
    info->regs->rsp = addr;

    return 1;

err:
    return 0;
}

bool setup_stack_locked(
    drakvuf_t drakvuf,
    vmi_instance_t vmi,
    drakvuf_trap_info_t* info,
    struct argument args[],
    int nb_args)
{
    bool is32bit = (drakvuf_get_page_mode(drakvuf) != VMI_PM_IA32E);
    return is32bit ? setup_stack_32(vmi, info, args, nb_args) : setup_stack_64(vmi, info, args, nb_args);
}

bool setup_stack(
    drakvuf_t drakvuf,
    drakvuf_trap_info_t* info,
    struct argument args[],
    int nb_args)
{
    vmi_instance_t vmi = drakvuf_lock_and_get_vmi(drakvuf);
    bool success = setup_stack_locked(drakvuf, vmi, info, args, nb_args);
    drakvuf_release_vmi(drakvuf);
    return success;
}
Exemple #3
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;
}
Exemple #4
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;
}