VirtualBox

source: vbox/trunk/src/VBox/Debugger/DBGPlugInWinNt.cpp@ 57125

Last change on this file since 57125 was 57125, checked in by vboxsync, 9 years ago

DBGPlugInWinNt.cpp: With windows 10/AMD64 there is more kernel space that needs searching.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 46.8 KB
Line 
1/* $Id: DBGPlugInWinNt.cpp 57125 2015-07-30 10:16:39Z vboxsync $ */
2/** @file
3 * DBGPlugInWindows - Debugger and Guest OS Digger Plugin For Windows NT.
4 */
5
6/*
7 * Copyright (C) 2009-2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#define LOG_GROUP LOG_GROUP_DBGF ///@todo add new log group.
23#include "DBGPlugIns.h"
24#include <VBox/vmm/dbgf.h>
25#include <VBox/err.h>
26#include <VBox/param.h>
27#include <iprt/ldr.h>
28#include <iprt/mem.h>
29#include <iprt/stream.h>
30#include <iprt/string.h>
31
32#include "../Runtime/include/internal/ldrMZ.h" /* ugly */
33#include "../Runtime/include/internal/ldrPE.h" /* ugly */
34
35
36/*******************************************************************************
37* Structures and Typedefs *
38*******************************************************************************/
39
40/** @name Internal WinNT structures
41 * @{ */
42/**
43 * PsLoadedModuleList entry for 32-bit NT aka LDR_DATA_TABLE_ENTRY.
44 * Tested with XP.
45 */
46typedef struct NTMTE32
47{
48 struct
49 {
50 uint32_t Flink;
51 uint32_t Blink;
52 } InLoadOrderLinks,
53 InMemoryOrderModuleList,
54 InInitializationOrderModuleList;
55 uint32_t DllBase;
56 uint32_t EntryPoint;
57 uint32_t SizeOfImage;
58 struct
59 {
60 uint16_t Length;
61 uint16_t MaximumLength;
62 uint32_t Buffer;
63 } FullDllName,
64 BaseDllName;
65 uint32_t Flags;
66 uint16_t LoadCount;
67 uint16_t TlsIndex;
68 /* ... there is more ... */
69} NTMTE32;
70typedef NTMTE32 *PNTMTE32;
71
72/**
73 * PsLoadedModuleList entry for 64-bit NT aka LDR_DATA_TABLE_ENTRY.
74 */
75typedef struct NTMTE64
76{
77 struct
78 {
79 uint64_t Flink;
80 uint64_t Blink;
81 } InLoadOrderLinks, /**< 0x00 */
82 InMemoryOrderModuleList, /**< 0x10 */
83 InInitializationOrderModuleList; /**< 0x20 */
84 uint64_t DllBase; /**< 0x30 */
85 uint64_t EntryPoint; /**< 0x38 */
86 uint32_t SizeOfImage; /**< 0x40 */
87 uint32_t Alignment; /**< 0x44 */
88 struct
89 {
90 uint16_t Length; /**< 0x48,0x58 */
91 uint16_t MaximumLength; /**< 0x4a,0x5a */
92 uint32_t Alignment; /**< 0x4c,0x5c */
93 uint64_t Buffer; /**< 0x50,0x60 */
94 } FullDllName, /**< 0x48 */
95 BaseDllName; /**< 0x58 */
96 uint32_t Flags; /**< 0x68 */
97 uint16_t LoadCount; /**< 0x6c */
98 uint16_t TlsIndex; /**< 0x6e */
99 /* ... there is more ... */
100} NTMTE64;
101typedef NTMTE64 *PNTMTE64;
102
103/** MTE union. */
104typedef union NTMTE
105{
106 NTMTE32 vX_32;
107 NTMTE64 vX_64;
108} NTMTE;
109typedef NTMTE *PNTMTE;
110
111
112/**
113 * The essential bits of the KUSER_SHARED_DATA structure.
114 */
115typedef struct NTKUSERSHAREDDATA
116{
117 uint32_t TickCountLowDeprecated;
118 uint32_t TickCountMultiplier;
119 struct
120 {
121 uint32_t LowPart;
122 int32_t High1Time;
123 int32_t High2Time;
124
125 } InterruptTime,
126 SystemTime,
127 TimeZoneBias;
128 uint16_t ImageNumberLow;
129 uint16_t ImageNumberHigh;
130 RTUTF16 NtSystemRoot[260];
131 uint32_t MaxStackTraceDepth;
132 uint32_t CryptoExponent;
133 uint32_t TimeZoneId;
134 uint32_t LargePageMinimum;
135 uint32_t Reserved2[7];
136 uint32_t NtProductType;
137 uint8_t ProductTypeIsValid;
138 uint8_t abPadding[3];
139 uint32_t NtMajorVersion;
140 uint32_t NtMinorVersion;
141 /* uint8_t ProcessorFeatures[64];
142 ...
143 */
144} NTKUSERSHAREDDATA;
145typedef NTKUSERSHAREDDATA *PNTKUSERSHAREDDATA;
146
147/** KI_USER_SHARED_DATA for i386 */
148#define NTKUSERSHAREDDATA_WINNT32 UINT32_C(0xffdf0000)
149/** KI_USER_SHARED_DATA for AMD64 */
150#define NTKUSERSHAREDDATA_WINNT64 UINT64_C(0xfffff78000000000)
151
152/** NTKUSERSHAREDDATA::NtProductType */
153typedef enum NTPRODUCTTYPE
154{
155 kNtProductType_Invalid = 0,
156 kNtProductType_WinNt = 1,
157 kNtProductType_LanManNt,
158 kNtProductType_Server
159} NTPRODUCTTYPE;
160
161
162/** NT image header union. */
163typedef union NTHDRSU
164{
165 IMAGE_NT_HEADERS32 vX_32;
166 IMAGE_NT_HEADERS64 vX_64;
167} NTHDRS;
168/** Pointer to NT image header union. */
169typedef NTHDRS *PNTHDRS;
170/** Pointer to const NT image header union. */
171typedef NTHDRS const *PCNTHDRS;
172
173/** @} */
174
175
176
177typedef enum DBGDIGGERWINNTVER
178{
179 DBGDIGGERWINNTVER_UNKNOWN,
180 DBGDIGGERWINNTVER_3_1,
181 DBGDIGGERWINNTVER_3_5,
182 DBGDIGGERWINNTVER_4_0,
183 DBGDIGGERWINNTVER_5_0,
184 DBGDIGGERWINNTVER_5_1,
185 DBGDIGGERWINNTVER_6_0
186} DBGDIGGERWINNTVER;
187
188/**
189 * WinNT guest OS digger instance data.
190 */
191typedef struct DBGDIGGERWINNT
192{
193 /** Whether the information is valid or not.
194 * (For fending off illegal interface method calls.) */
195 bool fValid;
196 /** 32-bit (true) or 64-bit (false) */
197 bool f32Bit;
198
199 /** The NT version. */
200 DBGDIGGERWINNTVER enmVer;
201 /** NTKUSERSHAREDDATA::NtProductType */
202 NTPRODUCTTYPE NtProductType;
203 /** NTKUSERSHAREDDATA::NtMajorVersion */
204 uint32_t NtMajorVersion;
205 /** NTKUSERSHAREDDATA::NtMinorVersion */
206 uint32_t NtMinorVersion;
207
208 /** The address of the ntoskrnl.exe image. */
209 DBGFADDRESS KernelAddr;
210 /** The address of the ntoskrnl.exe module table entry. */
211 DBGFADDRESS KernelMteAddr;
212 /** The address of PsLoadedModuleList. */
213 DBGFADDRESS PsLoadedModuleListAddr;
214} DBGDIGGERWINNT;
215/** Pointer to the linux guest OS digger instance data. */
216typedef DBGDIGGERWINNT *PDBGDIGGERWINNT;
217
218
219/**
220 * The WinNT digger's loader reader instance data.
221 */
222typedef struct DBGDIGGERWINNTRDR
223{
224 /** The VM handle (referenced). */
225 PUVM pUVM;
226 /** The image base. */
227 DBGFADDRESS ImageAddr;
228 /** The image size. */
229 uint32_t cbImage;
230 /** The file offset of the SizeOfImage field in the optional header if it
231 * needs patching, otherwise set to UINT32_MAX. */
232 uint32_t offSizeOfImage;
233 /** The correct image size. */
234 uint32_t cbCorrectImageSize;
235 /** Number of entries in the aMappings table. */
236 uint32_t cMappings;
237 /** Mapping hint. */
238 uint32_t iHint;
239 /** Mapping file offset to memory offsets, ordered by file offset. */
240 struct
241 {
242 /** The file offset. */
243 uint32_t offFile;
244 /** The size of this mapping. */
245 uint32_t cbMem;
246 /** The offset to the memory from the start of the image. */
247 uint32_t offMem;
248 } aMappings[1];
249} DBGDIGGERWINNTRDR;
250/** Pointer a WinNT loader reader instance data. */
251typedef DBGDIGGERWINNTRDR *PDBGDIGGERWINNTRDR;
252
253
254/*******************************************************************************
255* Defined Constants And Macros *
256*******************************************************************************/
257/** Validates a 32-bit Windows NT kernel address */
258#define WINNT32_VALID_ADDRESS(Addr) ((Addr) > UINT32_C(0x80000000) && (Addr) < UINT32_C(0xfffff000))
259/** Validates a 64-bit Windows NT kernel address */
260 #define WINNT64_VALID_ADDRESS(Addr) ((Addr) > UINT64_C(0xffff800000000000) && (Addr) < UINT64_C(0xfffffffffffff000))
261/** Validates a kernel address. */
262#define WINNT_VALID_ADDRESS(pThis, Addr) ((pThis)->f32Bit ? WINNT32_VALID_ADDRESS(Addr) : WINNT64_VALID_ADDRESS(Addr))
263/** Versioned and bitness wrapper. */
264#define WINNT_UNION(pThis, pUnion, Member) ((pThis)->f32Bit ? (pUnion)->vX_32. Member : (pUnion)->vX_64. Member )
265
266/** The length (in chars) of the kernel file name (no path). */
267#define WINNT_KERNEL_BASE_NAME_LEN 12
268
269/** WindowsNT on little endian ASCII systems. */
270#define DIG_WINNT_MOD_TAG UINT64_C(0x54696e646f774e54)
271
272
273/*******************************************************************************
274* Internal Functions *
275*******************************************************************************/
276static DECLCALLBACK(int) dbgDiggerWinNtInit(PUVM pUVM, void *pvData);
277
278
279/*******************************************************************************
280* Global Variables *
281*******************************************************************************/
282/** Kernel names. */
283static const RTUTF16 g_wszKernelNames[][WINNT_KERNEL_BASE_NAME_LEN + 1] =
284{
285 { 'n', 't', 'o', 's', 'k', 'r', 'n', 'l', '.', 'e', 'x', 'e' }
286};
287
288
289
290/** @callback_method_impl{PFNRTLDRRDRMEMREAD} */
291static DECLCALLBACK(int) dbgDiggerWinNtRdr_Read(void *pvBuf, size_t cb, size_t off, void *pvUser)
292{
293 PDBGDIGGERWINNTRDR pThis = (PDBGDIGGERWINNTRDR)pvUser;
294 uint32_t offFile = (uint32_t)off;
295 AssertReturn(offFile == off, VERR_INVALID_PARAMETER);
296
297 uint32_t i = pThis->iHint;
298 if (pThis->aMappings[i].offFile > offFile)
299 {
300 i = pThis->cMappings;
301 while (i-- > 0)
302 if (offFile >= pThis->aMappings[i].offFile)
303 break;
304 pThis->iHint = i;
305 }
306
307 while (cb > 0)
308 {
309 uint32_t offNextMap = i + 1 < pThis->cMappings ? pThis->aMappings[i + 1].offFile : pThis->cbImage;
310 uint32_t offMap = offFile - pThis->aMappings[i].offFile;
311
312 /* Read file bits backed by memory. */
313 if (offMap < pThis->aMappings[i].cbMem)
314 {
315 uint32_t cbToRead = pThis->aMappings[i].cbMem - offMap;
316 if (cbToRead > cb)
317 cbToRead = (uint32_t)cb;
318
319 DBGFADDRESS Addr = pThis->ImageAddr;
320 DBGFR3AddrAdd(&Addr, pThis->aMappings[i].offMem + offMap);
321
322 int rc = DBGFR3MemRead(pThis->pUVM, 0 /*idCpu*/, &Addr, pvBuf, cbToRead);
323 if (RT_FAILURE(rc))
324 return rc;
325
326 /* Apply SizeOfImage patch? */
327 if ( pThis->offSizeOfImage != UINT32_MAX
328 && offFile < pThis->offSizeOfImage + 4
329 && offFile + cbToRead > pThis->offSizeOfImage)
330 {
331 uint32_t SizeOfImage = pThis->cbCorrectImageSize;
332 uint32_t cbPatch = sizeof(SizeOfImage);
333 int32_t offPatch = pThis->offSizeOfImage - offFile;
334 uint8_t *pbPatch = (uint8_t *)pvBuf + offPatch;
335 if (offFile + cbToRead < pThis->offSizeOfImage + cbPatch)
336 cbPatch = offFile + cbToRead - pThis->offSizeOfImage;
337 while (cbPatch-- > 0)
338 {
339 if (offPatch >= 0)
340 *pbPatch = (uint8_t)SizeOfImage;
341 offPatch++;
342 pbPatch++;
343 SizeOfImage >>= 8;
344 }
345 }
346
347 /* Done? */
348 if (cbToRead == cb)
349 break;
350
351 offFile += cbToRead;
352 cb -= cbToRead;
353 pvBuf = (char *)pvBuf + cbToRead;
354 }
355
356 /* Mind the gap. */
357 if (offNextMap > offFile)
358 {
359 uint32_t cbZero = offNextMap - offFile;
360 if (cbZero > cb)
361 {
362 RT_BZERO(pvBuf, cb);
363 break;
364 }
365
366 RT_BZERO(pvBuf, cbZero);
367 offFile += cbZero;
368 cb -= cbZero;
369 pvBuf = (char *)pvBuf + cbZero;
370 }
371
372 pThis->iHint = ++i;
373 }
374
375 return VINF_SUCCESS;
376}
377
378
379/** @callback_method_impl{PFNRTLDRRDRMEMDTOR} */
380static DECLCALLBACK(void) dbgDiggerWinNtRdr_Dtor(void *pvUser)
381{
382 PDBGDIGGERWINNTRDR pThis = (PDBGDIGGERWINNTRDR)pvUser;
383
384 VMR3ReleaseUVM(pThis->pUVM);
385 pThis->pUVM = NULL;
386 RTMemFree(pvUser);
387}
388
389
390/**
391 * Checks if the section headers look okay.
392 *
393 * @returns true / false.
394 * @param paShs Pointer to the section headers.
395 * @param cShs Number of headers.
396 * @param cbImage The image size reported by NT.
397 * @param uRvaRsrc The RVA of the resource directory. UINT32_MAX if
398 * no resource directory.
399 * @param cbSectAlign The section alignment specified in the header.
400 * @param pcbImageCorrect The corrected image size. This is derived from
401 * cbImage and virtual range of the section tables.
402 *
403 * The problem is that NT may choose to drop the
404 * last pages in images it loads early, starting at
405 * the resource directory. These images will have
406 * a page aligned cbImage.
407 */
408static bool dbgDiggerWinNtCheckSectHdrsAndImgSize(PCIMAGE_SECTION_HEADER paShs, uint32_t cShs, uint32_t cbImage,
409 uint32_t uRvaRsrc, uint32_t cbSectAlign, uint32_t *pcbImageCorrect)
410{
411 *pcbImageCorrect = cbImage;
412
413 for (uint32_t i = 0; i < cShs; i++)
414 {
415 if (!paShs[i].Name[0])
416 {
417 Log(("DigWinNt: Section header #%u has no name\n", i));
418 return false;
419 }
420
421 if (paShs[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD)
422 continue;
423
424 /* Check that sizes are within the same range and that both sizes and
425 addresses are within reasonable limits. */
426 if ( RT_ALIGN(paShs[i].Misc.VirtualSize, _64K) < RT_ALIGN(paShs[i].SizeOfRawData, _64K)
427 || paShs[i].Misc.VirtualSize >= _1G
428 || paShs[i].SizeOfRawData >= _1G)
429 {
430 Log(("DigWinNt: Section header #%u has a VirtualSize=%#x and SizeOfRawData=%#x, that's too much data!\n",
431 i, paShs[i].Misc.VirtualSize, paShs[i].SizeOfRawData));
432 return false;
433 }
434 uint32_t uRvaEnd = paShs[i].VirtualAddress + paShs[i].Misc.VirtualSize;
435 if (uRvaEnd >= _1G || uRvaEnd < paShs[i].VirtualAddress)
436 {
437 Log(("DigWinNt: Section header #%u has a VirtualSize=%#x and VirtualAddr=%#x, %#x in total, that's too much!\n",
438 i, paShs[i].Misc.VirtualSize, paShs[i].VirtualAddress, uRvaEnd));
439 return false;
440 }
441
442 /* Check for images chopped off around '.rsrc'. */
443 if ( cbImage < uRvaEnd
444 && uRvaEnd >= uRvaRsrc)
445 cbImage = RT_ALIGN(uRvaEnd, cbSectAlign);
446
447 /* Check that the section is within the image. */
448 if (uRvaEnd > cbImage)
449 {
450 Log(("DigWinNt: Section header #%u has a virtual address range beyond the image: %#x TO %#x cbImage=%#x\n",
451 i, paShs[i].VirtualAddress, uRvaEnd, cbImage));
452 return false;
453 }
454 }
455
456 Assert(*pcbImageCorrect == cbImage || !(*pcbImageCorrect & 0xfff));
457 *pcbImageCorrect = cbImage;
458 return true;
459}
460
461
462/**
463 * Create a loader module for the in-guest-memory PE module.
464 */
465static int dbgDiggerWinNtCreateLdrMod(PDBGDIGGERWINNT pThis, PUVM pUVM, const char *pszName, PCDBGFADDRESS pImageAddr,
466 uint32_t cbImage, uint8_t *pbBuf, size_t cbBuf,
467 uint32_t offHdrs, PCNTHDRS pHdrs, PRTLDRMOD phLdrMod)
468{
469 /*
470 * Allocate and create a reader instance.
471 */
472 uint32_t const cShs = WINNT_UNION(pThis, pHdrs, FileHeader.NumberOfSections);
473 PDBGDIGGERWINNTRDR pRdr = (PDBGDIGGERWINNTRDR)RTMemAlloc(RT_OFFSETOF(DBGDIGGERWINNTRDR, aMappings[cShs + 2]));
474 if (!pRdr)
475 return VERR_NO_MEMORY;
476
477 VMR3RetainUVM(pUVM);
478 pRdr->pUVM = pUVM;
479 pRdr->ImageAddr = *pImageAddr;
480 pRdr->cbImage = cbImage;
481 pRdr->cbCorrectImageSize = cbImage;
482 pRdr->offSizeOfImage = UINT32_MAX;
483 pRdr->iHint = 0;
484
485 /*
486 * Use the section table to construct a more accurate view of the file/
487 * image if it's in the buffer (it should be).
488 */
489 uint32_t uRvaRsrc = UINT32_MAX;
490 if (WINNT_UNION(pThis, pHdrs, OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE]).Size > 0)
491 uRvaRsrc = WINNT_UNION(pThis, pHdrs, OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE]).VirtualAddress;
492 uint32_t offShs = offHdrs
493 + ( pThis->f32Bit
494 ? pHdrs->vX_32.FileHeader.SizeOfOptionalHeader + RT_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader)
495 : pHdrs->vX_64.FileHeader.SizeOfOptionalHeader + RT_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader));
496 uint32_t cbShs = cShs * sizeof(IMAGE_SECTION_HEADER);
497 PCIMAGE_SECTION_HEADER paShs = (PCIMAGE_SECTION_HEADER)(pbBuf + offShs);
498 if ( offShs + cbShs <= RT_MIN(cbImage, cbBuf)
499 && dbgDiggerWinNtCheckSectHdrsAndImgSize(paShs, cShs, cbImage, uRvaRsrc,
500 WINNT_UNION(pThis, pHdrs, OptionalHeader.SectionAlignment),
501 &pRdr->cbCorrectImageSize))
502 {
503 pRdr->cMappings = 0;
504
505 for (uint32_t i = 0; i < cShs; i++)
506 if ( paShs[i].SizeOfRawData > 0
507 && paShs[i].PointerToRawData > 0)
508 {
509 uint32_t j = 1;
510 if (!pRdr->cMappings)
511 pRdr->cMappings++;
512 else
513 {
514 while (j < pRdr->cMappings && pRdr->aMappings[j].offFile < paShs[i].PointerToRawData)
515 j++;
516 if (j < pRdr->cMappings)
517 memmove(&pRdr->aMappings[j + 1], &pRdr->aMappings[j], (pRdr->cMappings - j) * sizeof(pRdr->aMappings));
518 }
519 pRdr->aMappings[j].offFile = paShs[i].PointerToRawData;
520 pRdr->aMappings[j].offMem = paShs[i].VirtualAddress;
521 pRdr->aMappings[j].cbMem = i + 1 < cShs
522 ? paShs[i + 1].VirtualAddress - paShs[i].VirtualAddress
523 : paShs[i].Misc.VirtualSize;
524 if (j == pRdr->cMappings)
525 pRdr->cbImage = paShs[i].PointerToRawData + paShs[i].SizeOfRawData;
526 pRdr->cMappings++;
527 }
528
529 /* Insert the mapping of the headers that isn't covered by the section table. */
530 pRdr->aMappings[0].offFile = 0;
531 pRdr->aMappings[0].offMem = 0;
532 pRdr->aMappings[0].cbMem = pRdr->cMappings ? pRdr->aMappings[1].offFile : pRdr->cbImage;
533
534 int j = pRdr->cMappings - 1;
535 while (j-- > 0)
536 {
537 uint32_t cbFile = pRdr->aMappings[j + 1].offFile - pRdr->aMappings[j].offFile;
538 if (pRdr->aMappings[j].cbMem > cbFile)
539 pRdr->aMappings[j].cbMem = cbFile;
540 }
541 }
542 else
543 {
544 /*
545 * Fallback, fake identity mapped file data.
546 */
547 pRdr->cMappings = 1;
548 pRdr->aMappings[0].offFile = 0;
549 pRdr->aMappings[0].offMem = 0;
550 pRdr->aMappings[0].cbMem = pRdr->cbImage;
551 }
552
553 /* Enable the SizeOfImage patching if necessary. */
554 if (pRdr->cbCorrectImageSize != cbImage)
555 {
556 Log(("DigWinNT: The image is really %#x bytes long, not %#x as mapped by NT!\n", pRdr->cbCorrectImageSize, cbImage));
557 pRdr->offSizeOfImage = pThis->f32Bit
558 ? offHdrs + RT_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader.SizeOfImage)
559 : offHdrs + RT_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader.SizeOfImage);
560 }
561
562 /*
563 * Call the loader to open the PE image for debugging.
564 * Note! It always calls pfnDtor.
565 */
566 RTLDRMOD hLdrMod;
567 int rc = RTLdrOpenInMemory(pszName, RTLDR_O_FOR_DEBUG, RTLDRARCH_WHATEVER, pRdr->cbImage,
568 dbgDiggerWinNtRdr_Read, dbgDiggerWinNtRdr_Dtor, pRdr,
569 &hLdrMod);
570 if (RT_SUCCESS(rc))
571 *phLdrMod = hLdrMod;
572 else
573 *phLdrMod = NIL_RTLDRMOD;
574 return rc;
575}
576
577
578/**
579 * Process a PE image found in guest memory.
580 *
581 * @param pThis The instance data.
582 * @param pUVM The user mode VM handle.
583 * @param pszName The image name.
584 * @param pImageAddr The image address.
585 * @param cbImage The size of the image.
586 * @param pbBuf Scratch buffer containing the first
587 * RT_MIN(cbBuf, cbImage) bytes of the image.
588 * @param cbBuf The scratch buffer size.
589 */
590static void dbgDiggerWinNtProcessImage(PDBGDIGGERWINNT pThis, PUVM pUVM, const char *pszName,
591 PCDBGFADDRESS pImageAddr, uint32_t cbImage,
592 uint8_t *pbBuf, size_t cbBuf)
593{
594 LogFlow(("DigWinNt: %RGp %#x %s\n", pImageAddr->FlatPtr, cbImage, pszName));
595
596 /*
597 * Do some basic validation first.
598 * This is the usual exteremely verbose and messy code...
599 */
600 Assert(cbBuf >= sizeof(IMAGE_NT_HEADERS64));
601 if ( cbImage < sizeof(IMAGE_NT_HEADERS64)
602 || cbImage >= _1M * 256)
603 {
604 Log(("DigWinNt: %s: Bad image size: %#x\n", pszName, cbImage));
605 return;
606 }
607
608 /* Dig out the NT/PE headers. */
609 IMAGE_DOS_HEADER const *pMzHdr = (IMAGE_DOS_HEADER const *)pbBuf;
610 PCNTHDRS pHdrs;
611 uint32_t offHdrs;
612 if (pMzHdr->e_magic != IMAGE_DOS_SIGNATURE)
613 {
614 offHdrs = 0;
615 pHdrs = (PCNTHDRS)pbBuf;
616 }
617 else if ( pMzHdr->e_lfanew >= cbImage
618 || pMzHdr->e_lfanew < sizeof(*pMzHdr)
619 || pMzHdr->e_lfanew + sizeof(IMAGE_NT_HEADERS64) > cbImage)
620 {
621 Log(("DigWinNt: %s: PE header to far into image: %#x cbImage=%#x\n", pszName, pMzHdr->e_lfanew, cbImage));
622 return;
623 }
624 else if ( pMzHdr->e_lfanew < cbBuf
625 && pMzHdr->e_lfanew + sizeof(IMAGE_NT_HEADERS64) <= cbBuf)
626 {
627 offHdrs = pMzHdr->e_lfanew;
628 pHdrs = (NTHDRS const *)(pbBuf + offHdrs);
629 }
630 else
631 {
632 Log(("DigWinNt: %s: PE header to far into image (lazy bird): %#x\n", pszName, pMzHdr->e_lfanew));
633 return;
634 }
635 if (pHdrs->vX_32.Signature != IMAGE_NT_SIGNATURE)
636 {
637 Log(("DigWinNt: %s: Bad PE signature: %#x\n", pszName, pHdrs->vX_32.Signature));
638 return;
639 }
640
641 /* The file header is the same on both archs */
642 if (pHdrs->vX_32.FileHeader.Machine != (pThis->f32Bit ? IMAGE_FILE_MACHINE_I386 : IMAGE_FILE_MACHINE_AMD64))
643 {
644 Log(("DigWinNt: %s: Invalid FH.Machine: %#x\n", pszName, pHdrs->vX_32.FileHeader.Machine));
645 return;
646 }
647 if (pHdrs->vX_32.FileHeader.SizeOfOptionalHeader != (pThis->f32Bit ? sizeof(IMAGE_OPTIONAL_HEADER32) : sizeof(IMAGE_OPTIONAL_HEADER64)))
648 {
649 Log(("DigWinNt: %s: Invalid FH.SizeOfOptionalHeader: %#x\n", pszName, pHdrs->vX_32.FileHeader.SizeOfOptionalHeader));
650 return;
651 }
652 if (WINNT_UNION(pThis, pHdrs, FileHeader.NumberOfSections) > 64)
653 {
654 Log(("DigWinNt: %s: Too many sections: %#x\n", pszName, WINNT_UNION(pThis, pHdrs, FileHeader.NumberOfSections)));
655 return;
656 }
657
658 const uint32_t TimeDateStamp = pHdrs->vX_32.FileHeader.TimeDateStamp;
659
660 /* The optional header is not... */
661 if (WINNT_UNION(pThis, pHdrs, OptionalHeader.Magic) != (pThis->f32Bit ? IMAGE_NT_OPTIONAL_HDR32_MAGIC : IMAGE_NT_OPTIONAL_HDR64_MAGIC))
662 {
663 Log(("DigWinNt: %s: Invalid OH.Magic: %#x\n", pszName, WINNT_UNION(pThis, pHdrs, OptionalHeader.Magic)));
664 return;
665 }
666 uint32_t cbImageFromHdr = WINNT_UNION(pThis, pHdrs, OptionalHeader.SizeOfImage);
667 if (RT_ALIGN(cbImageFromHdr, _4K) != RT_ALIGN(cbImage, _4K))
668 {
669 Log(("DigWinNt: %s: Invalid OH.SizeOfImage: %#x, expected %#x\n", pszName, cbImageFromHdr, cbImage));
670 return;
671 }
672 if (WINNT_UNION(pThis, pHdrs, OptionalHeader.NumberOfRvaAndSizes) != IMAGE_NUMBEROF_DIRECTORY_ENTRIES)
673 {
674 Log(("DigWinNt: %s: Invalid OH.NumberOfRvaAndSizes: %#x\n", pszName, WINNT_UNION(pThis, pHdrs, OptionalHeader.NumberOfRvaAndSizes)));
675 return;
676 }
677
678 /*
679 * Create the module using the in memory image first, falling back
680 * on cached image.
681 */
682 RTLDRMOD hLdrMod;
683 int rc = dbgDiggerWinNtCreateLdrMod(pThis, pUVM, pszName, pImageAddr, cbImage, pbBuf, cbBuf, offHdrs, pHdrs,
684 &hLdrMod);
685 if (RT_FAILURE(rc))
686 hLdrMod = NIL_RTLDRMOD;
687
688 RTDBGMOD hMod;
689 rc = RTDbgModCreateFromPeImage(&hMod, pszName, NULL, hLdrMod,
690 cbImageFromHdr, TimeDateStamp, DBGFR3AsGetConfig(pUVM));
691 if (RT_FAILURE(rc))
692 {
693 /*
694 * Final fallback is a container module.
695 */
696 rc = RTDbgModCreate(&hMod, pszName, cbImage, 0);
697 if (RT_FAILURE(rc))
698 return;
699
700 rc = RTDbgModSymbolAdd(hMod, "Headers", 0 /*iSeg*/, 0, cbImage, 0 /*fFlags*/, NULL);
701 AssertRC(rc);
702 }
703
704 /* Tag the module. */
705 rc = RTDbgModSetTag(hMod, DIG_WINNT_MOD_TAG);
706 AssertRC(rc);
707
708 /*
709 * Link the module.
710 */
711 RTDBGAS hAs = DBGFR3AsResolveAndRetain(pUVM, DBGF_AS_KERNEL);
712 if (hAs != NIL_RTDBGAS)
713 rc = RTDbgAsModuleLink(hAs, hMod, pImageAddr->FlatPtr, RTDBGASLINK_FLAGS_REPLACE /*fFlags*/);
714 else
715 rc = VERR_INTERNAL_ERROR;
716 RTDbgModRelease(hMod);
717 RTDbgAsRelease(hAs);
718}
719
720
721/**
722 * @copydoc DBGFOSREG::pfnQueryInterface
723 */
724static DECLCALLBACK(void *) dbgDiggerWinNtQueryInterface(PUVM pUVM, void *pvData, DBGFOSINTERFACE enmIf)
725{
726 return NULL;
727}
728
729
730/**
731 * @copydoc DBGFOSREG::pfnQueryVersion
732 */
733static DECLCALLBACK(int) dbgDiggerWinNtQueryVersion(PUVM pUVM, void *pvData, char *pszVersion, size_t cchVersion)
734{
735 PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
736 Assert(pThis->fValid);
737 const char *pszNtProductType;
738 switch (pThis->NtProductType)
739 {
740 case kNtProductType_WinNt: pszNtProductType = "-WinNT"; break;
741 case kNtProductType_LanManNt: pszNtProductType = "-LanManNT"; break;
742 case kNtProductType_Server: pszNtProductType = "-Server"; break;
743 default: pszNtProductType = ""; break;
744 }
745 RTStrPrintf(pszVersion, cchVersion, "%u.%u-%s%s", pThis->NtMajorVersion, pThis->NtMinorVersion,
746 pThis->f32Bit ? "x86" : "AMD64", pszNtProductType);
747 return VINF_SUCCESS;
748}
749
750
751/**
752 * @copydoc DBGFOSREG::pfnTerm
753 */
754static DECLCALLBACK(void) dbgDiggerWinNtTerm(PUVM pUVM, void *pvData)
755{
756 PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
757 Assert(pThis->fValid);
758
759 pThis->fValid = false;
760}
761
762
763/**
764 * @copydoc DBGFOSREG::pfnRefresh
765 */
766static DECLCALLBACK(int) dbgDiggerWinNtRefresh(PUVM pUVM, void *pvData)
767{
768 PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
769 NOREF(pThis);
770 Assert(pThis->fValid);
771
772 /*
773 * For now we'll flush and reload everything.
774 */
775 RTDBGAS hDbgAs = DBGFR3AsResolveAndRetain(pUVM, DBGF_AS_KERNEL);
776 if (hDbgAs != NIL_RTDBGAS)
777 {
778 uint32_t iMod = RTDbgAsModuleCount(hDbgAs);
779 while (iMod-- > 0)
780 {
781 RTDBGMOD hMod = RTDbgAsModuleByIndex(hDbgAs, iMod);
782 if (hMod != NIL_RTDBGMOD)
783 {
784 if (RTDbgModGetTag(hMod) == DIG_WINNT_MOD_TAG)
785 {
786 int rc = RTDbgAsModuleUnlink(hDbgAs, hMod);
787 AssertRC(rc);
788 }
789 RTDbgModRelease(hMod);
790 }
791 }
792 RTDbgAsRelease(hDbgAs);
793 }
794
795 dbgDiggerWinNtTerm(pUVM, pvData);
796 return dbgDiggerWinNtInit(pUVM, pvData);
797}
798
799
800/**
801 * @copydoc DBGFOSREG::pfnInit
802 */
803static DECLCALLBACK(int) dbgDiggerWinNtInit(PUVM pUVM, void *pvData)
804{
805 PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
806 Assert(!pThis->fValid);
807
808 union
809 {
810 uint8_t au8[0x2000];
811 RTUTF16 wsz[0x2000/2];
812 NTKUSERSHAREDDATA UserSharedData;
813 } u;
814 DBGFADDRESS Addr;
815 int rc;
816
817 /*
818 * Figure the NT version.
819 */
820 DBGFR3AddrFromFlat(pUVM, &Addr, pThis->f32Bit ? NTKUSERSHAREDDATA_WINNT32 : NTKUSERSHAREDDATA_WINNT64);
821 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &Addr, &u, PAGE_SIZE);
822 if (RT_FAILURE(rc))
823 return rc;
824 pThis->NtProductType = u.UserSharedData.ProductTypeIsValid && u.UserSharedData.NtProductType <= kNtProductType_Server
825 ? (NTPRODUCTTYPE)u.UserSharedData.NtProductType
826 : kNtProductType_Invalid;
827 pThis->NtMajorVersion = u.UserSharedData.NtMajorVersion;
828 pThis->NtMinorVersion = u.UserSharedData.NtMinorVersion;
829
830 /*
831 * Dig out the module chain.
832 */
833 DBGFADDRESS AddrPrev = pThis->PsLoadedModuleListAddr;
834 Addr = pThis->KernelMteAddr;
835 do
836 {
837 /* Read the validate the MTE. */
838 NTMTE Mte;
839 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &Addr, &Mte, pThis->f32Bit ? sizeof(Mte.vX_32) : sizeof(Mte.vX_64));
840 if (RT_FAILURE(rc))
841 break;
842 if (WINNT_UNION(pThis, &Mte, InLoadOrderLinks.Blink) != AddrPrev.FlatPtr)
843 {
844 Log(("DigWinNt: Bad Mte At %RGv - backpointer\n", Addr.FlatPtr));
845 break;
846 }
847 if (!WINNT_VALID_ADDRESS(pThis, WINNT_UNION(pThis, &Mte, InLoadOrderLinks.Flink)) )
848 {
849 Log(("DigWinNt: Bad Mte at %RGv - forward pointer\n", Addr.FlatPtr));
850 break;
851 }
852 if (!WINNT_VALID_ADDRESS(pThis, WINNT_UNION(pThis, &Mte, BaseDllName.Buffer)))
853 {
854 Log(("DigWinNt: Bad Mte at %RGv - BaseDllName=%llx\n", Addr.FlatPtr, WINNT_UNION(pThis, &Mte, BaseDllName.Buffer)));
855 break;
856 }
857 if (!WINNT_VALID_ADDRESS(pThis, WINNT_UNION(pThis, &Mte, FullDllName.Buffer)))
858 {
859 Log(("DigWinNt: Bad Mte at %RGv - FullDllName=%llx\n", Addr.FlatPtr, WINNT_UNION(pThis, &Mte, FullDllName.Buffer)));
860 break;
861 }
862 if ( !WINNT_VALID_ADDRESS(pThis, WINNT_UNION(pThis, &Mte, DllBase))
863 || WINNT_UNION(pThis, &Mte, SizeOfImage) > _1M*256
864 || WINNT_UNION(pThis, &Mte, EntryPoint) - WINNT_UNION(pThis, &Mte, DllBase) > WINNT_UNION(pThis, &Mte, SizeOfImage) )
865 {
866 Log(("DigWinNt: Bad Mte at %RGv - EntryPoint=%llx SizeOfImage=%x DllBase=%llx\n",
867 Addr.FlatPtr, WINNT_UNION(pThis, &Mte, EntryPoint), WINNT_UNION(pThis, &Mte, SizeOfImage), WINNT_UNION(pThis, &Mte, DllBase)));
868 break;
869 }
870
871 /* Read the full name. */
872 DBGFADDRESS AddrName;
873 DBGFR3AddrFromFlat(pUVM, &AddrName, WINNT_UNION(pThis, &Mte, FullDllName.Buffer));
874 uint16_t cbName = WINNT_UNION(pThis, &Mte, FullDllName.Length);
875 if (cbName < sizeof(u))
876 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &AddrName, &u, cbName);
877 else
878 rc = VERR_OUT_OF_RANGE;
879 if (RT_FAILURE(rc))
880 {
881 DBGFR3AddrFromFlat(pUVM, &AddrName, WINNT_UNION(pThis, &Mte, BaseDllName.Buffer));
882 cbName = WINNT_UNION(pThis, &Mte, BaseDllName.Length);
883 if (cbName < sizeof(u))
884 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &AddrName, &u, cbName);
885 else
886 rc = VERR_OUT_OF_RANGE;
887 }
888 if (RT_SUCCESS(rc))
889 {
890 u.wsz[cbName/2] = '\0';
891 char *pszName;
892 rc = RTUtf16ToUtf8(u.wsz, &pszName);
893 if (RT_SUCCESS(rc))
894 {
895 /* Read the start of the PE image and pass it along to a worker. */
896 DBGFADDRESS ImageAddr;
897 DBGFR3AddrFromFlat(pUVM, &ImageAddr, WINNT_UNION(pThis, &Mte, DllBase));
898 uint32_t cbImageBuf = RT_MIN(sizeof(u), WINNT_UNION(pThis, &Mte, SizeOfImage));
899 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &ImageAddr, &u, cbImageBuf);
900 if (RT_SUCCESS(rc))
901 dbgDiggerWinNtProcessImage(pThis,
902 pUVM,
903 pszName,
904 &ImageAddr,
905 WINNT_UNION(pThis, &Mte, SizeOfImage),
906 &u.au8[0],
907 sizeof(u));
908 RTStrFree(pszName);
909 }
910 }
911
912 /* next */
913 AddrPrev = Addr;
914 DBGFR3AddrFromFlat(pUVM, &Addr, WINNT_UNION(pThis, &Mte, InLoadOrderLinks.Flink));
915 } while ( Addr.FlatPtr != pThis->KernelMteAddr.FlatPtr
916 && Addr.FlatPtr != pThis->PsLoadedModuleListAddr.FlatPtr);
917
918 pThis->fValid = true;
919 return VINF_SUCCESS;
920}
921
922
923/**
924 * @copydoc DBGFOSREG::pfnProbe
925 */
926static DECLCALLBACK(bool) dbgDiggerWinNtProbe(PUVM pUVM, void *pvData)
927{
928 PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
929 DBGFADDRESS Addr;
930 union
931 {
932 uint8_t au8[8192];
933 uint16_t au16[8192/2];
934 uint32_t au32[8192/4];
935 IMAGE_DOS_HEADER MzHdr;
936 RTUTF16 wsz[8192/2];
937 } u;
938
939 union
940 {
941 NTMTE32 v32;
942 NTMTE64 v64;
943 } uMte, uMte2, uMte3;
944
945 /*
946 * Look for the PAGELK section name that seems to be a part of all kernels.
947 * Then try find the module table entry for it. Since it's the first entry
948 * in the PsLoadedModuleList we can easily validate the list head and report
949 * success.
950 */
951 CPUMMODE enmMode = DBGFR3CpuGetMode(pUVM, 0 /*idCpu*/);
952 uint64_t const uStart = enmMode == CPUMMODE_LONG ? UINT64_C(0xffff080000000000) : UINT32_C(0x80001000);
953 uint64_t const uEnd = enmMode == CPUMMODE_LONG ? UINT64_C(0xffffffffffff0000) : UINT32_C(0xffff0000);
954 DBGFADDRESS KernelAddr;
955 for (DBGFR3AddrFromFlat(pUVM, &KernelAddr, uStart);
956 KernelAddr.FlatPtr < uEnd;
957 KernelAddr.FlatPtr += PAGE_SIZE)
958 {
959 int rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &KernelAddr, uEnd - KernelAddr.FlatPtr,
960 1, "PAGELK\0", sizeof("PAGELK\0"), &KernelAddr);
961 if (RT_FAILURE(rc))
962 break;
963 DBGFR3AddrSub(&KernelAddr, KernelAddr.FlatPtr & PAGE_OFFSET_MASK);
964
965 /* MZ + PE header. */
966 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &KernelAddr, &u, sizeof(u));
967 if ( RT_SUCCESS(rc)
968 && u.MzHdr.e_magic == IMAGE_DOS_SIGNATURE
969 && !(u.MzHdr.e_lfanew & 0x7)
970 && u.MzHdr.e_lfanew >= 0x080
971 && u.MzHdr.e_lfanew <= 0x400) /* W8 is at 0x288*/
972 {
973 if (enmMode != CPUMMODE_LONG)
974 {
975 IMAGE_NT_HEADERS32 const *pHdrs = (IMAGE_NT_HEADERS32 const *)&u.au8[u.MzHdr.e_lfanew];
976 if ( pHdrs->Signature == IMAGE_NT_SIGNATURE
977 && pHdrs->FileHeader.Machine == IMAGE_FILE_MACHINE_I386
978 && pHdrs->FileHeader.SizeOfOptionalHeader == sizeof(pHdrs->OptionalHeader)
979 && pHdrs->FileHeader.NumberOfSections >= 10 /* the kernel has lots */
980 && (pHdrs->FileHeader.Characteristics & (IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL)) == IMAGE_FILE_EXECUTABLE_IMAGE
981 && pHdrs->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC
982 && pHdrs->OptionalHeader.NumberOfRvaAndSizes == IMAGE_NUMBEROF_DIRECTORY_ENTRIES
983 )
984 {
985 /* Find the MTE. */
986 RT_ZERO(uMte);
987 uMte.v32.DllBase = KernelAddr.FlatPtr;
988 uMte.v32.EntryPoint = KernelAddr.FlatPtr + pHdrs->OptionalHeader.AddressOfEntryPoint;
989 uMte.v32.SizeOfImage = pHdrs->OptionalHeader.SizeOfImage;
990 DBGFADDRESS HitAddr;
991 rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &KernelAddr, uEnd - KernelAddr.FlatPtr,
992 4 /*align*/, &uMte.v32.DllBase, 3 * sizeof(uint32_t), &HitAddr);
993 while (RT_SUCCESS(rc))
994 {
995 /* check the name. */
996 DBGFADDRESS MteAddr = HitAddr;
997 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrSub(&MteAddr, RT_OFFSETOF(NTMTE32, DllBase)),
998 &uMte2.v32, sizeof(uMte2.v32));
999 if ( RT_SUCCESS(rc)
1000 && uMte2.v32.DllBase == uMte.v32.DllBase
1001 && uMte2.v32.EntryPoint == uMte.v32.EntryPoint
1002 && uMte2.v32.SizeOfImage == uMte.v32.SizeOfImage
1003 && WINNT32_VALID_ADDRESS(uMte2.v32.InLoadOrderLinks.Flink)
1004 && WINNT32_VALID_ADDRESS(uMte2.v32.BaseDllName.Buffer)
1005 && WINNT32_VALID_ADDRESS(uMte2.v32.FullDllName.Buffer)
1006 && uMte2.v32.BaseDllName.Length <= 128
1007 && uMte2.v32.FullDllName.Length <= 260
1008 )
1009 {
1010 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pUVM, &Addr, uMte2.v32.BaseDllName.Buffer),
1011 u.wsz, uMte2.v32.BaseDllName.Length);
1012 u.wsz[uMte2.v32.BaseDllName.Length / 2] = '\0';
1013 if ( RT_SUCCESS(rc)
1014 && ( !RTUtf16ICmp(u.wsz, g_wszKernelNames[0])
1015 /* || !RTUtf16ICmp(u.wsz, g_wszKernelNames[1]) */
1016 )
1017 )
1018 {
1019 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/,
1020 DBGFR3AddrFromFlat(pUVM, &Addr, uMte2.v32.InLoadOrderLinks.Blink),
1021 &uMte3.v32, RT_SIZEOFMEMB(NTMTE32, InLoadOrderLinks));
1022 if ( RT_SUCCESS(rc)
1023 && uMte3.v32.InLoadOrderLinks.Flink == MteAddr.FlatPtr
1024 && WINNT32_VALID_ADDRESS(uMte3.v32.InLoadOrderLinks.Blink) )
1025 {
1026 Log(("DigWinNt: MteAddr=%RGv KernelAddr=%RGv SizeOfImage=%x &PsLoadedModuleList=%RGv (32-bit)\n",
1027 MteAddr.FlatPtr, KernelAddr.FlatPtr, uMte2.v32.SizeOfImage, Addr.FlatPtr));
1028 pThis->KernelAddr = KernelAddr;
1029 pThis->KernelMteAddr = MteAddr;
1030 pThis->PsLoadedModuleListAddr = Addr;
1031 pThis->f32Bit = true;
1032 return true;
1033 }
1034 }
1035 else if (RT_SUCCESS(rc))
1036 {
1037 Log2(("DigWinNt: Wrong module: MteAddr=%RGv ImageAddr=%RGv SizeOfImage=%#x '%ls'\n",
1038 MteAddr.FlatPtr, KernelAddr.FlatPtr, uMte2.v32.SizeOfImage, u.wsz));
1039 break; /* Not NT kernel */
1040 }
1041 }
1042
1043 /* next */
1044 DBGFR3AddrAdd(&HitAddr, 4);
1045 if (HitAddr.FlatPtr < uEnd)
1046 rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &HitAddr, uEnd - HitAddr.FlatPtr,
1047 4 /*align*/, &uMte.v32.DllBase, 3 * sizeof(uint32_t), &HitAddr);
1048 else
1049 rc = VERR_DBGF_MEM_NOT_FOUND;
1050 }
1051 }
1052 }
1053 else
1054 {
1055 IMAGE_NT_HEADERS64 const *pHdrs = (IMAGE_NT_HEADERS64 const *)&u.au8[u.MzHdr.e_lfanew];
1056 if ( pHdrs->Signature == IMAGE_NT_SIGNATURE
1057 && pHdrs->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64
1058 && pHdrs->FileHeader.SizeOfOptionalHeader == sizeof(pHdrs->OptionalHeader)
1059 && pHdrs->FileHeader.NumberOfSections >= 10 /* the kernel has lots */
1060 && (pHdrs->FileHeader.Characteristics & (IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL))
1061 == IMAGE_FILE_EXECUTABLE_IMAGE
1062 && pHdrs->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC
1063 && pHdrs->OptionalHeader.NumberOfRvaAndSizes == IMAGE_NUMBEROF_DIRECTORY_ENTRIES
1064 )
1065 {
1066 /* Find the MTE. */
1067 RT_ZERO(uMte.v64);
1068 uMte.v64.DllBase = KernelAddr.FlatPtr;
1069 uMte.v64.EntryPoint = KernelAddr.FlatPtr + pHdrs->OptionalHeader.AddressOfEntryPoint;
1070 uMte.v64.SizeOfImage = pHdrs->OptionalHeader.SizeOfImage;
1071 DBGFADDRESS ScanAddr;
1072 DBGFADDRESS HitAddr;
1073 rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pUVM, &ScanAddr, uStart),
1074 uEnd - uStart, 8 /*align*/, &uMte.v64.DllBase, 5 * sizeof(uint32_t), &HitAddr);
1075 while (RT_SUCCESS(rc))
1076 {
1077 /* Read the start of the MTE and check some basic members. */
1078 DBGFADDRESS MteAddr = HitAddr;
1079 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrSub(&MteAddr, RT_OFFSETOF(NTMTE64, DllBase)),
1080 &uMte2.v64, sizeof(uMte2.v64));
1081 if ( RT_SUCCESS(rc)
1082 && uMte2.v64.DllBase == uMte.v64.DllBase
1083 && uMte2.v64.EntryPoint == uMte.v64.EntryPoint
1084 && uMte2.v64.SizeOfImage == uMte.v64.SizeOfImage
1085 && WINNT64_VALID_ADDRESS(uMte2.v64.InLoadOrderLinks.Flink)
1086 && WINNT64_VALID_ADDRESS(uMte2.v64.BaseDllName.Buffer)
1087 && WINNT64_VALID_ADDRESS(uMte2.v64.FullDllName.Buffer)
1088 && uMte2.v64.BaseDllName.Length <= 128
1089 && uMte2.v64.FullDllName.Length <= 260
1090 )
1091 {
1092 /* Try read the base name and compare with known NT kernel names. */
1093 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pUVM, &Addr, uMte2.v64.BaseDllName.Buffer),
1094 u.wsz, uMte2.v64.BaseDllName.Length);
1095 u.wsz[uMte2.v64.BaseDllName.Length / 2] = '\0';
1096 if ( RT_SUCCESS(rc)
1097 && ( !RTUtf16ICmp(u.wsz, g_wszKernelNames[0])
1098 /* || !RTUtf16ICmp(u.wsz, g_wszKernelNames[1]) */
1099 )
1100 )
1101 {
1102 /* Read the link entry of the previous entry in the list and check that its
1103 forward pointer points at the MTE we've found. */
1104 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/,
1105 DBGFR3AddrFromFlat(pUVM, &Addr, uMte2.v64.InLoadOrderLinks.Blink),
1106 &uMte3.v64, RT_SIZEOFMEMB(NTMTE64, InLoadOrderLinks));
1107 if ( RT_SUCCESS(rc)
1108 && uMte3.v64.InLoadOrderLinks.Flink == MteAddr.FlatPtr
1109 && WINNT64_VALID_ADDRESS(uMte3.v64.InLoadOrderLinks.Blink) )
1110 {
1111 Log(("DigWinNt: MteAddr=%RGv KernelAddr=%RGv SizeOfImage=%x &PsLoadedModuleList=%RGv (32-bit)\n",
1112 MteAddr.FlatPtr, KernelAddr.FlatPtr, uMte2.v64.SizeOfImage, Addr.FlatPtr));
1113 pThis->KernelAddr = KernelAddr;
1114 pThis->KernelMteAddr = MteAddr;
1115 pThis->PsLoadedModuleListAddr = Addr;
1116 pThis->f32Bit = false;
1117 return true;
1118 }
1119 }
1120 else if (RT_SUCCESS(rc))
1121 {
1122 Log2(("DigWinNt: Wrong module: MteAddr=%RGv ImageAddr=%RGv SizeOfImage=%#x '%ls'\n",
1123 MteAddr.FlatPtr, KernelAddr.FlatPtr, uMte2.v64.SizeOfImage, u.wsz));
1124 break; /* Not NT kernel */
1125 }
1126 }
1127
1128 /* next */
1129 DBGFR3AddrAdd(&HitAddr, 8);
1130 if (HitAddr.FlatPtr < uEnd)
1131 rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &HitAddr, uEnd - HitAddr.FlatPtr,
1132 8 /*align*/, &uMte.v64.DllBase, 3 * sizeof(uint32_t), &HitAddr);
1133 else
1134 rc = VERR_DBGF_MEM_NOT_FOUND;
1135 }
1136 }
1137 }
1138 }
1139 }
1140 return false;
1141}
1142
1143
1144/**
1145 * @copydoc DBGFOSREG::pfnDestruct
1146 */
1147static DECLCALLBACK(void) dbgDiggerWinNtDestruct(PUVM pUVM, void *pvData)
1148{
1149
1150}
1151
1152
1153/**
1154 * @copydoc DBGFOSREG::pfnConstruct
1155 */
1156static DECLCALLBACK(int) dbgDiggerWinNtConstruct(PUVM pUVM, void *pvData)
1157{
1158 PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
1159 pThis->fValid = false;
1160 pThis->f32Bit = false;
1161 pThis->enmVer = DBGDIGGERWINNTVER_UNKNOWN;
1162 return VINF_SUCCESS;
1163}
1164
1165
1166const DBGFOSREG g_DBGDiggerWinNt =
1167{
1168 /* .u32Magic = */ DBGFOSREG_MAGIC,
1169 /* .fFlags = */ 0,
1170 /* .cbData = */ sizeof(DBGDIGGERWINNT),
1171 /* .szName = */ "WinNT",
1172 /* .pfnConstruct = */ dbgDiggerWinNtConstruct,
1173 /* .pfnDestruct = */ dbgDiggerWinNtDestruct,
1174 /* .pfnProbe = */ dbgDiggerWinNtProbe,
1175 /* .pfnInit = */ dbgDiggerWinNtInit,
1176 /* .pfnRefresh = */ dbgDiggerWinNtRefresh,
1177 /* .pfnTerm = */ dbgDiggerWinNtTerm,
1178 /* .pfnQueryVersion = */ dbgDiggerWinNtQueryVersion,
1179 /* .pfnQueryInterface = */ dbgDiggerWinNtQueryInterface,
1180 /* .u32EndMagic = */ DBGFOSREG_MAGIC
1181};
1182
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette