qemu/contrib/elf2dmp/main.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2018 Virtuozzo International GmbH
   3 *
   4 * This work is licensed under the terms of the GNU GPL, version 2 or later.
   5 *
   6 */
   7
   8#include <inttypes.h>
   9
  10#include "qemu/osdep.h"
  11#include "err.h"
  12#include "addrspace.h"
  13#include "pe.h"
  14#include "pdb.h"
  15#include "kdbg.h"
  16#include "download.h"
  17#include "qemu/win_dump_defs.h"
  18
  19#define SYM_URL_BASE    "https://msdl.microsoft.com/download/symbols/"
  20#define PDB_NAME    "ntkrnlmp.pdb"
  21
  22#define INITIAL_MXCSR   0x1f80
  23
  24typedef struct idt_desc {
  25    uint16_t offset1;   /* offset bits 0..15 */
  26    uint16_t selector;
  27    uint8_t ist;
  28    uint8_t type_attr;
  29    uint16_t offset2;   /* offset bits 16..31 */
  30    uint32_t offset3;   /* offset bits 32..63 */
  31    uint32_t rsrvd;
  32} __attribute__ ((packed)) idt_desc_t;
  33
  34static uint64_t idt_desc_addr(idt_desc_t desc)
  35{
  36    return (uint64_t)desc.offset1 | ((uint64_t)desc.offset2 << 16) |
  37          ((uint64_t)desc.offset3 << 32);
  38}
  39
  40static const uint64_t SharedUserData = 0xfffff78000000000;
  41
  42#define KUSD_OFFSET_SUITE_MASK 0x2d0
  43#define KUSD_OFFSET_PRODUCT_TYPE 0x264
  44
  45#define SYM_RESOLVE(base, r, s) ((s = pdb_resolve(base, r, #s)),\
  46    s ? printf(#s" = 0x%016"PRIx64"\n", s) :\
  47    eprintf("Failed to resolve "#s"\n"), s)
  48
  49static uint64_t rol(uint64_t x, uint64_t y)
  50{
  51    return (x << y) | (x >> (64 - y));
  52}
  53
  54/*
  55 * Decoding algorithm can be found in Volatility project
  56 */
  57static void kdbg_decode(uint64_t *dst, uint64_t *src, size_t size,
  58        uint64_t kwn, uint64_t kwa, uint64_t kdbe)
  59{
  60    size_t i;
  61    assert(size % sizeof(uint64_t) == 0);
  62    for (i = 0; i < size / sizeof(uint64_t); i++) {
  63        uint64_t block;
  64
  65        block = src[i];
  66        block = rol(block ^ kwn, (uint8_t)kwn);
  67        block = __builtin_bswap64(block ^ kdbe) ^ kwa;
  68        dst[i] = block;
  69    }
  70}
  71
  72static KDDEBUGGER_DATA64 *get_kdbg(uint64_t KernBase, struct pdb_reader *pdb,
  73        struct va_space *vs, uint64_t KdDebuggerDataBlock)
  74{
  75    const char OwnerTag[4] = "KDBG";
  76    KDDEBUGGER_DATA64 *kdbg = NULL;
  77    DBGKD_DEBUG_DATA_HEADER64 kdbg_hdr;
  78    bool decode = false;
  79    uint64_t kwn, kwa, KdpDataBlockEncoded;
  80
  81    if (va_space_rw(vs,
  82                KdDebuggerDataBlock + offsetof(KDDEBUGGER_DATA64, Header),
  83                &kdbg_hdr, sizeof(kdbg_hdr), 0)) {
  84        eprintf("Failed to extract KDBG header\n");
  85        return NULL;
  86    }
  87
  88    if (memcmp(&kdbg_hdr.OwnerTag, OwnerTag, sizeof(OwnerTag))) {
  89        uint64_t KiWaitNever, KiWaitAlways;
  90
  91        decode = true;
  92
  93        if (!SYM_RESOLVE(KernBase, pdb, KiWaitNever) ||
  94                !SYM_RESOLVE(KernBase, pdb, KiWaitAlways) ||
  95                !SYM_RESOLVE(KernBase, pdb, KdpDataBlockEncoded)) {
  96            return NULL;
  97        }
  98
  99        if (va_space_rw(vs, KiWaitNever, &kwn, sizeof(kwn), 0) ||
 100                va_space_rw(vs, KiWaitAlways, &kwa, sizeof(kwa), 0)) {
 101            return NULL;
 102        }
 103
 104        printf("[KiWaitNever] = 0x%016"PRIx64"\n", kwn);
 105        printf("[KiWaitAlways] = 0x%016"PRIx64"\n", kwa);
 106
 107        /*
 108         * If KDBG header can be decoded, KDBG size is available
 109         * and entire KDBG can be decoded.
 110         */
 111        printf("Decoding KDBG header...\n");
 112        kdbg_decode((uint64_t *)&kdbg_hdr, (uint64_t *)&kdbg_hdr,
 113                sizeof(kdbg_hdr), kwn, kwa, KdpDataBlockEncoded);
 114
 115        printf("Owner tag is \'%.4s\'\n", (char *)&kdbg_hdr.OwnerTag);
 116        if (memcmp(&kdbg_hdr.OwnerTag, OwnerTag, sizeof(OwnerTag))) {
 117            eprintf("Failed to decode KDBG header\n");
 118            return NULL;
 119        }
 120    }
 121
 122    kdbg = malloc(kdbg_hdr.Size);
 123    if (!kdbg) {
 124        return NULL;
 125    }
 126
 127    if (va_space_rw(vs, KdDebuggerDataBlock, kdbg, kdbg_hdr.Size, 0)) {
 128        eprintf("Failed to extract entire KDBG\n");
 129        return NULL;
 130    }
 131
 132    if (!decode) {
 133        return kdbg;
 134    }
 135
 136    printf("Decoding KdDebuggerDataBlock...\n");
 137    kdbg_decode((uint64_t *)kdbg, (uint64_t *)kdbg, kdbg_hdr.Size,
 138                kwn, kwa, KdpDataBlockEncoded);
 139
 140    va_space_rw(vs, KdDebuggerDataBlock, kdbg, kdbg_hdr.Size, 1);
 141
 142    return kdbg;
 143}
 144
 145static void win_context_init_from_qemu_cpu_state(WinContext *ctx,
 146        QEMUCPUState *s)
 147{
 148    WinContext win_ctx = (WinContext){
 149        .ContextFlags = WIN_CTX_X64 | WIN_CTX_INT | WIN_CTX_SEG | WIN_CTX_CTL,
 150        .MxCsr = INITIAL_MXCSR,
 151
 152        .SegCs = s->cs.selector,
 153        .SegSs = s->ss.selector,
 154        .SegDs = s->ds.selector,
 155        .SegEs = s->es.selector,
 156        .SegFs = s->fs.selector,
 157        .SegGs = s->gs.selector,
 158        .EFlags = (uint32_t)s->rflags,
 159
 160        .Rax = s->rax,
 161        .Rbx = s->rbx,
 162        .Rcx = s->rcx,
 163        .Rdx = s->rdx,
 164        .Rsp = s->rsp,
 165        .Rbp = s->rbp,
 166        .Rsi = s->rsi,
 167        .Rdi = s->rdi,
 168        .R8  = s->r8,
 169        .R9  = s->r9,
 170        .R10 = s->r10,
 171        .R11 = s->r11,
 172        .R12 = s->r12,
 173        .R13 = s->r13,
 174        .R14 = s->r14,
 175        .R15 = s->r15,
 176
 177        .Rip = s->rip,
 178        .FltSave = {
 179            .MxCsr = INITIAL_MXCSR,
 180        },
 181    };
 182
 183    *ctx = win_ctx;
 184}
 185
 186/*
 187 * Finds paging-structure hierarchy base,
 188 * if previously set doesn't give access to kernel structures
 189 */
 190static int fix_dtb(struct va_space *vs, QEMU_Elf *qe)
 191{
 192    /*
 193     * Firstly, test previously set DTB.
 194     */
 195    if (va_space_resolve(vs, SharedUserData)) {
 196        return 0;
 197    }
 198
 199    /*
 200     * Secondly, find CPU which run system task.
 201     */
 202    size_t i;
 203    for (i = 0; i < qe->state_nr; i++) {
 204        QEMUCPUState *s = qe->state[i];
 205
 206        if (is_system(s)) {
 207            va_space_set_dtb(vs, s->cr[3]);
 208            printf("DTB 0x%016"PRIx64" has been found from CPU #%zu"
 209                    " as system task CR3\n", vs->dtb, i);
 210            return !(va_space_resolve(vs, SharedUserData));
 211        }
 212    }
 213
 214    /*
 215     * Thirdly, use KERNEL_GS_BASE from CPU #0 as PRCB address and
 216     * CR3 as [Prcb+0x7000]
 217     */
 218    if (qe->has_kernel_gs_base) {
 219        QEMUCPUState *s = qe->state[0];
 220        uint64_t Prcb = s->kernel_gs_base;
 221        uint64_t *cr3 = va_space_resolve(vs, Prcb + 0x7000);
 222
 223        if (!cr3) {
 224            return 1;
 225        }
 226
 227        va_space_set_dtb(vs, *cr3);
 228        printf("DirectoryTableBase = 0x%016"PRIx64" has been found from CPU #0"
 229                " as interrupt handling CR3\n", vs->dtb);
 230        return !(va_space_resolve(vs, SharedUserData));
 231    }
 232
 233    return 1;
 234}
 235
 236static int fill_header(WinDumpHeader64 *hdr, struct pa_space *ps,
 237        struct va_space *vs, uint64_t KdDebuggerDataBlock,
 238        KDDEBUGGER_DATA64 *kdbg, uint64_t KdVersionBlock, int nr_cpus)
 239{
 240    uint32_t *suite_mask = va_space_resolve(vs, SharedUserData +
 241            KUSD_OFFSET_SUITE_MASK);
 242    int32_t *product_type = va_space_resolve(vs, SharedUserData +
 243            KUSD_OFFSET_PRODUCT_TYPE);
 244    DBGKD_GET_VERSION64 kvb;
 245    WinDumpHeader64 h;
 246    size_t i;
 247
 248    QEMU_BUILD_BUG_ON(KUSD_OFFSET_SUITE_MASK >= PAGE_SIZE);
 249    QEMU_BUILD_BUG_ON(KUSD_OFFSET_PRODUCT_TYPE >= PAGE_SIZE);
 250
 251    if (!suite_mask || !product_type) {
 252        return 1;
 253    }
 254
 255    if (va_space_rw(vs, KdVersionBlock, &kvb, sizeof(kvb), 0)) {
 256        eprintf("Failed to extract KdVersionBlock\n");
 257        return 1;
 258    }
 259
 260    h = (WinDumpHeader64) {
 261        .Signature = "PAGE",
 262        .ValidDump = "DU64",
 263        .MajorVersion = kvb.MajorVersion,
 264        .MinorVersion = kvb.MinorVersion,
 265        .DirectoryTableBase = vs->dtb,
 266        .PfnDatabase = kdbg->MmPfnDatabase,
 267        .PsLoadedModuleList = kdbg->PsLoadedModuleList,
 268        .PsActiveProcessHead = kdbg->PsActiveProcessHead,
 269        .MachineImageType = kvb.MachineType,
 270        .NumberProcessors = nr_cpus,
 271        .BugcheckCode = LIVE_SYSTEM_DUMP,
 272        .KdDebuggerDataBlock = KdDebuggerDataBlock,
 273        .DumpType = 1,
 274        .Comment = "Hello from elf2dmp!",
 275        .SuiteMask = *suite_mask,
 276        .ProductType = *product_type,
 277        .SecondaryDataState = kvb.KdSecondaryVersion,
 278        .PhysicalMemoryBlock = (WinDumpPhyMemDesc64) {
 279            .NumberOfRuns = ps->block_nr,
 280        },
 281        .RequiredDumpSpace = sizeof(h),
 282    };
 283
 284    for (i = 0; i < ps->block_nr; i++) {
 285        h.PhysicalMemoryBlock.NumberOfPages += ps->block[i].size / PAGE_SIZE;
 286        h.PhysicalMemoryBlock.Run[i] = (WinDumpPhyMemRun64) {
 287            .BasePage = ps->block[i].paddr / PAGE_SIZE,
 288            .PageCount = ps->block[i].size / PAGE_SIZE,
 289        };
 290    }
 291
 292    h.RequiredDumpSpace += h.PhysicalMemoryBlock.NumberOfPages << PAGE_BITS;
 293
 294    *hdr = h;
 295
 296    return 0;
 297}
 298
 299static int fill_context(KDDEBUGGER_DATA64 *kdbg,
 300        struct va_space *vs, QEMU_Elf *qe)
 301{
 302        int i;
 303    for (i = 0; i < qe->state_nr; i++) {
 304        uint64_t Prcb;
 305        uint64_t Context;
 306        WinContext ctx;
 307        QEMUCPUState *s = qe->state[i];
 308
 309        if (va_space_rw(vs, kdbg->KiProcessorBlock + sizeof(Prcb) * i,
 310                    &Prcb, sizeof(Prcb), 0)) {
 311            eprintf("Failed to read CPU #%d PRCB location\n", i);
 312            return 1;
 313        }
 314
 315        if (va_space_rw(vs, Prcb + kdbg->OffsetPrcbContext,
 316                    &Context, sizeof(Context), 0)) {
 317            eprintf("Failed to read CPU #%d ContextFrame location\n", i);
 318            return 1;
 319        }
 320
 321        printf("Filling context for CPU #%d...\n", i);
 322        win_context_init_from_qemu_cpu_state(&ctx, s);
 323
 324        if (va_space_rw(vs, Context, &ctx, sizeof(ctx), 1)) {
 325            eprintf("Failed to fill CPU #%d context\n", i);
 326            return 1;
 327        }
 328    }
 329
 330    return 0;
 331}
 332
 333static int write_dump(struct pa_space *ps,
 334        WinDumpHeader64 *hdr, const char *name)
 335{
 336    FILE *dmp_file = fopen(name, "wb");
 337    size_t i;
 338
 339    if (!dmp_file) {
 340        eprintf("Failed to open output file \'%s\'\n", name);
 341        return 1;
 342    }
 343
 344    printf("Writing header to file...\n");
 345
 346    if (fwrite(hdr, sizeof(*hdr), 1, dmp_file) != 1) {
 347        eprintf("Failed to write dump header\n");
 348        fclose(dmp_file);
 349        return 1;
 350    }
 351
 352    for (i = 0; i < ps->block_nr; i++) {
 353        struct pa_block *b = &ps->block[i];
 354
 355        printf("Writing block #%zu/%zu to file...\n", i, ps->block_nr);
 356        if (fwrite(b->addr, b->size, 1, dmp_file) != 1) {
 357            eprintf("Failed to write dump header\n");
 358            fclose(dmp_file);
 359            return 1;
 360        }
 361    }
 362
 363    return fclose(dmp_file);
 364}
 365
 366static int pe_get_pdb_symstore_hash(uint64_t base, void *start_addr,
 367        char *hash, struct va_space *vs)
 368{
 369    const char e_magic[2] = "MZ";
 370    const char Signature[4] = "PE\0\0";
 371    const char sign_rsds[4] = "RSDS";
 372    IMAGE_DOS_HEADER *dos_hdr = start_addr;
 373    IMAGE_NT_HEADERS64 nt_hdrs;
 374    IMAGE_FILE_HEADER *file_hdr = &nt_hdrs.FileHeader;
 375    IMAGE_OPTIONAL_HEADER64 *opt_hdr = &nt_hdrs.OptionalHeader;
 376    IMAGE_DATA_DIRECTORY *data_dir = nt_hdrs.OptionalHeader.DataDirectory;
 377    IMAGE_DEBUG_DIRECTORY debug_dir;
 378    OMFSignatureRSDS rsds;
 379    char *pdb_name;
 380    size_t pdb_name_sz;
 381    size_t i;
 382
 383    QEMU_BUILD_BUG_ON(sizeof(*dos_hdr) >= PAGE_SIZE);
 384
 385    if (memcmp(&dos_hdr->e_magic, e_magic, sizeof(e_magic))) {
 386        return 1;
 387    }
 388
 389    if (va_space_rw(vs, base + dos_hdr->e_lfanew,
 390                &nt_hdrs, sizeof(nt_hdrs), 0)) {
 391        return 1;
 392    }
 393
 394    if (memcmp(&nt_hdrs.Signature, Signature, sizeof(Signature)) ||
 395            file_hdr->Machine != 0x8664 || opt_hdr->Magic != 0x020b) {
 396        return 1;
 397    }
 398
 399    printf("Debug Directory RVA = 0x%08"PRIx32"\n",
 400            (uint32_t)data_dir[IMAGE_FILE_DEBUG_DIRECTORY].VirtualAddress);
 401
 402    if (va_space_rw(vs,
 403                base + data_dir[IMAGE_FILE_DEBUG_DIRECTORY].VirtualAddress,
 404                &debug_dir, sizeof(debug_dir), 0)) {
 405        return 1;
 406    }
 407
 408    if (debug_dir.Type != IMAGE_DEBUG_TYPE_CODEVIEW) {
 409        return 1;
 410    }
 411
 412    if (va_space_rw(vs,
 413                base + debug_dir.AddressOfRawData,
 414                &rsds, sizeof(rsds), 0)) {
 415        return 1;
 416    }
 417
 418    printf("CodeView signature is \'%.4s\'\n", rsds.Signature);
 419
 420    if (memcmp(&rsds.Signature, sign_rsds, sizeof(sign_rsds))) {
 421        return 1;
 422    }
 423
 424    pdb_name_sz = debug_dir.SizeOfData - sizeof(rsds);
 425    pdb_name = malloc(pdb_name_sz);
 426    if (!pdb_name) {
 427        return 1;
 428    }
 429
 430    if (va_space_rw(vs, base + debug_dir.AddressOfRawData +
 431                offsetof(OMFSignatureRSDS, name), pdb_name, pdb_name_sz, 0)) {
 432        free(pdb_name);
 433        return 1;
 434    }
 435
 436    printf("PDB name is \'%s\', \'%s\' expected\n", pdb_name, PDB_NAME);
 437
 438    if (strcmp(pdb_name, PDB_NAME)) {
 439        eprintf("Unexpected PDB name, it seems the kernel isn't found\n");
 440        free(pdb_name);
 441        return 1;
 442    }
 443
 444    free(pdb_name);
 445
 446    sprintf(hash, "%.08x%.04x%.04x%.02x%.02x", rsds.guid.a, rsds.guid.b,
 447            rsds.guid.c, rsds.guid.d[0], rsds.guid.d[1]);
 448    hash += 20;
 449    for (i = 0; i < 6; i++, hash += 2) {
 450        sprintf(hash, "%.02x", rsds.guid.e[i]);
 451    }
 452
 453    sprintf(hash, "%.01x", rsds.age);
 454
 455    return 0;
 456}
 457
 458int main(int argc, char *argv[])
 459{
 460    int err = 0;
 461    QEMU_Elf qemu_elf;
 462    struct pa_space ps;
 463    struct va_space vs;
 464    QEMUCPUState *state;
 465    idt_desc_t first_idt_desc;
 466    uint64_t KernBase;
 467    void *nt_start_addr = NULL;
 468    WinDumpHeader64 header;
 469    char pdb_hash[34];
 470    char pdb_url[] = SYM_URL_BASE PDB_NAME
 471        "/0123456789ABCDEF0123456789ABCDEFx/" PDB_NAME;
 472    struct pdb_reader pdb;
 473    uint64_t KdDebuggerDataBlock;
 474    KDDEBUGGER_DATA64 *kdbg;
 475    uint64_t KdVersionBlock;
 476
 477    if (argc != 3) {
 478        eprintf("usage:\n\t%s elf_file dmp_file\n", argv[0]);
 479        return 1;
 480    }
 481
 482    if (QEMU_Elf_init(&qemu_elf, argv[1])) {
 483        eprintf("Failed to initialize QEMU ELF dump\n");
 484        return 1;
 485    }
 486
 487    if (pa_space_create(&ps, &qemu_elf)) {
 488        eprintf("Failed to initialize physical address space\n");
 489        err = 1;
 490        goto out_elf;
 491    }
 492
 493    state = qemu_elf.state[0];
 494    printf("CPU #0 CR3 is 0x%016"PRIx64"\n", state->cr[3]);
 495
 496    va_space_create(&vs, &ps, state->cr[3]);
 497    if (fix_dtb(&vs, &qemu_elf)) {
 498        eprintf("Failed to find paging base\n");
 499        err = 1;
 500        goto out_elf;
 501    }
 502
 503    printf("CPU #0 IDT is at 0x%016"PRIx64"\n", state->idt.base);
 504
 505    if (va_space_rw(&vs, state->idt.base,
 506                &first_idt_desc, sizeof(first_idt_desc), 0)) {
 507        eprintf("Failed to get CPU #0 IDT[0]\n");
 508        err = 1;
 509        goto out_ps;
 510    }
 511    printf("CPU #0 IDT[0] -> 0x%016"PRIx64"\n", idt_desc_addr(first_idt_desc));
 512
 513    KernBase = idt_desc_addr(first_idt_desc) & ~(PAGE_SIZE - 1);
 514    printf("Searching kernel downwards from 0x%016"PRIx64"...\n", KernBase);
 515
 516    for (; KernBase >= 0xfffff78000000000; KernBase -= PAGE_SIZE) {
 517        nt_start_addr = va_space_resolve(&vs, KernBase);
 518        if (!nt_start_addr) {
 519            continue;
 520        }
 521
 522        if (*(uint16_t *)nt_start_addr == 0x5a4d) { /* MZ */
 523            break;
 524        }
 525    }
 526
 527    if (!nt_start_addr) {
 528        eprintf("Failed to find NT kernel image\n");
 529        err = 1;
 530        goto out_ps;
 531    }
 532
 533    printf("KernBase = 0x%016"PRIx64", signature is \'%.2s\'\n", KernBase,
 534            (char *)nt_start_addr);
 535
 536    if (pe_get_pdb_symstore_hash(KernBase, nt_start_addr, pdb_hash, &vs)) {
 537        eprintf("Failed to get PDB symbol store hash\n");
 538        err = 1;
 539        goto out_ps;
 540    }
 541
 542    sprintf(pdb_url, "%s%s/%s/%s", SYM_URL_BASE, PDB_NAME, pdb_hash, PDB_NAME);
 543    printf("PDB URL is %s\n", pdb_url);
 544
 545    if (download_url(PDB_NAME, pdb_url)) {
 546        eprintf("Failed to download PDB file\n");
 547        err = 1;
 548        goto out_ps;
 549    }
 550
 551    if (pdb_init_from_file(PDB_NAME, &pdb)) {
 552        eprintf("Failed to initialize PDB reader\n");
 553        err = 1;
 554        goto out_pdb_file;
 555    }
 556
 557    if (!SYM_RESOLVE(KernBase, &pdb, KdDebuggerDataBlock) ||
 558            !SYM_RESOLVE(KernBase, &pdb, KdVersionBlock)) {
 559        err = 1;
 560        goto out_pdb;
 561    }
 562
 563    kdbg = get_kdbg(KernBase, &pdb, &vs, KdDebuggerDataBlock);
 564    if (!kdbg) {
 565        err = 1;
 566        goto out_pdb;
 567    }
 568
 569    if (fill_header(&header, &ps, &vs, KdDebuggerDataBlock, kdbg,
 570            KdVersionBlock, qemu_elf.state_nr)) {
 571        err = 1;
 572        goto out_pdb;
 573    }
 574
 575    if (fill_context(kdbg, &vs, &qemu_elf)) {
 576        err = 1;
 577        goto out_pdb;
 578    }
 579
 580    if (write_dump(&ps, &header, argv[2])) {
 581        eprintf("Failed to save dump\n");
 582        err = 1;
 583        goto out_kdbg;
 584    }
 585
 586out_kdbg:
 587    free(kdbg);
 588out_pdb:
 589    pdb_exit(&pdb);
 590out_pdb_file:
 591    unlink(PDB_NAME);
 592out_ps:
 593    pa_space_destroy(&ps);
 594out_elf:
 595    QEMU_Elf_exit(&qemu_elf);
 596
 597    return err;
 598}
 599