1
/* $Id: DBGPlugInWinNt.cpp 35346 2010-12-27 16:13:13Z vboxsync $ */
3
* DBGPlugInWindows - Debugger and Guest OS Digger Plugin For Windows NT.
7
* Copyright (C) 2009-2010 Oracle Corporation
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.
19
/*******************************************************************************
21
*******************************************************************************/
22
#define LOG_GROUP LOG_GROUP_DBGF ///@todo add new log group.
23
#include "DBGPlugIns.h"
24
#include <VBox/vmm/dbgf.h>
26
#include <VBox/param.h>
27
#include <iprt/string.h>
29
#include <iprt/stream.h>
31
#include "../Runtime/include/internal/ldrMZ.h" /* ugly */
32
#include "../Runtime/include/internal/ldrPE.h" /* ugly */
35
/*******************************************************************************
36
* Structures and Typedefs *
37
*******************************************************************************/
39
/** @name Internal WinNT structures
42
* PsLoadedModuleList entry for 32-bit NT aka LDR_DATA_TABLE_ENTRY.
45
typedef struct NTMTE32
52
InMemoryOrderModuleList,
53
InInitializationOrderModuleList;
60
uint16_t MaximumLength;
67
/* ... there is more ... */
69
typedef NTMTE32 *PNTMTE32;
72
* PsLoadedModuleList entry for 32-bit NT aka LDR_DATA_TABLE_ENTRY.
75
* @todo This is incomplete and just to get rid of warnings.
77
typedef struct NTMTE64
84
InMemoryOrderModuleList,
85
InInitializationOrderModuleList;
93
uint16_t MaximumLength;
101
/* ... there is more ... */
103
typedef NTMTE64 *PNTMTE64;
111
typedef NTMTE *PNTMTE;
115
* The essential bits of the KUSER_SHARED_DATA structure.
117
typedef struct NTKUSERSHAREDDATA
119
uint32_t TickCountLowDeprecated;
120
uint32_t TickCountMultiplier;
130
uint16_t ImageNumberLow;
131
uint16_t ImageNumberHigh;
132
RTUTF16 NtSystemRoot[260];
133
uint32_t MaxStackTraceDepth;
134
uint32_t CryptoExponent;
136
uint32_t LargePageMinimum;
137
uint32_t Reserved2[7];
138
uint32_t NtProductType;
139
uint8_t ProductTypeIsValid;
140
uint8_t abPadding[3];
141
uint32_t NtMajorVersion;
142
uint32_t NtMinorVersion;
143
/* uint8_t ProcessorFeatures[64];
147
typedef NTKUSERSHAREDDATA *PNTKUSERSHAREDDATA;
149
/** KI_USER_SHARED_DATA for i386 */
150
#define NTKUSERSHAREDDATA_WINNT32 UINT32_C(0xffdf0000)
151
/** KI_USER_SHARED_DATA for AMD64 */
152
#define NTKUSERSHAREDDATA_WINNT64 UINT64_C(0xfffff78000000000)
154
/** NTKUSERSHAREDDATA::NtProductType */
155
typedef enum NTPRODUCTTYPE
157
kNtProductType_Invalid = 0,
158
kNtProductType_WinNt = 1,
159
kNtProductType_LanManNt,
160
kNtProductType_Server
164
* PDB v2.0 in image debug info.
165
* The URL is constructed from the timestamp and the %02x age?
167
typedef struct CV_INFO_PDB20
169
uint32_t Signature; /**< CV_SIGNATURE_PDB70. */
170
int32_t Offset; /**< Always 0. Used to be the offset to the real debug info. */
171
uint32_t TimeDateStamp;
173
uint8_t PdbFilename[4];
175
/** The CV_INFO_PDB20 signature. */
176
#define CV_SIGNATURE_PDB20 RT_MAKE_U32_FROM_U8('N','B','1','0')
179
* PDB v7.0 in image debug info.
180
* The URL is constructed from the signature and the %02x age.
183
typedef struct CV_INFO_PDB70
185
uint32_t CvSignature; /**< CV_SIGNATURE_PDB70. */
188
uint8_t PdbFilename[4];
191
AssertCompileMemberOffset(CV_INFO_PDB70, Signature, 4);
192
AssertCompileMemberOffset(CV_INFO_PDB70, Age, 4 + 16);
193
/** The CV_INFO_PDB70 signature. */
194
#define CV_SIGNATURE_PDB70 RT_MAKE_U32_FROM_U8('R','S','D','S')
199
typedef enum DBGDIGGERWINNTVER
201
DBGDIGGERWINNTVER_UNKNOWN,
202
DBGDIGGERWINNTVER_3_1,
203
DBGDIGGERWINNTVER_3_5,
204
DBGDIGGERWINNTVER_4_0,
205
DBGDIGGERWINNTVER_5_0,
206
DBGDIGGERWINNTVER_5_1,
207
DBGDIGGERWINNTVER_6_0
211
* WinNT guest OS digger instance data.
213
typedef struct DBGDIGGERWINNT
215
/** Whether the information is valid or not.
216
* (For fending off illegal interface method calls.) */
218
/** 32-bit (true) or 64-bit (false) */
221
/** The NT version. */
222
DBGDIGGERWINNTVER enmVer;
223
/** NTKUSERSHAREDDATA::NtProductType */
224
NTPRODUCTTYPE NtProductType;
225
/** NTKUSERSHAREDDATA::NtMajorVersion */
226
uint32_t NtMajorVersion;
227
/** NTKUSERSHAREDDATA::NtMinorVersion */
228
uint32_t NtMinorVersion;
230
/** The address of the ntoskrnl.exe image. */
231
DBGFADDRESS KernelAddr;
232
/** The address of the ntoskrnl.exe module table entry. */
233
DBGFADDRESS KernelMteAddr;
234
/** The address of PsLoadedModuleList. */
235
DBGFADDRESS PsLoadedModuleListAddr;
237
/** Pointer to the linux guest OS digger instance data. */
238
typedef DBGDIGGERWINNT *PDBGDIGGERWINNT;
241
/*******************************************************************************
242
* Defined Constants And Macros *
243
*******************************************************************************/
244
/** Validates a 32-bit Windows NT kernel address */
245
#define WINNT32_VALID_ADDRESS(Addr) ((Addr) > UINT32_C(0x80000000) && (Addr) < UINT32_C(0xfffff000))
246
/** Validates a 64-bit Windows NT kernel address */
247
#define WINNT64_VALID_ADDRESS(Addr) ((Addr) > UINT64_C(0xffffffff80000000) && (Addr) < UINT64_C(0xfffffffffffff000))
248
/** Validates a kernel address. */
249
#define WINNT_VALID_ADDRESS(pThis, Addr) ((pThis)->f32Bit ? WINNT32_VALID_ADDRESS(Addr) : WINNT64_VALID_ADDRESS(Addr))
250
/** Versioned and bitness wrapper. */
251
#define WINNT_UNION(pThis, pUnion, Member) ((pThis)->f32Bit ? (pUnion)->vX_32. Member : (pUnion)->vX_64. Member )
253
/** The length (in chars) of the kernel file name (no path). */
254
#define WINNT_KERNEL_BASE_NAME_LEN 12
256
/** WindowsNT on little endian ASCII systems. */
257
#define DIG_WINNT_MOD_TAG UINT64_C(0x54696e646f774e54)
260
/*******************************************************************************
261
* Internal Functions *
262
*******************************************************************************/
263
static DECLCALLBACK(int) dbgDiggerWinNtInit(PVM pVM, void *pvData);
266
/*******************************************************************************
268
*******************************************************************************/
270
static const RTUTF16 g_wszKernelNames[][WINNT_KERNEL_BASE_NAME_LEN + 1] =
272
{ 'n', 't', 'o', 's', 'k', 'r', 'n', 'l', '.', 'e', 'x', 'e' }
277
* Process a PE image found in guest memory.
279
* @param pThis The instance data.
280
* @param pVM The VM handle.
281
* @param pszName The image name.
282
* @param pImageAddr The image address.
283
* @param cbImage The size of the image.
284
* @param pbBuf Scratch buffer containing the first
285
* RT_MIN(cbBuf, cbImage) bytes of the image.
286
* @param cbBuf The scratch buffer size.
288
static void dbgDiggerWinNtProcessImage(PDBGDIGGERWINNT pThis, PVM pVM, const char *pszName,
289
PCDBGFADDRESS pImageAddr, uint32_t cbImage,
290
uint8_t *pbBuf, size_t cbBuf)
292
LogFlow(("DigWinNt: %RGp %#x %s\n", pImageAddr->FlatPtr, cbImage, pszName));
295
* Do some basic validation first.
296
* This is the usual exteremely verbose and messy code...
298
Assert(cbBuf >= sizeof(IMAGE_NT_HEADERS64));
299
if ( cbImage < sizeof(IMAGE_NT_HEADERS64)
300
|| cbImage >= _1M * 256)
302
Log(("DigWinNt: %s: Bad image size: %#x\n", pszName, cbImage));
306
/* Dig out the NT/PE headers. */
307
IMAGE_DOS_HEADER const *pMzHdr = (IMAGE_DOS_HEADER const *)pbBuf;
310
IMAGE_NT_HEADERS64 vX_32;
311
IMAGE_NT_HEADERS64 vX_64;
315
if (pMzHdr->e_magic != IMAGE_DOS_SIGNATURE)
318
pHdrs = (NTHDRS const *)pbBuf;
320
else if ( pMzHdr->e_lfanew >= cbImage
321
|| pMzHdr->e_lfanew < sizeof(*pMzHdr)
322
|| pMzHdr->e_lfanew + sizeof(IMAGE_NT_HEADERS64) > cbImage)
324
Log(("DigWinNt: %s: PE header to far into image: %#x cbImage=%#x\n", pMzHdr->e_lfanew, cbImage));
327
else if ( pMzHdr->e_lfanew < cbBuf
328
&& pMzHdr->e_lfanew + sizeof(IMAGE_NT_HEADERS64) <= cbBuf)
330
offHdrs = pMzHdr->e_lfanew;
331
pHdrs = (NTHDRS const *)(pbBuf + offHdrs);
335
Log(("DigWinNt: %s: PE header to far into image (lazy bird): %#x\n", pMzHdr->e_lfanew));
338
if (pHdrs->vX_32.Signature != IMAGE_NT_SIGNATURE)
340
Log(("DigWinNt: %s: Bad PE signature: %#x\n", pszName, pHdrs->vX_32.Signature));
344
/* The file header is the same on both archs */
345
if (pHdrs->vX_32.FileHeader.Machine != (pThis->f32Bit ? IMAGE_FILE_MACHINE_I386 : IMAGE_FILE_MACHINE_AMD64))
347
Log(("DigWinNt: %s: Invalid FH.Machine: %#x\n", pszName, pHdrs->vX_32.FileHeader.Machine));
350
if (pHdrs->vX_32.FileHeader.SizeOfOptionalHeader != (pThis->f32Bit ? sizeof(IMAGE_OPTIONAL_HEADER32) : sizeof(IMAGE_OPTIONAL_HEADER64)))
352
Log(("DigWinNt: %s: Invalid FH.SizeOfOptionalHeader: %#x\n", pszName, pHdrs->vX_32.FileHeader.SizeOfOptionalHeader));
355
const uint32_t TimeDateStamp = pHdrs->vX_32.FileHeader.TimeDateStamp;
357
/* The optional header is not... */
358
if (WINNT_UNION(pThis, pHdrs, OptionalHeader.Magic) != (pThis->f32Bit ? IMAGE_NT_OPTIONAL_HDR32_MAGIC : IMAGE_NT_OPTIONAL_HDR64_MAGIC))
360
Log(("DigWinNt: %s: Invalid OH.Magic: %#x\n", pszName, WINNT_UNION(pThis, pHdrs, OptionalHeader.Magic)));
363
if (WINNT_UNION(pThis, pHdrs, OptionalHeader.SizeOfImage) != cbImage)
365
Log(("DigWinNt: %s: Invalid OH.SizeOfImage: %#x, expected %#x\n", pszName, WINNT_UNION(pThis, pHdrs, OptionalHeader.SizeOfImage), cbImage));
368
if (WINNT_UNION(pThis, pHdrs, OptionalHeader.NumberOfRvaAndSizes) != IMAGE_NUMBEROF_DIRECTORY_ENTRIES)
370
Log(("DigWinNt: %s: Invalid OH.SizeOfImage: %#x\n", pszName, WINNT_UNION(pThis, pHdrs, OptionalHeader.NumberOfRvaAndSizes)));
374
uint32_t uRvaDebugDir = 0;
375
uint32_t cbDebugDir = 0;
376
IMAGE_DATA_DIRECTORY const *pDir = &WINNT_UNION(pThis, pHdrs, OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG]);
377
if ( pDir->VirtualAddress > offHdrs
378
&& pDir->VirtualAddress < cbImage
379
&& pDir->Size >= sizeof(IMAGE_DEBUG_DIRECTORY)
380
&& pDir->Size < cbImage
381
&& pDir->VirtualAddress + pDir->Size <= cbImage
384
uRvaDebugDir = pDir->VirtualAddress;
385
cbDebugDir = pDir->Size;
388
/* dig into the section table... */
394
int rc = RTDbgModCreate(&hMod, pszName, cbImage, 0 /*fFlags*/);
397
rc = RTDbgModSetTag(hMod, DIG_WINNT_MOD_TAG); AssertRC(rc);
400
rc = RTDbgModSymbolAdd(hMod, "start", 0 /*iSeg*/, 0, cbImage, 0 /*fFlags*/, NULL); AssertRC(rc);
405
* Dig out debug info if possible. What we're after is the CODEVIEW part.
407
if (uRvaDebugDir != 0)
409
DBGFADDRESS Addr = *pImageAddr;
410
DBGFR3AddrAdd(&Addr, uRvaDebugDir);
411
rc = DBGFR3MemRead(pVM, 0 /*idCpu*/, &Addr, pbBuf, RT_MIN(cbDebugDir, cbBuf));
414
IMAGE_DEBUG_DIRECTORY const *pa = (IMAGE_DEBUG_DIRECTORY const *)pbBuf;
415
size_t c = RT_MIN(RT_MIN(cbDebugDir, cbBuf) / sizeof(*pa), 10);
416
for (uint32_t i = 0; i < c; i++)
417
if ( pa[i].AddressOfRawData > offHdrs
418
&& pa[i].AddressOfRawData < cbImage
419
&& pa[i].SizeOfData < cbImage
420
&& pa[i].AddressOfRawData + pa[i].SizeOfData <= cbImage
421
&& pa[i].TimeDateStamp == TimeDateStamp /* too paranoid? */
422
&& pa[i].Type == IMAGE_DEBUG_TYPE_CODEVIEW
432
RTDBGAS hAs = DBGFR3AsResolveAndRetain(pVM, DBGF_AS_KERNEL);
433
if (hAs != NIL_RTDBGAS)
434
rc = RTDbgAsModuleLink(hAs, hMod, pImageAddr->FlatPtr, RTDBGASLINK_FLAGS_REPLACE /*fFlags*/);
436
rc = VERR_INTERNAL_ERROR;
437
RTDbgModRelease(hMod);
443
* @copydoc DBGFOSREG::pfnQueryInterface
445
static DECLCALLBACK(void *) dbgDiggerWinNtQueryInterface(PVM pVM, void *pvData, DBGFOSINTERFACE enmIf)
452
* @copydoc DBGFOSREG::pfnQueryVersion
454
static DECLCALLBACK(int) dbgDiggerWinNtQueryVersion(PVM pVM, void *pvData, char *pszVersion, size_t cchVersion)
456
PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
457
Assert(pThis->fValid);
458
const char *pszNtProductType;
459
switch (pThis->NtProductType)
461
case kNtProductType_WinNt: pszNtProductType = "-WinNT"; break;
462
case kNtProductType_LanManNt: pszNtProductType = "-LanManNT"; break;
463
case kNtProductType_Server: pszNtProductType = "-Server"; break;
464
default: pszNtProductType = ""; break;
466
RTStrPrintf(pszVersion, cchVersion, "%u.%u%s", pThis->NtMajorVersion, pThis->NtMinorVersion, pszNtProductType);
472
* @copydoc DBGFOSREG::pfnTerm
474
static DECLCALLBACK(void) dbgDiggerWinNtTerm(PVM pVM, void *pvData)
476
PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
477
Assert(pThis->fValid);
479
pThis->fValid = false;
484
* @copydoc DBGFOSREG::pfnRefresh
486
static DECLCALLBACK(int) dbgDiggerWinNtRefresh(PVM pVM, void *pvData)
488
PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
490
Assert(pThis->fValid);
493
* For now we'll flush and reload everything.
495
RTDBGAS hDbgAs = DBGFR3AsResolveAndRetain(pVM, DBGF_AS_KERNEL);
496
if (hDbgAs != NIL_RTDBGAS)
498
uint32_t iMod = RTDbgAsModuleCount(hDbgAs);
501
RTDBGMOD hMod = RTDbgAsModuleByIndex(hDbgAs, iMod);
502
if (hMod != NIL_RTDBGMOD)
504
if (RTDbgModGetTag(hMod) == DIG_WINNT_MOD_TAG)
506
int rc = RTDbgAsModuleUnlink(hDbgAs, hMod);
509
RTDbgModRelease(hMod);
512
RTDbgAsRelease(hDbgAs);
515
dbgDiggerWinNtTerm(pVM, pvData);
516
return dbgDiggerWinNtInit(pVM, pvData);
521
* @copydoc DBGFOSREG::pfnInit
523
static DECLCALLBACK(int) dbgDiggerWinNtInit(PVM pVM, void *pvData)
525
PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
526
Assert(!pThis->fValid);
531
RTUTF16 wsz[0x2000/2];
532
NTKUSERSHAREDDATA UserSharedData;
538
* Figure the NT version.
540
DBGFR3AddrFromFlat(pVM, &Addr, pThis->f32Bit ? NTKUSERSHAREDDATA_WINNT32 : NTKUSERSHAREDDATA_WINNT64);
541
rc = DBGFR3MemRead(pVM, 0 /*idCpu*/, &Addr, &u, PAGE_SIZE);
544
pThis->NtProductType = u.UserSharedData.ProductTypeIsValid && u.UserSharedData.NtProductType <= kNtProductType_Server
545
? (NTPRODUCTTYPE)u.UserSharedData.NtProductType
546
: kNtProductType_Invalid;
547
pThis->NtMajorVersion = u.UserSharedData.NtMajorVersion;
548
pThis->NtMinorVersion = u.UserSharedData.NtMinorVersion;
551
* Dig out the module chain.
553
DBGFADDRESS AddrPrev = pThis->PsLoadedModuleListAddr;
554
Addr = pThis->KernelMteAddr;
557
/* Read the validate the MTE. */
559
rc = DBGFR3MemRead(pVM, 0 /*idCpu*/, &Addr, &Mte, pThis->f32Bit ? sizeof(Mte.vX_32) : sizeof(Mte.vX_64));
562
if (WINNT_UNION(pThis, &Mte, InLoadOrderLinks.Blink) != AddrPrev.FlatPtr)
564
Log(("DigWinNt: Bad Mte At %RGv - backpointer\n", Addr.FlatPtr));
567
if (!WINNT_VALID_ADDRESS(pThis, WINNT_UNION(pThis, &Mte, InLoadOrderLinks.Flink)) )
569
Log(("DigWinNt: Bad Mte at %RGv - forward pointer\n", Addr.FlatPtr));
572
if (!WINNT_VALID_ADDRESS(pThis, WINNT_UNION(pThis, &Mte, BaseDllName.Buffer)))
574
Log(("DigWinNt: Bad Mte at %RGv - BaseDllName=%llx\n", Addr.FlatPtr, WINNT_UNION(pThis, &Mte, BaseDllName.Buffer)));
577
if (!WINNT_VALID_ADDRESS(pThis, WINNT_UNION(pThis, &Mte, FullDllName.Buffer)))
579
Log(("DigWinNt: Bad Mte at %RGv - FullDllName=%llx\n", Addr.FlatPtr, WINNT_UNION(pThis, &Mte, FullDllName.Buffer)));
582
if ( !WINNT_VALID_ADDRESS(pThis, WINNT_UNION(pThis, &Mte, DllBase))
583
|| WINNT_UNION(pThis, &Mte, SizeOfImage) > _1M*256
584
|| WINNT_UNION(pThis, &Mte, EntryPoint) - WINNT_UNION(pThis, &Mte, DllBase) > WINNT_UNION(pThis, &Mte, SizeOfImage) )
586
Log(("DigWinNt: Bad Mte at %RGv - EntryPoint=%llx SizeOfImage=%x DllBase=%llx\n",
587
Addr.FlatPtr, WINNT_UNION(pThis, &Mte, EntryPoint), WINNT_UNION(pThis, &Mte, SizeOfImage), WINNT_UNION(pThis, &Mte, DllBase)));
591
/* Read the full name. */
592
DBGFADDRESS AddrName;
593
DBGFR3AddrFromFlat(pVM, &AddrName, WINNT_UNION(pThis, &Mte, FullDllName.Buffer));
594
uint16_t cbName = WINNT_UNION(pThis, &Mte, FullDllName.Length);
595
if (cbName < sizeof(u))
596
rc = DBGFR3MemRead(pVM, 0 /*idCpu*/, &AddrName, &u, cbName);
598
rc = VERR_OUT_OF_RANGE;
601
DBGFR3AddrFromFlat(pVM, &AddrName, WINNT_UNION(pThis, &Mte, BaseDllName.Buffer));
602
cbName = WINNT_UNION(pThis, &Mte, BaseDllName.Length);
603
if (cbName < sizeof(u))
604
rc = DBGFR3MemRead(pVM, 0 /*idCpu*/, &AddrName, &u, cbName);
606
rc = VERR_OUT_OF_RANGE;
610
u.wsz[cbName/2] = '\0';
612
rc = RTUtf16ToUtf8(u.wsz, &pszName);
615
/* Read the start of the PE image and pass it along to a worker. */
616
DBGFADDRESS ImageAddr;
617
DBGFR3AddrFromFlat(pVM, &ImageAddr, WINNT_UNION(pThis, &Mte, DllBase));
618
uint32_t cbImageBuf = RT_MIN(sizeof(u), WINNT_UNION(pThis, &Mte, SizeOfImage));
619
rc = DBGFR3MemRead(pVM, 0 /*idCpu*/, &ImageAddr, &u, cbImageBuf);
621
dbgDiggerWinNtProcessImage(pThis,
625
WINNT_UNION(pThis, &Mte, SizeOfImage),
634
DBGFR3AddrFromFlat(pVM, &Addr, WINNT_UNION(pThis, &Mte, InLoadOrderLinks.Flink));
635
} while ( Addr.FlatPtr != pThis->KernelMteAddr.FlatPtr
636
&& Addr.FlatPtr != pThis->PsLoadedModuleListAddr.FlatPtr);
638
pThis->fValid = true;
644
* @copydoc DBGFOSREG::pfnProbe
646
static DECLCALLBACK(bool) dbgDiggerWinNtProbe(PVM pVM, void *pvData)
648
PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
653
uint16_t au16[8192/2];
654
uint32_t au32[8192/4];
655
IMAGE_DOS_HEADER MzHdr;
660
* Look for the MISYSPTE section name that seems to be a part of all kernels.
661
* Then try find the module table entry for it. Since it's the first entry
662
* in the PsLoadedModuleList we can easily validate the list head and report
665
CPUMMODE enmMode = DBGFR3CpuGetMode(pVM, 0 /*idCpu*/);
666
if (enmMode == CPUMMODE_LONG)
668
/** @todo when 32-bit is working, add support for 64-bit windows nt. */
672
DBGFADDRESS KernelAddr;
673
for (DBGFR3AddrFromFlat(pVM, &KernelAddr, UINT32_C(0x80001000));
674
KernelAddr.FlatPtr < UINT32_C(0xffff0000);
675
KernelAddr.FlatPtr += PAGE_SIZE)
677
int rc = DBGFR3MemScan(pVM, 0 /*idCpu*/, &KernelAddr, UINT32_C(0xffff0000) - KernelAddr.FlatPtr,
678
1, "MISYSPTE", sizeof("MISYSPTE") - 1, &KernelAddr);
681
DBGFR3AddrSub(&KernelAddr, KernelAddr.FlatPtr & PAGE_OFFSET_MASK);
683
/* MZ + PE header. */
684
rc = DBGFR3MemRead(pVM, 0 /*idCpu*/, &KernelAddr, &u, sizeof(u));
686
&& u.MzHdr.e_magic == IMAGE_DOS_SIGNATURE
687
&& !(u.MzHdr.e_lfanew & 0x7)
688
&& u.MzHdr.e_lfanew >= 0x080
689
&& u.MzHdr.e_lfanew <= 0x200)
691
IMAGE_NT_HEADERS32 const *pHdrs = (IMAGE_NT_HEADERS32 const *)&u.au8[u.MzHdr.e_lfanew];
692
if ( pHdrs->Signature == IMAGE_NT_SIGNATURE
693
&& pHdrs->FileHeader.Machine == IMAGE_FILE_MACHINE_I386
694
&& pHdrs->FileHeader.SizeOfOptionalHeader == sizeof(pHdrs->OptionalHeader)
695
&& pHdrs->FileHeader.NumberOfSections >= 10 /* the kernel has lots */
696
&& (pHdrs->FileHeader.Characteristics & (IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL)) == IMAGE_FILE_EXECUTABLE_IMAGE
697
&& pHdrs->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC
698
&& pHdrs->OptionalHeader.NumberOfRvaAndSizes == IMAGE_NUMBEROF_DIRECTORY_ENTRIES
699
/** @todo need more ntoskrnl signs? */
705
Mte.DllBase = KernelAddr.FlatPtr;
706
Mte.EntryPoint = KernelAddr.FlatPtr + pHdrs->OptionalHeader.AddressOfEntryPoint;
707
Mte.SizeOfImage = pHdrs->OptionalHeader.SizeOfImage;
709
rc = DBGFR3MemScan(pVM, 0 /*idCpu*/, &KernelAddr, UINT32_MAX - KernelAddr.FlatPtr,
710
4 /*align*/, &Mte.DllBase, 3 * sizeof(uint32_t), &HitAddr);
711
while (RT_SUCCESS(rc))
713
/* check the name. */
715
DBGFADDRESS MteAddr = HitAddr;
716
rc = DBGFR3MemRead(pVM, 0 /*idCpu*/, DBGFR3AddrSub(&MteAddr, RT_OFFSETOF(NTMTE32, DllBase)),
717
&Mte2, sizeof(Mte2));
719
&& Mte2.DllBase == Mte.DllBase
720
&& Mte2.EntryPoint == Mte.EntryPoint
721
&& Mte2.SizeOfImage == Mte.SizeOfImage
722
&& WINNT32_VALID_ADDRESS(Mte2.InLoadOrderLinks.Flink)
723
&& Mte2.InLoadOrderLinks.Blink > KernelAddr.FlatPtr /* list head inside ntoskrnl */
724
&& Mte2.InLoadOrderLinks.Blink < KernelAddr.FlatPtr + Mte.SizeOfImage
725
&& WINNT32_VALID_ADDRESS(Mte2.BaseDllName.Buffer)
726
&& WINNT32_VALID_ADDRESS(Mte2.FullDllName.Buffer)
727
&& Mte2.BaseDllName.Length <= Mte2.BaseDllName.MaximumLength
728
&& Mte2.BaseDllName.Length == WINNT_KERNEL_BASE_NAME_LEN * 2
729
&& Mte2.FullDllName.Length <= Mte2.FullDllName.MaximumLength
730
&& Mte2.FullDllName.Length <= 256
733
rc = DBGFR3MemRead(pVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pVM, &Addr, Mte2.BaseDllName.Buffer),
734
u.wsz, Mte2.BaseDllName.Length);
735
u.wsz[Mte2.BaseDllName.Length / 2] = '\0';
737
&& ( !RTUtf16ICmp(u.wsz, g_wszKernelNames[0])
738
/* || !RTUtf16ICmp(u.wsz, g_wszKernelNames[1]) */
743
rc = DBGFR3MemRead(pVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pVM, &Addr, Mte2.InLoadOrderLinks.Blink),
744
&Mte3, RT_SIZEOFMEMB(NTMTE32, InLoadOrderLinks));
746
&& Mte3.InLoadOrderLinks.Flink == MteAddr.FlatPtr
747
&& WINNT32_VALID_ADDRESS(Mte3.InLoadOrderLinks.Blink) )
749
Log(("DigWinNt: MteAddr=%RGv KernelAddr=%RGv SizeOfImage=%x &PsLoadedModuleList=%RGv (32-bit)\n",
750
MteAddr.FlatPtr, KernelAddr.FlatPtr, Mte2.SizeOfImage, Addr.FlatPtr));
751
pThis->KernelAddr = KernelAddr;
752
pThis->KernelMteAddr = MteAddr;
753
pThis->PsLoadedModuleListAddr = Addr;
754
pThis->f32Bit = true;
761
DBGFR3AddrAdd(&HitAddr, 4);
762
if (HitAddr.FlatPtr <= UINT32_C(0xfffff000))
763
rc = DBGFR3MemScan(pVM, 0 /*idCpu*/, &HitAddr, UINT32_MAX - HitAddr.FlatPtr,
764
4 /*align*/, &Mte.DllBase, 3 * sizeof(uint32_t), &HitAddr);
766
rc = VERR_DBGF_MEM_NOT_FOUND;
777
* @copydoc DBGFOSREG::pfnDestruct
779
static DECLCALLBACK(void) dbgDiggerWinNtDestruct(PVM pVM, void *pvData)
786
* @copydoc DBGFOSREG::pfnConstruct
788
static DECLCALLBACK(int) dbgDiggerWinNtConstruct(PVM pVM, void *pvData)
790
PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
791
pThis->fValid = false;
792
pThis->f32Bit = false;
793
pThis->enmVer = DBGDIGGERWINNTVER_UNKNOWN;
798
const DBGFOSREG g_DBGDiggerWinNt =
800
/* .u32Magic = */ DBGFOSREG_MAGIC,
802
/* .cbData = */ sizeof(DBGDIGGERWINNT),
803
/* .szName = */ "WinNT",
804
/* .pfnConstruct = */ dbgDiggerWinNtConstruct,
805
/* .pfnDestruct = */ dbgDiggerWinNtDestruct,
806
/* .pfnProbe = */ dbgDiggerWinNtProbe,
807
/* .pfnInit = */ dbgDiggerWinNtInit,
808
/* .pfnRefresh = */ dbgDiggerWinNtRefresh,
809
/* .pfnTerm = */ dbgDiggerWinNtTerm,
810
/* .pfnQueryVersion = */ dbgDiggerWinNtQueryVersion,
811
/* .pfnQueryInterface = */ dbgDiggerWinNtQueryInterface,
812
/* .u32EndMagic = */ DBGFOSREG_MAGIC