2 * Copyright (c) 2018 Virtuozzo International GmbH
4 * This work is licensed under the terms of the GNU GPL, version 2 or later.
8 #include "qemu/osdep.h"
9 #include "qemu/bitops.h"
12 #include "addrspace.h"
17 #include "qemu/win_dump_defs.h"
19 #define SYM_URL_BASE "https://msdl.microsoft.com/download/symbols/"
20 #define PDB_NAME "ntkrnlmp.pdb"
21 #define PE_NAME "ntoskrnl.exe"
23 #define INITIAL_MXCSR 0x1f80
24 #define MAX_NUMBER_OF_RUNS 42
26 typedef struct idt_desc
{
27 uint16_t offset1
; /* offset bits 0..15 */
31 uint16_t offset2
; /* offset bits 16..31 */
32 uint32_t offset3
; /* offset bits 32..63 */
34 } __attribute__ ((packed
)) idt_desc_t
;
36 static uint64_t idt_desc_addr(idt_desc_t desc
)
38 return (uint64_t)desc
.offset1
| ((uint64_t)desc
.offset2
<< 16) |
39 ((uint64_t)desc
.offset3
<< 32);
42 static const uint64_t SharedUserData
= 0xfffff78000000000;
44 #define KUSD_OFFSET_SUITE_MASK 0x2d0
45 #define KUSD_OFFSET_PRODUCT_TYPE 0x264
47 #define SYM_RESOLVE(base, r, s) ((s = pdb_resolve(base, r, #s)),\
48 s ? printf(#s" = 0x%016"PRIx64"\n", s) :\
49 eprintf("Failed to resolve "#s"\n"), s)
52 * Decoding algorithm can be found in Volatility project
54 static void kdbg_decode(uint64_t *dst
, uint64_t *src
, size_t size
,
55 uint64_t kwn
, uint64_t kwa
, uint64_t kdbe
)
58 assert(size
% sizeof(uint64_t) == 0);
59 for (i
= 0; i
< size
/ sizeof(uint64_t); i
++) {
63 block
= rol64(block
^ kwn
, kwn
);
64 block
= __builtin_bswap64(block
^ kdbe
) ^ kwa
;
69 static KDDEBUGGER_DATA64
*get_kdbg(uint64_t KernBase
, struct pdb_reader
*pdb
,
70 struct va_space
*vs
, uint64_t KdDebuggerDataBlock
)
72 const char OwnerTag
[4] = "KDBG";
73 KDDEBUGGER_DATA64
*kdbg
= NULL
;
74 DBGKD_DEBUG_DATA_HEADER64 kdbg_hdr
;
76 uint64_t kwn
, kwa
, KdpDataBlockEncoded
;
79 KdDebuggerDataBlock
+ offsetof(KDDEBUGGER_DATA64
, Header
),
80 &kdbg_hdr
, sizeof(kdbg_hdr
), 0)) {
81 eprintf("Failed to extract KDBG header\n");
85 if (memcmp(&kdbg_hdr
.OwnerTag
, OwnerTag
, sizeof(OwnerTag
))) {
86 uint64_t KiWaitNever
, KiWaitAlways
;
90 if (!SYM_RESOLVE(KernBase
, pdb
, KiWaitNever
) ||
91 !SYM_RESOLVE(KernBase
, pdb
, KiWaitAlways
) ||
92 !SYM_RESOLVE(KernBase
, pdb
, KdpDataBlockEncoded
)) {
96 if (!va_space_rw(vs
, KiWaitNever
, &kwn
, sizeof(kwn
), 0) ||
97 !va_space_rw(vs
, KiWaitAlways
, &kwa
, sizeof(kwa
), 0)) {
101 printf("[KiWaitNever] = 0x%016"PRIx64
"\n", kwn
);
102 printf("[KiWaitAlways] = 0x%016"PRIx64
"\n", kwa
);
105 * If KDBG header can be decoded, KDBG size is available
106 * and entire KDBG can be decoded.
108 printf("Decoding KDBG header...\n");
109 kdbg_decode((uint64_t *)&kdbg_hdr
, (uint64_t *)&kdbg_hdr
,
110 sizeof(kdbg_hdr
), kwn
, kwa
, KdpDataBlockEncoded
);
112 printf("Owner tag is \'%.4s\'\n", (char *)&kdbg_hdr
.OwnerTag
);
113 if (memcmp(&kdbg_hdr
.OwnerTag
, OwnerTag
, sizeof(OwnerTag
))) {
114 eprintf("Failed to decode KDBG header\n");
119 kdbg
= g_malloc(kdbg_hdr
.Size
);
121 if (!va_space_rw(vs
, KdDebuggerDataBlock
, kdbg
, kdbg_hdr
.Size
, 0)) {
122 eprintf("Failed to extract entire KDBG\n");
131 printf("Decoding KdDebuggerDataBlock...\n");
132 kdbg_decode((uint64_t *)kdbg
, (uint64_t *)kdbg
, kdbg_hdr
.Size
,
133 kwn
, kwa
, KdpDataBlockEncoded
);
135 va_space_rw(vs
, KdDebuggerDataBlock
, kdbg
, kdbg_hdr
.Size
, 1);
140 static void win_context_init_from_qemu_cpu_state(WinContext64
*ctx
,
143 WinContext64 win_ctx
= (WinContext64
){
144 .ContextFlags
= WIN_CTX_X64
| WIN_CTX_INT
| WIN_CTX_SEG
| WIN_CTX_CTL
,
145 .MxCsr
= INITIAL_MXCSR
,
147 .SegCs
= s
->cs
.selector
,
148 .SegSs
= s
->ss
.selector
,
149 .SegDs
= s
->ds
.selector
,
150 .SegEs
= s
->es
.selector
,
151 .SegFs
= s
->fs
.selector
,
152 .SegGs
= s
->gs
.selector
,
153 .EFlags
= (uint32_t)s
->rflags
,
174 .MxCsr
= INITIAL_MXCSR
,
182 * Finds paging-structure hierarchy base,
183 * if previously set doesn't give access to kernel structures
185 static bool fix_dtb(struct va_space
*vs
, QEMU_Elf
*qe
)
188 * Firstly, test previously set DTB.
190 if (va_space_resolve(vs
, SharedUserData
)) {
195 * Secondly, find CPU which run system task.
198 for (i
= 0; i
< qe
->state_nr
; i
++) {
199 QEMUCPUState
*s
= qe
->state
[i
];
202 va_space_set_dtb(vs
, s
->cr
[3]);
203 printf("DTB 0x%016"PRIx64
" has been found from CPU #%zu"
204 " as system task CR3\n", vs
->dtb
, i
);
205 return va_space_resolve(vs
, SharedUserData
);
210 * Thirdly, use KERNEL_GS_BASE from CPU #0 as PRCB address and
211 * CR3 as [Prcb+0x7000]
213 if (qe
->has_kernel_gs_base
) {
214 QEMUCPUState
*s
= qe
->state
[0];
215 uint64_t Prcb
= s
->kernel_gs_base
;
216 uint64_t *cr3
= va_space_resolve(vs
, Prcb
+ 0x7000);
222 va_space_set_dtb(vs
, *cr3
);
223 printf("DirectoryTableBase = 0x%016"PRIx64
" has been found from CPU #0"
224 " as interrupt handling CR3\n", vs
->dtb
);
225 return va_space_resolve(vs
, SharedUserData
);
231 static void try_merge_runs(struct pa_space
*ps
,
232 WinDumpPhyMemDesc64
*PhysicalMemoryBlock
)
234 unsigned int merge_cnt
= 0, run_idx
= 0;
236 PhysicalMemoryBlock
->NumberOfRuns
= 0;
238 for (size_t idx
= 0; idx
< ps
->block_nr
; idx
++) {
239 struct pa_block
*blk
= ps
->block
+ idx
;
240 struct pa_block
*next
= blk
+ 1;
242 PhysicalMemoryBlock
->NumberOfPages
+= blk
->size
/ ELF2DMP_PAGE_SIZE
;
244 if (idx
+ 1 != ps
->block_nr
&& blk
->paddr
+ blk
->size
== next
->paddr
) {
245 printf("Block #%zu 0x%"PRIx64
"+:0x%"PRIx64
" and %u previous will be"
246 " merged\n", idx
, blk
->paddr
, blk
->size
, merge_cnt
);
249 struct pa_block
*first_merged
= blk
- merge_cnt
;
251 printf("Block #%zu 0x%"PRIx64
"+:0x%"PRIx64
" and %u previous will be"
252 " merged to 0x%"PRIx64
"+:0x%"PRIx64
" (run #%u)\n",
253 idx
, blk
->paddr
, blk
->size
, merge_cnt
, first_merged
->paddr
,
254 blk
->paddr
+ blk
->size
- first_merged
->paddr
, run_idx
);
255 PhysicalMemoryBlock
->Run
[run_idx
] = (WinDumpPhyMemRun64
) {
256 .BasePage
= first_merged
->paddr
/ ELF2DMP_PAGE_SIZE
,
257 .PageCount
= (blk
->paddr
+ blk
->size
- first_merged
->paddr
) /
260 PhysicalMemoryBlock
->NumberOfRuns
++;
267 static bool fill_header(WinDumpHeader64
*hdr
, struct pa_space
*ps
,
268 struct va_space
*vs
, uint64_t KdDebuggerDataBlock
,
269 KDDEBUGGER_DATA64
*kdbg
, uint64_t KdVersionBlock
,
272 uint32_t *suite_mask
= va_space_resolve(vs
, SharedUserData
+
273 KUSD_OFFSET_SUITE_MASK
);
274 int32_t *product_type
= va_space_resolve(vs
, SharedUserData
+
275 KUSD_OFFSET_PRODUCT_TYPE
);
276 DBGKD_GET_VERSION64 kvb
;
279 QEMU_BUILD_BUG_ON(KUSD_OFFSET_SUITE_MASK
>= ELF2DMP_PAGE_SIZE
);
280 QEMU_BUILD_BUG_ON(KUSD_OFFSET_PRODUCT_TYPE
>= ELF2DMP_PAGE_SIZE
);
282 if (!suite_mask
|| !product_type
) {
286 if (!va_space_rw(vs
, KdVersionBlock
, &kvb
, sizeof(kvb
), 0)) {
287 eprintf("Failed to extract KdVersionBlock\n");
291 h
= (WinDumpHeader64
) {
294 .MajorVersion
= kvb
.MajorVersion
,
295 .MinorVersion
= kvb
.MinorVersion
,
296 .DirectoryTableBase
= vs
->dtb
,
297 .PfnDatabase
= kdbg
->MmPfnDatabase
,
298 .PsLoadedModuleList
= kdbg
->PsLoadedModuleList
,
299 .PsActiveProcessHead
= kdbg
->PsActiveProcessHead
,
300 .MachineImageType
= kvb
.MachineType
,
301 .NumberProcessors
= nr_cpus
,
302 .BugcheckCode
= LIVE_SYSTEM_DUMP
,
303 .KdDebuggerDataBlock
= KdDebuggerDataBlock
,
305 .Comment
= "Hello from elf2dmp!",
306 .SuiteMask
= *suite_mask
,
307 .ProductType
= *product_type
,
308 .SecondaryDataState
= kvb
.KdSecondaryVersion
,
309 .PhysicalMemoryBlock
= (WinDumpPhyMemDesc64
) {
310 .NumberOfRuns
= ps
->block_nr
,
312 .RequiredDumpSpace
= sizeof(h
),
315 if (h
.PhysicalMemoryBlock
.NumberOfRuns
<= MAX_NUMBER_OF_RUNS
) {
316 for (size_t idx
= 0; idx
< ps
->block_nr
; idx
++) {
317 h
.PhysicalMemoryBlock
.NumberOfPages
+=
318 ps
->block
[idx
].size
/ ELF2DMP_PAGE_SIZE
;
319 h
.PhysicalMemoryBlock
.Run
[idx
] = (WinDumpPhyMemRun64
) {
320 .BasePage
= ps
->block
[idx
].paddr
/ ELF2DMP_PAGE_SIZE
,
321 .PageCount
= ps
->block
[idx
].size
/ ELF2DMP_PAGE_SIZE
,
325 try_merge_runs(ps
, &h
.PhysicalMemoryBlock
);
328 h
.RequiredDumpSpace
+=
329 h
.PhysicalMemoryBlock
.NumberOfPages
<< ELF2DMP_PAGE_BITS
;
337 * fill_context() continues even if it fails to fill contexts of some CPUs.
338 * A dump may still contain valuable information even if it lacks contexts of
339 * some CPUs due to dump corruption or a failure before starting CPUs.
341 static void fill_context(KDDEBUGGER_DATA64
*kdbg
,
342 struct va_space
*vs
, QEMU_Elf
*qe
)
346 for (i
= 0; i
< qe
->state_nr
; i
++) {
350 QEMUCPUState
*s
= qe
->state
[i
];
352 if (!va_space_rw(vs
, kdbg
->KiProcessorBlock
+ sizeof(Prcb
) * i
,
353 &Prcb
, sizeof(Prcb
), 0)) {
354 eprintf("Failed to read CPU #%d PRCB location\n", i
);
359 eprintf("Context for CPU #%d is missing\n", i
);
363 if (!va_space_rw(vs
, Prcb
+ kdbg
->OffsetPrcbContext
,
364 &Context
, sizeof(Context
), 0)) {
365 eprintf("Failed to read CPU #%d ContextFrame location\n", i
);
369 printf("Filling context for CPU #%d...\n", i
);
370 win_context_init_from_qemu_cpu_state(&ctx
, s
);
372 if (!va_space_rw(vs
, Context
, &ctx
, sizeof(ctx
), 1)) {
373 eprintf("Failed to fill CPU #%d context\n", i
);
379 static bool pe_get_data_dir_entry(uint64_t base
, void *start_addr
, int idx
,
380 void *entry
, size_t size
, struct va_space
*vs
)
382 const char e_magic
[2] = "MZ";
383 const char Signature
[4] = "PE\0\0";
384 IMAGE_DOS_HEADER
*dos_hdr
= start_addr
;
385 IMAGE_NT_HEADERS64 nt_hdrs
;
386 IMAGE_FILE_HEADER
*file_hdr
= &nt_hdrs
.FileHeader
;
387 IMAGE_OPTIONAL_HEADER64
*opt_hdr
= &nt_hdrs
.OptionalHeader
;
388 IMAGE_DATA_DIRECTORY
*data_dir
= nt_hdrs
.OptionalHeader
.DataDirectory
;
390 QEMU_BUILD_BUG_ON(sizeof(*dos_hdr
) >= ELF2DMP_PAGE_SIZE
);
392 if (memcmp(&dos_hdr
->e_magic
, e_magic
, sizeof(e_magic
))) {
396 if (!va_space_rw(vs
, base
+ dos_hdr
->e_lfanew
,
397 &nt_hdrs
, sizeof(nt_hdrs
), 0)) {
401 if (memcmp(&nt_hdrs
.Signature
, Signature
, sizeof(Signature
)) ||
402 file_hdr
->Machine
!= 0x8664 || opt_hdr
->Magic
!= 0x020b) {
406 if (!va_space_rw(vs
, base
+ data_dir
[idx
].VirtualAddress
, entry
, size
, 0)) {
410 printf("Data directory entry #%d: RVA = 0x%08"PRIx32
"\n", idx
,
411 (uint32_t)data_dir
[idx
].VirtualAddress
);
416 static bool write_dump(struct pa_space
*ps
,
417 WinDumpHeader64
*hdr
, const char *name
)
419 FILE *dmp_file
= fopen(name
, "wb");
423 eprintf("Failed to open output file \'%s\'\n", name
);
427 printf("Writing header to file...\n");
429 if (fwrite(hdr
, sizeof(*hdr
), 1, dmp_file
) != 1) {
430 eprintf("Failed to write dump header\n");
435 for (i
= 0; i
< ps
->block_nr
; i
++) {
436 struct pa_block
*b
= &ps
->block
[i
];
438 printf("Writing block #%zu/%zu of %"PRIu64
" bytes to file...\n", i
,
439 ps
->block_nr
, b
->size
);
440 if (fwrite(b
->addr
, b
->size
, 1, dmp_file
) != 1) {
441 eprintf("Failed to write block\n");
447 return !fclose(dmp_file
);
450 static bool pe_check_pdb_name(uint64_t base
, void *start_addr
,
451 struct va_space
*vs
, OMFSignatureRSDS
*rsds
)
453 const char sign_rsds
[4] = "RSDS";
454 IMAGE_DEBUG_DIRECTORY debug_dir
;
455 char pdb_name
[sizeof(PDB_NAME
)];
457 if (!pe_get_data_dir_entry(base
, start_addr
, IMAGE_FILE_DEBUG_DIRECTORY
,
458 &debug_dir
, sizeof(debug_dir
), vs
)) {
459 eprintf("Failed to get Debug Directory\n");
463 if (debug_dir
.Type
!= IMAGE_DEBUG_TYPE_CODEVIEW
) {
464 eprintf("Debug Directory type is not CodeView\n");
468 if (!va_space_rw(vs
, base
+ debug_dir
.AddressOfRawData
,
469 rsds
, sizeof(*rsds
), 0)) {
470 eprintf("Failed to resolve OMFSignatureRSDS\n");
474 if (memcmp(&rsds
->Signature
, sign_rsds
, sizeof(sign_rsds
))) {
475 eprintf("CodeView signature is \'%.4s\', \'%.4s\' expected\n",
476 rsds
->Signature
, sign_rsds
);
480 if (debug_dir
.SizeOfData
- sizeof(*rsds
) != sizeof(PDB_NAME
)) {
481 eprintf("PDB name size doesn't match\n");
485 if (!va_space_rw(vs
, base
+ debug_dir
.AddressOfRawData
+
486 offsetof(OMFSignatureRSDS
, name
),
487 pdb_name
, sizeof(PDB_NAME
), 0)) {
488 eprintf("Failed to resolve PDB name\n");
492 printf("PDB name is \'%s\', \'%s\' expected\n", pdb_name
, PDB_NAME
);
494 return !strcmp(pdb_name
, PDB_NAME
);
497 static void pe_get_pdb_symstore_hash(OMFSignatureRSDS
*rsds
, char *hash
)
499 sprintf(hash
, "%.08x%.04x%.04x%.02x%.02x", rsds
->guid
.a
, rsds
->guid
.b
,
500 rsds
->guid
.c
, rsds
->guid
.d
[0], rsds
->guid
.d
[1]);
502 for (unsigned int i
= 0; i
< 6; i
++, hash
+= 2) {
503 sprintf(hash
, "%.02x", rsds
->guid
.e
[i
]);
506 sprintf(hash
, "%.01x", rsds
->age
);
509 int main(int argc
, char *argv
[])
516 idt_desc_t first_idt_desc
;
518 void *nt_start_addr
= NULL
;
519 WinDumpHeader64 header
;
521 char pdb_url
[] = SYM_URL_BASE PDB_NAME
522 "/0123456789ABCDEF0123456789ABCDEFx/" PDB_NAME
;
523 struct pdb_reader pdb
;
524 uint64_t KdDebuggerDataBlock
;
525 KDDEBUGGER_DATA64
*kdbg
;
526 uint64_t KdVersionBlock
;
527 bool kernel_found
= false;
528 OMFSignatureRSDS rsds
;
531 eprintf("usage:\n\t%s elf_file dmp_file\n", argv
[0]);
535 if (!QEMU_Elf_init(&qemu_elf
, argv
[1])) {
536 eprintf("Failed to initialize QEMU ELF dump\n");
540 pa_space_create(&ps
, &qemu_elf
);
542 state
= qemu_elf
.state
[0];
543 printf("CPU #0 CR3 is 0x%016"PRIx64
"\n", state
->cr
[3]);
545 va_space_create(&vs
, &ps
, state
->cr
[3]);
546 if (!fix_dtb(&vs
, &qemu_elf
)) {
547 eprintf("Failed to find paging base\n");
551 printf("CPU #0 IDT is at 0x%016"PRIx64
"\n", state
->idt
.base
);
553 if (!va_space_rw(&vs
, state
->idt
.base
,
554 &first_idt_desc
, sizeof(first_idt_desc
), 0)) {
555 eprintf("Failed to get CPU #0 IDT[0]\n");
558 printf("CPU #0 IDT[0] -> 0x%016"PRIx64
"\n", idt_desc_addr(first_idt_desc
));
560 KernBase
= idt_desc_addr(first_idt_desc
) & ~(ELF2DMP_PAGE_SIZE
- 1);
561 printf("Searching kernel downwards from 0x%016"PRIx64
"...\n", KernBase
);
563 for (; KernBase
>= 0xfffff78000000000; KernBase
-= ELF2DMP_PAGE_SIZE
) {
564 nt_start_addr
= va_space_resolve(&vs
, KernBase
);
565 if (!nt_start_addr
) {
569 if (*(uint16_t *)nt_start_addr
== 0x5a4d) { /* MZ */
570 printf("Checking candidate KernBase = 0x%016"PRIx64
"\n", KernBase
);
571 if (pe_check_pdb_name(KernBase
, nt_start_addr
, &vs
, &rsds
)) {
579 eprintf("Failed to find NT kernel image\n");
583 printf("KernBase = 0x%016"PRIx64
", signature is \'%.2s\'\n", KernBase
,
584 (char *)nt_start_addr
);
586 pe_get_pdb_symstore_hash(&rsds
, pdb_hash
);
588 sprintf(pdb_url
, "%s%s/%s/%s", SYM_URL_BASE
, PDB_NAME
, pdb_hash
, PDB_NAME
);
589 printf("PDB URL is %s\n", pdb_url
);
591 if (!download_url(PDB_NAME
, pdb_url
)) {
592 eprintf("Failed to download PDB file\n");
596 if (!pdb_init_from_file(PDB_NAME
, &pdb
)) {
597 eprintf("Failed to initialize PDB reader\n");
601 if (!SYM_RESOLVE(KernBase
, &pdb
, KdDebuggerDataBlock
) ||
602 !SYM_RESOLVE(KernBase
, &pdb
, KdVersionBlock
)) {
606 kdbg
= get_kdbg(KernBase
, &pdb
, &vs
, KdDebuggerDataBlock
);
611 if (!fill_header(&header
, &ps
, &vs
, KdDebuggerDataBlock
, kdbg
,
612 KdVersionBlock
, qemu_elf
.state_nr
)) {
616 fill_context(kdbg
, &vs
, &qemu_elf
);
618 if (!write_dump(&ps
, &header
, argv
[2])) {
619 eprintf("Failed to save dump\n");
632 pa_space_destroy(&ps
);
633 QEMU_Elf_exit(&qemu_elf
);