VirtualBox

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

Last change on this file since 45238 was 44528, checked in by vboxsync, 12 years ago

header (C) fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.0 KB
Line 
1/* $Id: DBGPlugInWinNt.cpp 44528 2013-02-04 14:27:54Z vboxsync $ */
2/** @file
3 * DBGPlugInWindows - Debugger and Guest OS Digger Plugin For Windows NT.
4 */
5
6/*
7 * Copyright (C) 2009-2013 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/string.h>
28#include <iprt/mem.h>
29#include <iprt/stream.h>
30
31#include "../Runtime/include/internal/ldrMZ.h" /* ugly */
32#include "../Runtime/include/internal/ldrPE.h" /* ugly */
33
34
35/*******************************************************************************
36* Structures and Typedefs *
37*******************************************************************************/
38
39/** @name Internal WinNT structures
40 * @{ */
41/**
42 * PsLoadedModuleList entry for 32-bit NT aka LDR_DATA_TABLE_ENTRY.
43 * Tested with XP.
44 */
45typedef struct NTMTE32
46{
47 struct
48 {
49 uint32_t Flink;
50 uint32_t Blink;
51 } InLoadOrderLinks,
52 InMemoryOrderModuleList,
53 InInitializationOrderModuleList;
54 uint32_t DllBase;
55 uint32_t EntryPoint;
56 uint32_t SizeOfImage;
57 struct
58 {
59 uint16_t Length;
60 uint16_t MaximumLength;
61 uint32_t Buffer;
62 } FullDllName,
63 BaseDllName;
64 uint32_t Flags;
65 uint16_t LoadCount;
66 uint16_t TlsIndex;
67 /* ... there is more ... */
68} NTMTE32;
69typedef NTMTE32 *PNTMTE32;
70
71/**
72 * PsLoadedModuleList entry for 32-bit NT aka LDR_DATA_TABLE_ENTRY.
73 * Tested with XP.
74 *
75 * @todo This is incomplete and just to get rid of warnings.
76 */
77typedef struct NTMTE64
78{
79 struct
80 {
81 uint64_t Flink;
82 uint64_t Blink;
83 } InLoadOrderLinks,
84 InMemoryOrderModuleList,
85 InInitializationOrderModuleList;
86 uint64_t DllBase;
87 uint64_t EntryPoint;
88 uint32_t SizeOfImage;
89 uint32_t Alignment;
90 struct
91 {
92 uint16_t Length;
93 uint16_t MaximumLength;
94 uint32_t Alignment;
95 uint64_t Buffer;
96 } FullDllName,
97 BaseDllName;
98 uint32_t Flags;
99 uint16_t LoadCount;
100 uint16_t TlsIndex;
101 /* ... there is more ... */
102} NTMTE64;
103typedef NTMTE64 *PNTMTE64;
104
105/** MTE union. */
106typedef union NTMTE
107{
108 NTMTE32 vX_32;
109 NTMTE64 vX_64;
110} NTMTE;
111typedef NTMTE *PNTMTE;
112
113
114/**
115 * The essential bits of the KUSER_SHARED_DATA structure.
116 */
117typedef struct NTKUSERSHAREDDATA
118{
119 uint32_t TickCountLowDeprecated;
120 uint32_t TickCountMultiplier;
121 struct
122 {
123 uint32_t LowPart;
124 int32_t High1Time;
125 int32_t High2Time;
126
127 } InterruptTime,
128 SystemTime,
129 TimeZoneBias;
130 uint16_t ImageNumberLow;
131 uint16_t ImageNumberHigh;
132 RTUTF16 NtSystemRoot[260];
133 uint32_t MaxStackTraceDepth;
134 uint32_t CryptoExponent;
135 uint32_t TimeZoneId;
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];
144 ...
145 */
146} NTKUSERSHAREDDATA;
147typedef NTKUSERSHAREDDATA *PNTKUSERSHAREDDATA;
148
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)
153
154/** NTKUSERSHAREDDATA::NtProductType */
155typedef enum NTPRODUCTTYPE
156{
157 kNtProductType_Invalid = 0,
158 kNtProductType_WinNt = 1,
159 kNtProductType_LanManNt,
160 kNtProductType_Server
161} NTPRODUCTTYPE;
162
163/**
164 * PDB v2.0 in image debug info.
165 * The URL is constructed from the timestamp and the %02x age?
166 */
167typedef struct CV_INFO_PDB20
168{
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;
172 uint32_t Age;
173 uint8_t PdbFilename[4];
174} CV_INFO_PDB20;
175/** The CV_INFO_PDB20 signature. */
176#define CV_SIGNATURE_PDB20 RT_MAKE_U32_FROM_U8('N','B','1','0')
177
178/**
179 * PDB v7.0 in image debug info.
180 * The URL is constructed from the signature and the %02x age.
181 */
182#pragma pack(4)
183typedef struct CV_INFO_PDB70
184{
185 uint32_t CvSignature; /**< CV_SIGNATURE_PDB70. */
186 RTUUID Signature;
187 uint32_t Age;
188 uint8_t PdbFilename[4];
189} CV_INFO_PDB70;
190#pragma pack()
191AssertCompileMemberOffset(CV_INFO_PDB70, Signature, 4);
192AssertCompileMemberOffset(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')
195
196/** @} */
197
198
199typedef enum DBGDIGGERWINNTVER
200{
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
208} DBGDIGGERWINNTVER;
209
210/**
211 * WinNT guest OS digger instance data.
212 */
213typedef struct DBGDIGGERWINNT
214{
215 /** Whether the information is valid or not.
216 * (For fending off illegal interface method calls.) */
217 bool fValid;
218 /** 32-bit (true) or 64-bit (false) */
219 bool f32Bit;
220
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;
229
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;
236} DBGDIGGERWINNT;
237/** Pointer to the linux guest OS digger instance data. */
238typedef DBGDIGGERWINNT *PDBGDIGGERWINNT;
239
240
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 )
252
253/** The length (in chars) of the kernel file name (no path). */
254#define WINNT_KERNEL_BASE_NAME_LEN 12
255
256/** WindowsNT on little endian ASCII systems. */
257#define DIG_WINNT_MOD_TAG UINT64_C(0x54696e646f774e54)
258
259
260/*******************************************************************************
261* Internal Functions *
262*******************************************************************************/
263static DECLCALLBACK(int) dbgDiggerWinNtInit(PUVM pUVM, void *pvData);
264
265
266/*******************************************************************************
267* Global Variables *
268*******************************************************************************/
269/** Kernel names. */
270static const RTUTF16 g_wszKernelNames[][WINNT_KERNEL_BASE_NAME_LEN + 1] =
271{
272 { 'n', 't', 'o', 's', 'k', 'r', 'n', 'l', '.', 'e', 'x', 'e' }
273};
274
275
276/**
277 * Process a PE image found in guest memory.
278 *
279 * @param pThis The instance data.
280 * @param pUVM The user mode 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.
287 */
288static void dbgDiggerWinNtProcessImage(PDBGDIGGERWINNT pThis, PUVM pUVM, const char *pszName,
289 PCDBGFADDRESS pImageAddr, uint32_t cbImage,
290 uint8_t *pbBuf, size_t cbBuf)
291{
292 LogFlow(("DigWinNt: %RGp %#x %s\n", pImageAddr->FlatPtr, cbImage, pszName));
293
294 /*
295 * Do some basic validation first.
296 * This is the usual exteremely verbose and messy code...
297 */
298 Assert(cbBuf >= sizeof(IMAGE_NT_HEADERS64));
299 if ( cbImage < sizeof(IMAGE_NT_HEADERS64)
300 || cbImage >= _1M * 256)
301 {
302 Log(("DigWinNt: %s: Bad image size: %#x\n", pszName, cbImage));
303 return;
304 }
305
306 /* Dig out the NT/PE headers. */
307 IMAGE_DOS_HEADER const *pMzHdr = (IMAGE_DOS_HEADER const *)pbBuf;
308 typedef union NTHDRSU
309 {
310 IMAGE_NT_HEADERS64 vX_32;
311 IMAGE_NT_HEADERS64 vX_64;
312 } NTHDRS;
313 NTHDRS const *pHdrs;
314 uint32_t offHdrs;
315 if (pMzHdr->e_magic != IMAGE_DOS_SIGNATURE)
316 {
317 offHdrs = 0;
318 pHdrs = (NTHDRS const *)pbBuf;
319 }
320 else if ( pMzHdr->e_lfanew >= cbImage
321 || pMzHdr->e_lfanew < sizeof(*pMzHdr)
322 || pMzHdr->e_lfanew + sizeof(IMAGE_NT_HEADERS64) > cbImage)
323 {
324 Log(("DigWinNt: %s: PE header to far into image: %#x cbImage=%#x\n", pMzHdr->e_lfanew, cbImage));
325 return;
326 }
327 else if ( pMzHdr->e_lfanew < cbBuf
328 && pMzHdr->e_lfanew + sizeof(IMAGE_NT_HEADERS64) <= cbBuf)
329 {
330 offHdrs = pMzHdr->e_lfanew;
331 pHdrs = (NTHDRS const *)(pbBuf + offHdrs);
332 }
333 else
334 {
335 Log(("DigWinNt: %s: PE header to far into image (lazy bird): %#x\n", pMzHdr->e_lfanew));
336 return;
337 }
338 if (pHdrs->vX_32.Signature != IMAGE_NT_SIGNATURE)
339 {
340 Log(("DigWinNt: %s: Bad PE signature: %#x\n", pszName, pHdrs->vX_32.Signature));
341 return;
342 }
343
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))
346 {
347 Log(("DigWinNt: %s: Invalid FH.Machine: %#x\n", pszName, pHdrs->vX_32.FileHeader.Machine));
348 return;
349 }
350 if (pHdrs->vX_32.FileHeader.SizeOfOptionalHeader != (pThis->f32Bit ? sizeof(IMAGE_OPTIONAL_HEADER32) : sizeof(IMAGE_OPTIONAL_HEADER64)))
351 {
352 Log(("DigWinNt: %s: Invalid FH.SizeOfOptionalHeader: %#x\n", pszName, pHdrs->vX_32.FileHeader.SizeOfOptionalHeader));
353 return;
354 }
355 const uint32_t TimeDateStamp = pHdrs->vX_32.FileHeader.TimeDateStamp;
356
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))
359 {
360 Log(("DigWinNt: %s: Invalid OH.Magic: %#x\n", pszName, WINNT_UNION(pThis, pHdrs, OptionalHeader.Magic)));
361 return;
362 }
363 if (WINNT_UNION(pThis, pHdrs, OptionalHeader.SizeOfImage) != cbImage)
364 {
365 Log(("DigWinNt: %s: Invalid OH.SizeOfImage: %#x, expected %#x\n", pszName, WINNT_UNION(pThis, pHdrs, OptionalHeader.SizeOfImage), cbImage));
366 return;
367 }
368 if (WINNT_UNION(pThis, pHdrs, OptionalHeader.NumberOfRvaAndSizes) != IMAGE_NUMBEROF_DIRECTORY_ENTRIES)
369 {
370 Log(("DigWinNt: %s: Invalid OH.SizeOfImage: %#x\n", pszName, WINNT_UNION(pThis, pHdrs, OptionalHeader.NumberOfRvaAndSizes)));
371 return;
372 }
373
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
382 )
383 {
384 uRvaDebugDir = pDir->VirtualAddress;
385 cbDebugDir = pDir->Size;
386 }
387
388 /* dig into the section table... */
389
390 /*
391 * Create the module.
392 */
393 RTDBGMOD hMod;
394 int rc = RTDbgModCreate(&hMod, pszName, cbImage, 0 /*fFlags*/);
395 if (RT_FAILURE(rc))
396 return;
397 rc = RTDbgModSetTag(hMod, DIG_WINNT_MOD_TAG); AssertRC(rc);
398
399 /* temp hack: */
400 rc = RTDbgModSymbolAdd(hMod, "start", 0 /*iSeg*/, 0, cbImage, 0 /*fFlags*/, NULL); AssertRC(rc);
401
402 /* add sections? */
403
404 /*
405 * Dig out debug info if possible. What we're after is the CODEVIEW part.
406 */
407 if (uRvaDebugDir != 0)
408 {
409 DBGFADDRESS Addr = *pImageAddr;
410 DBGFR3AddrAdd(&Addr, uRvaDebugDir);
411 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &Addr, pbBuf, RT_MIN(cbDebugDir, cbBuf));
412 if (RT_SUCCESS(rc))
413 {
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
423 )
424 {
425 }
426 }
427 }
428
429 /*
430 * Link the module.
431 */
432 RTDBGAS hAs = DBGFR3AsResolveAndRetain(pUVM, DBGF_AS_KERNEL);
433 if (hAs != NIL_RTDBGAS)
434 rc = RTDbgAsModuleLink(hAs, hMod, pImageAddr->FlatPtr, RTDBGASLINK_FLAGS_REPLACE /*fFlags*/);
435 else
436 rc = VERR_INTERNAL_ERROR;
437 RTDbgModRelease(hMod);
438 RTDbgAsRelease(hAs);
439}
440
441
442/**
443 * @copydoc DBGFOSREG::pfnQueryInterface
444 */
445static DECLCALLBACK(void *) dbgDiggerWinNtQueryInterface(PUVM pUVM, void *pvData, DBGFOSINTERFACE enmIf)
446{
447 return NULL;
448}
449
450
451/**
452 * @copydoc DBGFOSREG::pfnQueryVersion
453 */
454static DECLCALLBACK(int) dbgDiggerWinNtQueryVersion(PUVM pUVM, void *pvData, char *pszVersion, size_t cchVersion)
455{
456 PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
457 Assert(pThis->fValid);
458 const char *pszNtProductType;
459 switch (pThis->NtProductType)
460 {
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;
465 }
466 RTStrPrintf(pszVersion, cchVersion, "%u.%u%s", pThis->NtMajorVersion, pThis->NtMinorVersion, pszNtProductType);
467 return VINF_SUCCESS;
468}
469
470
471/**
472 * @copydoc DBGFOSREG::pfnTerm
473 */
474static DECLCALLBACK(void) dbgDiggerWinNtTerm(PUVM pUVM, void *pvData)
475{
476 PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
477 Assert(pThis->fValid);
478
479 pThis->fValid = false;
480}
481
482
483/**
484 * @copydoc DBGFOSREG::pfnRefresh
485 */
486static DECLCALLBACK(int) dbgDiggerWinNtRefresh(PUVM pUVM, void *pvData)
487{
488 PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
489 NOREF(pThis);
490 Assert(pThis->fValid);
491
492 /*
493 * For now we'll flush and reload everything.
494 */
495 RTDBGAS hDbgAs = DBGFR3AsResolveAndRetain(pUVM, DBGF_AS_KERNEL);
496 if (hDbgAs != NIL_RTDBGAS)
497 {
498 uint32_t iMod = RTDbgAsModuleCount(hDbgAs);
499 while (iMod-- > 0)
500 {
501 RTDBGMOD hMod = RTDbgAsModuleByIndex(hDbgAs, iMod);
502 if (hMod != NIL_RTDBGMOD)
503 {
504 if (RTDbgModGetTag(hMod) == DIG_WINNT_MOD_TAG)
505 {
506 int rc = RTDbgAsModuleUnlink(hDbgAs, hMod);
507 AssertRC(rc);
508 }
509 RTDbgModRelease(hMod);
510 }
511 }
512 RTDbgAsRelease(hDbgAs);
513 }
514
515 dbgDiggerWinNtTerm(pUVM, pvData);
516 return dbgDiggerWinNtInit(pUVM, pvData);
517}
518
519
520/**
521 * @copydoc DBGFOSREG::pfnInit
522 */
523static DECLCALLBACK(int) dbgDiggerWinNtInit(PUVM pUVM, void *pvData)
524{
525 PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
526 Assert(!pThis->fValid);
527
528 union
529 {
530 uint8_t au8[0x2000];
531 RTUTF16 wsz[0x2000/2];
532 NTKUSERSHAREDDATA UserSharedData;
533 } u;
534 DBGFADDRESS Addr;
535 int rc;
536
537 /*
538 * Figure the NT version.
539 */
540 DBGFR3AddrFromFlat(pUVM, &Addr, pThis->f32Bit ? NTKUSERSHAREDDATA_WINNT32 : NTKUSERSHAREDDATA_WINNT64);
541 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &Addr, &u, PAGE_SIZE);
542 if (RT_FAILURE(rc))
543 return rc;
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;
549
550 /*
551 * Dig out the module chain.
552 */
553 DBGFADDRESS AddrPrev = pThis->PsLoadedModuleListAddr;
554 Addr = pThis->KernelMteAddr;
555 do
556 {
557 /* Read the validate the MTE. */
558 NTMTE Mte;
559 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &Addr, &Mte, pThis->f32Bit ? sizeof(Mte.vX_32) : sizeof(Mte.vX_64));
560 if (RT_FAILURE(rc))
561 break;
562 if (WINNT_UNION(pThis, &Mte, InLoadOrderLinks.Blink) != AddrPrev.FlatPtr)
563 {
564 Log(("DigWinNt: Bad Mte At %RGv - backpointer\n", Addr.FlatPtr));
565 break;
566 }
567 if (!WINNT_VALID_ADDRESS(pThis, WINNT_UNION(pThis, &Mte, InLoadOrderLinks.Flink)) )
568 {
569 Log(("DigWinNt: Bad Mte at %RGv - forward pointer\n", Addr.FlatPtr));
570 break;
571 }
572 if (!WINNT_VALID_ADDRESS(pThis, WINNT_UNION(pThis, &Mte, BaseDllName.Buffer)))
573 {
574 Log(("DigWinNt: Bad Mte at %RGv - BaseDllName=%llx\n", Addr.FlatPtr, WINNT_UNION(pThis, &Mte, BaseDllName.Buffer)));
575 break;
576 }
577 if (!WINNT_VALID_ADDRESS(pThis, WINNT_UNION(pThis, &Mte, FullDllName.Buffer)))
578 {
579 Log(("DigWinNt: Bad Mte at %RGv - FullDllName=%llx\n", Addr.FlatPtr, WINNT_UNION(pThis, &Mte, FullDllName.Buffer)));
580 break;
581 }
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) )
585 {
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)));
588 break;
589 }
590
591 /* Read the full name. */
592 DBGFADDRESS AddrName;
593 DBGFR3AddrFromFlat(pUVM, &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(pUVM, 0 /*idCpu*/, &AddrName, &u, cbName);
597 else
598 rc = VERR_OUT_OF_RANGE;
599 if (RT_FAILURE(rc))
600 {
601 DBGFR3AddrFromFlat(pUVM, &AddrName, WINNT_UNION(pThis, &Mte, BaseDllName.Buffer));
602 cbName = WINNT_UNION(pThis, &Mte, BaseDllName.Length);
603 if (cbName < sizeof(u))
604 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &AddrName, &u, cbName);
605 else
606 rc = VERR_OUT_OF_RANGE;
607 }
608 if (RT_SUCCESS(rc))
609 {
610 u.wsz[cbName/2] = '\0';
611 char *pszName;
612 rc = RTUtf16ToUtf8(u.wsz, &pszName);
613 if (RT_SUCCESS(rc))
614 {
615 /* Read the start of the PE image and pass it along to a worker. */
616 DBGFADDRESS ImageAddr;
617 DBGFR3AddrFromFlat(pUVM, &ImageAddr, WINNT_UNION(pThis, &Mte, DllBase));
618 uint32_t cbImageBuf = RT_MIN(sizeof(u), WINNT_UNION(pThis, &Mte, SizeOfImage));
619 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &ImageAddr, &u, cbImageBuf);
620 if (RT_SUCCESS(rc))
621 dbgDiggerWinNtProcessImage(pThis,
622 pUVM,
623 pszName,
624 &ImageAddr,
625 WINNT_UNION(pThis, &Mte, SizeOfImage),
626 &u.au8[0],
627 sizeof(u));
628 RTStrFree(pszName);
629 }
630 }
631
632 /* next */
633 AddrPrev = Addr;
634 DBGFR3AddrFromFlat(pUVM, &Addr, WINNT_UNION(pThis, &Mte, InLoadOrderLinks.Flink));
635 } while ( Addr.FlatPtr != pThis->KernelMteAddr.FlatPtr
636 && Addr.FlatPtr != pThis->PsLoadedModuleListAddr.FlatPtr);
637
638 pThis->fValid = true;
639 return VINF_SUCCESS;
640}
641
642
643/**
644 * @copydoc DBGFOSREG::pfnProbe
645 */
646static DECLCALLBACK(bool) dbgDiggerWinNtProbe(PUVM pUVM, void *pvData)
647{
648 PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
649 DBGFADDRESS Addr;
650 union
651 {
652 uint8_t au8[8192];
653 uint16_t au16[8192/2];
654 uint32_t au32[8192/4];
655 IMAGE_DOS_HEADER MzHdr;
656 RTUTF16 wsz[8192/2];
657 } u;
658
659 /*
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
663 * success.
664 */
665 CPUMMODE enmMode = DBGFR3CpuGetMode(pUVM, 0 /*idCpu*/);
666 if (enmMode == CPUMMODE_LONG)
667 {
668 /** @todo when 32-bit is working, add support for 64-bit windows nt. */
669 }
670 else
671 {
672 DBGFADDRESS KernelAddr;
673 for (DBGFR3AddrFromFlat(pUVM, &KernelAddr, UINT32_C(0x80001000));
674 KernelAddr.FlatPtr < UINT32_C(0xffff0000);
675 KernelAddr.FlatPtr += PAGE_SIZE)
676 {
677 int rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &KernelAddr, UINT32_C(0xffff0000) - KernelAddr.FlatPtr,
678 1, "MISYSPTE", sizeof("MISYSPTE") - 1, &KernelAddr);
679 if (RT_FAILURE(rc))
680 break;
681 DBGFR3AddrSub(&KernelAddr, KernelAddr.FlatPtr & PAGE_OFFSET_MASK);
682
683 /* MZ + PE header. */
684 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &KernelAddr, &u, sizeof(u));
685 if ( RT_SUCCESS(rc)
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)
690 {
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? */
700 )
701 {
702 /* Find the MTE. */
703 NTMTE32 Mte;
704 RT_ZERO(Mte);
705 Mte.DllBase = KernelAddr.FlatPtr;
706 Mte.EntryPoint = KernelAddr.FlatPtr + pHdrs->OptionalHeader.AddressOfEntryPoint;
707 Mte.SizeOfImage = pHdrs->OptionalHeader.SizeOfImage;
708 DBGFADDRESS HitAddr;
709 rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &KernelAddr, UINT32_MAX - KernelAddr.FlatPtr,
710 4 /*align*/, &Mte.DllBase, 3 * sizeof(uint32_t), &HitAddr);
711 while (RT_SUCCESS(rc))
712 {
713 /* check the name. */
714 NTMTE32 Mte2;
715 DBGFADDRESS MteAddr = HitAddr;
716 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrSub(&MteAddr, RT_OFFSETOF(NTMTE32, DllBase)),
717 &Mte2, sizeof(Mte2));
718 if ( RT_SUCCESS(rc)
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
731 )
732 {
733 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pUVM, &Addr, Mte2.BaseDllName.Buffer),
734 u.wsz, Mte2.BaseDllName.Length);
735 u.wsz[Mte2.BaseDllName.Length / 2] = '\0';
736 if ( RT_SUCCESS(rc)
737 && ( !RTUtf16ICmp(u.wsz, g_wszKernelNames[0])
738 /* || !RTUtf16ICmp(u.wsz, g_wszKernelNames[1]) */
739 )
740 )
741 {
742 NTMTE32 Mte3;
743 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pUVM, &Addr, Mte2.InLoadOrderLinks.Blink),
744 &Mte3, RT_SIZEOFMEMB(NTMTE32, InLoadOrderLinks));
745 if ( RT_SUCCESS(rc)
746 && Mte3.InLoadOrderLinks.Flink == MteAddr.FlatPtr
747 && WINNT32_VALID_ADDRESS(Mte3.InLoadOrderLinks.Blink) )
748 {
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;
755 return true;
756 }
757 }
758 }
759
760 /* next */
761 DBGFR3AddrAdd(&HitAddr, 4);
762 if (HitAddr.FlatPtr <= UINT32_C(0xfffff000))
763 rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &HitAddr, UINT32_MAX - HitAddr.FlatPtr,
764 4 /*align*/, &Mte.DllBase, 3 * sizeof(uint32_t), &HitAddr);
765 else
766 rc = VERR_DBGF_MEM_NOT_FOUND;
767 }
768 }
769 }
770 }
771 }
772 return false;
773}
774
775
776/**
777 * @copydoc DBGFOSREG::pfnDestruct
778 */
779static DECLCALLBACK(void) dbgDiggerWinNtDestruct(PUVM pUVM, void *pvData)
780{
781
782}
783
784
785/**
786 * @copydoc DBGFOSREG::pfnConstruct
787 */
788static DECLCALLBACK(int) dbgDiggerWinNtConstruct(PUVM pUVM, void *pvData)
789{
790 PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData;
791 pThis->fValid = false;
792 pThis->f32Bit = false;
793 pThis->enmVer = DBGDIGGERWINNTVER_UNKNOWN;
794 return VINF_SUCCESS;
795}
796
797
798const DBGFOSREG g_DBGDiggerWinNt =
799{
800 /* .u32Magic = */ DBGFOSREG_MAGIC,
801 /* .fFlags = */ 0,
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
813};
814
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