diff options
Diffstat (limited to 'src/VBox/Debugger/DBGPlugInWinNt.cpp')
-rw-r--r-- | src/VBox/Debugger/DBGPlugInWinNt.cpp | 767 |
1 files changed, 567 insertions, 200 deletions
diff --git a/src/VBox/Debugger/DBGPlugInWinNt.cpp b/src/VBox/Debugger/DBGPlugInWinNt.cpp index 503bc48a..be61017d 100644 --- a/src/VBox/Debugger/DBGPlugInWinNt.cpp +++ b/src/VBox/Debugger/DBGPlugInWinNt.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2009-2010 Oracle Corporation + * Copyright (C) 2009-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -24,9 +24,10 @@ #include <VBox/vmm/dbgf.h> #include <VBox/err.h> #include <VBox/param.h> -#include <iprt/string.h> +#include <iprt/ldr.h> #include <iprt/mem.h> #include <iprt/stream.h> +#include <iprt/string.h> #include "../Runtime/include/internal/ldrMZ.h" /* ugly */ #include "../Runtime/include/internal/ldrPE.h" /* ugly */ @@ -80,24 +81,24 @@ typedef struct NTMTE64 { uint64_t Flink; uint64_t Blink; - } InLoadOrderLinks, - InMemoryOrderModuleList, - InInitializationOrderModuleList; - uint64_t DllBase; - uint64_t EntryPoint; - uint32_t SizeOfImage; - uint32_t Alignment; + } InLoadOrderLinks, /**< 0x00 */ + InMemoryOrderModuleList, /**< 0x10 */ + InInitializationOrderModuleList; /**< 0x20 */ + uint64_t DllBase; /**< 0x30 */ + uint64_t EntryPoint; /**< 0x38 */ + uint32_t SizeOfImage; /**< 0x40 */ + uint32_t Alignment; /**< 0x44 */ struct { - uint16_t Length; - uint16_t MaximumLength; - uint32_t Alignment; - uint64_t Buffer; - } FullDllName, - BaseDllName; - uint32_t Flags; - uint16_t LoadCount; - uint16_t TlsIndex; + uint16_t Length; /**< 0x48,0x58 */ + uint16_t MaximumLength; /**< 0x4a,0x5a */ + uint32_t Alignment; /**< 0x4c,0x5c */ + uint64_t Buffer; /**< 0x50,0x60 */ + } FullDllName, /**< 0x48 */ + BaseDllName; /**< 0x58 */ + uint32_t Flags; /**< 0x68 */ + uint16_t LoadCount; /**< 0x6c */ + uint16_t TlsIndex; /**< 0x6e */ /* ... there is more ... */ } NTMTE64; typedef NTMTE64 *PNTMTE64; @@ -160,42 +161,22 @@ typedef enum NTPRODUCTTYPE kNtProductType_Server } NTPRODUCTTYPE; -/** - * PDB v2.0 in image debug info. - * The URL is constructed from the timestamp and the %02x age? - */ -typedef struct CV_INFO_PDB20 -{ - uint32_t Signature; /**< CV_SIGNATURE_PDB70. */ - int32_t Offset; /**< Always 0. Used to be the offset to the real debug info. */ - uint32_t TimeDateStamp; - uint32_t Age; - uint8_t PdbFilename[4]; -} CV_INFO_PDB20; -/** The CV_INFO_PDB20 signature. */ -#define CV_SIGNATURE_PDB20 RT_MAKE_U32_FROM_U8('N','B','1','0') -/** - * PDB v7.0 in image debug info. - * The URL is constructed from the signature and the %02x age. - */ -#pragma pack(4) -typedef struct CV_INFO_PDB70 +/** NT image header union. */ +typedef union NTHDRSU { - uint32_t CvSignature; /**< CV_SIGNATURE_PDB70. */ - RTUUID Signature; - uint32_t Age; - uint8_t PdbFilename[4]; -} CV_INFO_PDB70; -#pragma pack() -AssertCompileMemberOffset(CV_INFO_PDB70, Signature, 4); -AssertCompileMemberOffset(CV_INFO_PDB70, Age, 4 + 16); -/** The CV_INFO_PDB70 signature. */ -#define CV_SIGNATURE_PDB70 RT_MAKE_U32_FROM_U8('R','S','D','S') + IMAGE_NT_HEADERS32 vX_32; + IMAGE_NT_HEADERS64 vX_64; +} NTHDRS; +/** Pointer to NT image header union. */ +typedef NTHDRS *PNTHDRS; +/** Pointer to const NT image header union. */ +typedef NTHDRS const *PCNTHDRS; /** @} */ + typedef enum DBGDIGGERWINNTVER { DBGDIGGERWINNTVER_UNKNOWN, @@ -238,13 +219,48 @@ typedef struct DBGDIGGERWINNT typedef DBGDIGGERWINNT *PDBGDIGGERWINNT; +/** + * The WinNT digger's loader reader instance data. + */ +typedef struct DBGDIGGERWINNTRDR +{ + /** The VM handle (referenced). */ + PUVM pUVM; + /** The image base. */ + DBGFADDRESS ImageAddr; + /** The image size. */ + uint32_t cbImage; + /** The file offset of the SizeOfImage field in the optional header if it + * needs patching, otherwise set to UINT32_MAX. */ + uint32_t offSizeOfImage; + /** The correct image size. */ + uint32_t cbCorrectImageSize; + /** Number of entries in the aMappings table. */ + uint32_t cMappings; + /** Mapping hint. */ + uint32_t iHint; + /** Mapping file offset to memory offsets, ordered by file offset. */ + struct + { + /** The file offset. */ + uint32_t offFile; + /** The size of this mapping. */ + uint32_t cbMem; + /** The offset to the memory from the start of the image. */ + uint32_t offMem; + } aMappings[1]; +} DBGDIGGERWINNTRDR; +/** Pointer a WinNT loader reader instance data. */ +typedef DBGDIGGERWINNTRDR *PDBGDIGGERWINNTRDR; + + /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** Validates a 32-bit Windows NT kernel address */ #define WINNT32_VALID_ADDRESS(Addr) ((Addr) > UINT32_C(0x80000000) && (Addr) < UINT32_C(0xfffff000)) /** Validates a 64-bit Windows NT kernel address */ -#define WINNT64_VALID_ADDRESS(Addr) ((Addr) > UINT64_C(0xffffffff80000000) && (Addr) < UINT64_C(0xfffffffffffff000)) + #define WINNT64_VALID_ADDRESS(Addr) ((Addr) > UINT64_C(0xffff800000000000) && (Addr) < UINT64_C(0xfffffffffffff000)) /** Validates a kernel address. */ #define WINNT_VALID_ADDRESS(pThis, Addr) ((pThis)->f32Bit ? WINNT32_VALID_ADDRESS(Addr) : WINNT64_VALID_ADDRESS(Addr)) /** Versioned and bitness wrapper. */ @@ -260,7 +276,7 @@ typedef DBGDIGGERWINNT *PDBGDIGGERWINNT; /******************************************************************************* * Internal Functions * *******************************************************************************/ -static DECLCALLBACK(int) dbgDiggerWinNtInit(PVM pVM, void *pvData); +static DECLCALLBACK(int) dbgDiggerWinNtInit(PUVM pUVM, void *pvData); /******************************************************************************* @@ -273,19 +289,308 @@ static const RTUTF16 g_wszKernelNames[][WINNT_KERNEL_BASE_NAME_LEN + 1] = }; + +/** @callback_method_impl{PFNRTLDRRDRMEMREAD} */ +static DECLCALLBACK(int) dbgDiggerWinNtRdr_Read(void *pvBuf, size_t cb, size_t off, void *pvUser) +{ + PDBGDIGGERWINNTRDR pThis = (PDBGDIGGERWINNTRDR)pvUser; + uint32_t offFile = (uint32_t)off; + AssertReturn(offFile == off, VERR_INVALID_PARAMETER); + + uint32_t i = pThis->iHint; + if (pThis->aMappings[i].offFile > offFile) + { + i = pThis->cMappings; + while (i-- > 0) + if (offFile >= pThis->aMappings[i].offFile) + break; + pThis->iHint = i; + } + + while (cb > 0) + { + uint32_t offNextMap = i + 1 < pThis->cMappings ? pThis->aMappings[i + 1].offFile : pThis->cbImage; + uint32_t offMap = offFile - pThis->aMappings[i].offFile; + + /* Read file bits backed by memory. */ + if (offMap < pThis->aMappings[i].cbMem) + { + uint32_t cbToRead = pThis->aMappings[i].cbMem - offMap; + if (cbToRead > cb) + cbToRead = (uint32_t)cb; + + DBGFADDRESS Addr = pThis->ImageAddr; + DBGFR3AddrAdd(&Addr, pThis->aMappings[i].offMem + offMap); + + int rc = DBGFR3MemRead(pThis->pUVM, 0 /*idCpu*/, &Addr, pvBuf, cbToRead); + if (RT_FAILURE(rc)) + return rc; + + /* Apply SizeOfImage patch? */ + if ( pThis->offSizeOfImage != UINT32_MAX + && offFile < pThis->offSizeOfImage + 4 + && offFile + cbToRead > pThis->offSizeOfImage) + { + uint32_t SizeOfImage = pThis->cbCorrectImageSize; + uint32_t cbPatch = sizeof(SizeOfImage); + int32_t offPatch = pThis->offSizeOfImage - offFile; + uint8_t *pbPatch = (uint8_t *)pvBuf + offPatch; + if (offFile + cbToRead < pThis->offSizeOfImage + cbPatch) + cbPatch = offFile + cbToRead - pThis->offSizeOfImage; + while (cbPatch-- > 0) + { + if (offPatch >= 0) + *pbPatch = (uint8_t)SizeOfImage; + offPatch++; + pbPatch++; + SizeOfImage >>= 8; + } + } + + /* Done? */ + if (cbToRead == cb) + break; + + offFile += cbToRead; + cb -= cbToRead; + pvBuf = (char *)pvBuf + cbToRead; + } + + /* Mind the gap. */ + if (offNextMap > offFile) + { + uint32_t cbZero = offNextMap - offFile; + if (cbZero > cb) + { + RT_BZERO(pvBuf, cb); + break; + } + + RT_BZERO(pvBuf, cbZero); + offFile += cbZero; + cb -= cbZero; + pvBuf = (char *)pvBuf + cbZero; + } + + pThis->iHint = ++i; + } + + return VINF_SUCCESS; +} + + +/** @callback_method_impl{PFNRTLDRRDRMEMDTOR} */ +static DECLCALLBACK(void) dbgDiggerWinNtRdr_Dtor(void *pvUser) +{ + PDBGDIGGERWINNTRDR pThis = (PDBGDIGGERWINNTRDR)pvUser; + + VMR3ReleaseUVM(pThis->pUVM); + pThis->pUVM = NULL; + RTMemFree(pvUser); +} + + +/** + * Checks if the section headers look okay. + * + * @returns true / false. + * @param paShs Pointer to the section headers. + * @param cShs Number of headers. + * @param cbImage The image size reported by NT. + * @param uRvaRsrc The RVA of the resource directory. UINT32_MAX if + * no resource directory. + * @param cbSectAlign The section alignment specified in the header. + * @param pcbImageCorrect The corrected image size. This is derived from + * cbImage and virtual range of the section tables. + * + * The problem is that NT may choose to drop the + * last pages in images it loads early, starting at + * the resource directory. These images will have + * a page aligned cbImage. + */ +static bool dbgDiggerWinNtCheckSectHdrsAndImgSize(PCIMAGE_SECTION_HEADER paShs, uint32_t cShs, uint32_t cbImage, + uint32_t uRvaRsrc, uint32_t cbSectAlign, uint32_t *pcbImageCorrect) +{ + *pcbImageCorrect = cbImage; + + for (uint32_t i = 0; i < cShs; i++) + { + if (!paShs[i].Name[0]) + { + Log(("DigWinNt: Section header #%u has no name\n", i)); + return false; + } + + if (paShs[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD) + continue; + + /* Check that sizes are within the same range and that both sizes and + addresses are within reasonable limits. */ + if ( RT_ALIGN(paShs[i].Misc.VirtualSize, _64K) < RT_ALIGN(paShs[i].SizeOfRawData, _64K) + || paShs[i].Misc.VirtualSize >= _1G + || paShs[i].SizeOfRawData >= _1G) + { + Log(("DigWinNt: Section header #%u has a VirtualSize=%#x and SizeOfRawData=%#x, that's too much data!\n", + i, paShs[i].Misc.VirtualSize, paShs[i].SizeOfRawData)); + return false; + } + uint32_t uRvaEnd = paShs[i].VirtualAddress + paShs[i].Misc.VirtualSize; + if (uRvaEnd >= _1G || uRvaEnd < paShs[i].VirtualAddress) + { + Log(("DigWinNt: Section header #%u has a VirtualSize=%#x and VirtualAddr=%#x, %#x in total, that's too much!\n", + i, paShs[i].Misc.VirtualSize, paShs[i].VirtualAddress, uRvaEnd)); + return false; + } + + /* Check for images chopped off around '.rsrc'. */ + if ( cbImage < uRvaEnd + && uRvaEnd >= uRvaRsrc) + cbImage = RT_ALIGN(uRvaEnd, cbSectAlign); + + /* Check that the section is within the image. */ + if (uRvaEnd > cbImage) + { + Log(("DigWinNt: Section header #%u has a virtual address range beyond the image: %#x TO %#x cbImage=%#x\n", + i, paShs[i].VirtualAddress, uRvaEnd, cbImage)); + return false; + } + } + + Assert(*pcbImageCorrect == cbImage || !(*pcbImageCorrect & 0xfff)); + *pcbImageCorrect = cbImage; + return true; +} + + +/** + * Create a loader module for the in-guest-memory PE module. + */ +static int dbgDiggerWinNtCreateLdrMod(PDBGDIGGERWINNT pThis, PUVM pUVM, const char *pszName, PCDBGFADDRESS pImageAddr, + uint32_t cbImage, uint8_t *pbBuf, size_t cbBuf, + uint32_t offHdrs, PCNTHDRS pHdrs, PRTLDRMOD phLdrMod) +{ + /* + * Allocate and create a reader instance. + */ + uint32_t const cShs = WINNT_UNION(pThis, pHdrs, FileHeader.NumberOfSections); + PDBGDIGGERWINNTRDR pRdr = (PDBGDIGGERWINNTRDR)RTMemAlloc(RT_OFFSETOF(DBGDIGGERWINNTRDR, aMappings[cShs + 2])); + if (!pRdr) + return VERR_NO_MEMORY; + + VMR3RetainUVM(pUVM); + pRdr->pUVM = pUVM; + pRdr->ImageAddr = *pImageAddr; + pRdr->cbImage = cbImage; + pRdr->cbCorrectImageSize = cbImage; + pRdr->offSizeOfImage = UINT32_MAX; + pRdr->iHint = 0; + + /* + * Use the section table to construct a more accurate view of the file/ + * image if it's in the buffer (it should be). + */ + uint32_t uRvaRsrc = UINT32_MAX; + if (WINNT_UNION(pThis, pHdrs, OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE]).Size > 0) + uRvaRsrc = WINNT_UNION(pThis, pHdrs, OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE]).VirtualAddress; + uint32_t offShs = offHdrs + + ( pThis->f32Bit + ? pHdrs->vX_32.FileHeader.SizeOfOptionalHeader + RT_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader) + : pHdrs->vX_64.FileHeader.SizeOfOptionalHeader + RT_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader)); + uint32_t cbShs = cShs * sizeof(IMAGE_SECTION_HEADER); + PCIMAGE_SECTION_HEADER paShs = (PCIMAGE_SECTION_HEADER)(pbBuf + offShs); + if ( offShs + cbShs <= RT_MIN(cbImage, cbBuf) + && dbgDiggerWinNtCheckSectHdrsAndImgSize(paShs, cShs, cbImage, uRvaRsrc, + WINNT_UNION(pThis, pHdrs, OptionalHeader.SectionAlignment), + &pRdr->cbCorrectImageSize)) + { + pRdr->cMappings = 0; + + for (uint32_t i = 0; i < cShs; i++) + if ( paShs[i].SizeOfRawData > 0 + && paShs[i].PointerToRawData > 0) + { + uint32_t j = 1; + if (!pRdr->cMappings) + pRdr->cMappings++; + else + { + while (j < pRdr->cMappings && pRdr->aMappings[j].offFile < paShs[i].PointerToRawData) + j++; + if (j < pRdr->cMappings) + memmove(&pRdr->aMappings[j + 1], &pRdr->aMappings[j], (pRdr->cMappings - j) * sizeof(pRdr->aMappings)); + } + pRdr->aMappings[j].offFile = paShs[i].PointerToRawData; + pRdr->aMappings[j].offMem = paShs[i].VirtualAddress; + pRdr->aMappings[j].cbMem = i + 1 < cShs + ? paShs[i + 1].VirtualAddress - paShs[i].VirtualAddress + : paShs[i].Misc.VirtualSize; + if (j == pRdr->cMappings) + pRdr->cbImage = paShs[i].PointerToRawData + paShs[i].SizeOfRawData; + pRdr->cMappings++; + } + + /* Insert the mapping of the headers that isn't covered by the section table. */ + pRdr->aMappings[0].offFile = 0; + pRdr->aMappings[0].offMem = 0; + pRdr->aMappings[0].cbMem = pRdr->cMappings ? pRdr->aMappings[1].offFile : pRdr->cbImage; + + int j = pRdr->cMappings - 1; + while (j-- > 0) + { + uint32_t cbFile = pRdr->aMappings[j + 1].offFile - pRdr->aMappings[j].offFile; + if (pRdr->aMappings[j].cbMem > cbFile) + pRdr->aMappings[j].cbMem = cbFile; + } + } + else + { + /* + * Fallback, fake identity mapped file data. + */ + pRdr->cMappings = 1; + pRdr->aMappings[0].offFile = 0; + pRdr->aMappings[0].offMem = 0; + pRdr->aMappings[0].cbMem = pRdr->cbImage; + } + + /* Enable the SizeOfImage patching if necessary. */ + if (pRdr->cbCorrectImageSize != cbImage) + { + Log(("DigWinNT: The image is really %#x bytes long, not %#x as mapped by NT!\n", pRdr->cbCorrectImageSize, cbImage)); + pRdr->offSizeOfImage = pThis->f32Bit + ? offHdrs + RT_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader.SizeOfImage) + : offHdrs + RT_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader.SizeOfImage); + } + + /* + * Call the loader to open the PE image for debugging. + * Note! It always calls pfnDtor. + */ + RTLDRMOD hLdrMod; + int rc = RTLdrOpenInMemory(pszName, RTLDR_O_FOR_DEBUG, RTLDRARCH_WHATEVER, pRdr->cbImage, + dbgDiggerWinNtRdr_Read, dbgDiggerWinNtRdr_Dtor, pRdr, + &hLdrMod); + if (RT_SUCCESS(rc)) + *phLdrMod = hLdrMod; + else + *phLdrMod = NIL_RTLDRMOD; + return rc; +} + + /** * Process a PE image found in guest memory. * - * @param pThis The instance data. - * @param pVM The VM handle. - * @param pszName The image name. - * @param pImageAddr The image address. - * @param cbImage The size of the image. - * @param pbBuf Scratch buffer containing the first - * RT_MIN(cbBuf, cbImage) bytes of the image. - * @param cbBuf The scratch buffer size. + * @param pThis The instance data. + * @param pUVM The user mode VM handle. + * @param pszName The image name. + * @param pImageAddr The image address. + * @param cbImage The size of the image. + * @param pbBuf Scratch buffer containing the first + * RT_MIN(cbBuf, cbImage) bytes of the image. + * @param cbBuf The scratch buffer size. */ -static void dbgDiggerWinNtProcessImage(PDBGDIGGERWINNT pThis, PVM pVM, const char *pszName, +static void dbgDiggerWinNtProcessImage(PDBGDIGGERWINNT pThis, PUVM pUVM, const char *pszName, PCDBGFADDRESS pImageAddr, uint32_t cbImage, uint8_t *pbBuf, size_t cbBuf) { @@ -305,17 +610,12 @@ static void dbgDiggerWinNtProcessImage(PDBGDIGGERWINNT pThis, PVM pVM, const cha /* Dig out the NT/PE headers. */ IMAGE_DOS_HEADER const *pMzHdr = (IMAGE_DOS_HEADER const *)pbBuf; - typedef union NTHDRSU - { - IMAGE_NT_HEADERS64 vX_32; - IMAGE_NT_HEADERS64 vX_64; - } NTHDRS; - NTHDRS const *pHdrs; + PCNTHDRS pHdrs; uint32_t offHdrs; if (pMzHdr->e_magic != IMAGE_DOS_SIGNATURE) { offHdrs = 0; - pHdrs = (NTHDRS const *)pbBuf; + pHdrs = (PCNTHDRS)pbBuf; } else if ( pMzHdr->e_lfanew >= cbImage || pMzHdr->e_lfanew < sizeof(*pMzHdr) @@ -352,6 +652,12 @@ static void dbgDiggerWinNtProcessImage(PDBGDIGGERWINNT pThis, PVM pVM, const cha Log(("DigWinNt: %s: Invalid FH.SizeOfOptionalHeader: %#x\n", pszName, pHdrs->vX_32.FileHeader.SizeOfOptionalHeader)); return; } + if (WINNT_UNION(pThis, pHdrs, FileHeader.NumberOfSections) > 64) + { + Log(("DigWinNt: %s: Too many sections: %#x\n", pszName, WINNT_UNION(pThis, pHdrs, FileHeader.NumberOfSections))); + return; + } + const uint32_t TimeDateStamp = pHdrs->vX_32.FileHeader.TimeDateStamp; /* The optional header is not... */ @@ -360,76 +666,52 @@ static void dbgDiggerWinNtProcessImage(PDBGDIGGERWINNT pThis, PVM pVM, const cha Log(("DigWinNt: %s: Invalid OH.Magic: %#x\n", pszName, WINNT_UNION(pThis, pHdrs, OptionalHeader.Magic))); return; } - if (WINNT_UNION(pThis, pHdrs, OptionalHeader.SizeOfImage) != cbImage) + uint32_t cbImageFromHdr = WINNT_UNION(pThis, pHdrs, OptionalHeader.SizeOfImage); + if (RT_ALIGN(cbImageFromHdr, _4K) != RT_ALIGN(cbImage, _4K)) { - Log(("DigWinNt: %s: Invalid OH.SizeOfImage: %#x, expected %#x\n", pszName, WINNT_UNION(pThis, pHdrs, OptionalHeader.SizeOfImage), cbImage)); + Log(("DigWinNt: %s: Invalid OH.SizeOfImage: %#x, expected %#x\n", pszName, cbImageFromHdr, cbImage)); return; } if (WINNT_UNION(pThis, pHdrs, OptionalHeader.NumberOfRvaAndSizes) != IMAGE_NUMBEROF_DIRECTORY_ENTRIES) { - Log(("DigWinNt: %s: Invalid OH.SizeOfImage: %#x\n", pszName, WINNT_UNION(pThis, pHdrs, OptionalHeader.NumberOfRvaAndSizes))); + Log(("DigWinNt: %s: Invalid OH.NumberOfRvaAndSizes: %#x\n", pszName, WINNT_UNION(pThis, pHdrs, OptionalHeader.NumberOfRvaAndSizes))); return; } - uint32_t uRvaDebugDir = 0; - uint32_t cbDebugDir = 0; - IMAGE_DATA_DIRECTORY const *pDir = &WINNT_UNION(pThis, pHdrs, OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG]); - if ( pDir->VirtualAddress > offHdrs - && pDir->VirtualAddress < cbImage - && pDir->Size >= sizeof(IMAGE_DEBUG_DIRECTORY) - && pDir->Size < cbImage - && pDir->VirtualAddress + pDir->Size <= cbImage - ) - { - uRvaDebugDir = pDir->VirtualAddress; - cbDebugDir = pDir->Size; - } - - /* dig into the section table... */ - /* - * Create the module. + * Create the module using the in memory image first, falling back + * on cached image. */ - RTDBGMOD hMod; - int rc = RTDbgModCreate(&hMod, pszName, cbImage, 0 /*fFlags*/); + RTLDRMOD hLdrMod; + int rc = dbgDiggerWinNtCreateLdrMod(pThis, pUVM, pszName, pImageAddr, cbImage, pbBuf, cbBuf, offHdrs, pHdrs, + &hLdrMod); if (RT_FAILURE(rc)) - return; - rc = RTDbgModSetTag(hMod, DIG_WINNT_MOD_TAG); AssertRC(rc); - - /* temp hack: */ - rc = RTDbgModSymbolAdd(hMod, "start", 0 /*iSeg*/, 0, cbImage, 0 /*fFlags*/, NULL); AssertRC(rc); + hLdrMod = NIL_RTLDRMOD; - /* add sections? */ - - /* - * Dig out debug info if possible. What we're after is the CODEVIEW part. - */ - if (uRvaDebugDir != 0) + RTDBGMOD hMod; + rc = RTDbgModCreateFromPeImage(&hMod, pszName, NULL, hLdrMod, + cbImageFromHdr, TimeDateStamp, DBGFR3AsGetConfig(pUVM)); + if (RT_FAILURE(rc)) { - DBGFADDRESS Addr = *pImageAddr; - DBGFR3AddrAdd(&Addr, uRvaDebugDir); - rc = DBGFR3MemRead(pVM, 0 /*idCpu*/, &Addr, pbBuf, RT_MIN(cbDebugDir, cbBuf)); - if (RT_SUCCESS(rc)) - { - IMAGE_DEBUG_DIRECTORY const *pa = (IMAGE_DEBUG_DIRECTORY const *)pbBuf; - size_t c = RT_MIN(RT_MIN(cbDebugDir, cbBuf) / sizeof(*pa), 10); - for (uint32_t i = 0; i < c; i++) - if ( pa[i].AddressOfRawData > offHdrs - && pa[i].AddressOfRawData < cbImage - && pa[i].SizeOfData < cbImage - && pa[i].AddressOfRawData + pa[i].SizeOfData <= cbImage - && pa[i].TimeDateStamp == TimeDateStamp /* too paranoid? */ - && pa[i].Type == IMAGE_DEBUG_TYPE_CODEVIEW - ) - { - } - } + /* + * Final fallback is a container module. + */ + rc = RTDbgModCreate(&hMod, pszName, cbImage, 0); + if (RT_FAILURE(rc)) + return; + + rc = RTDbgModSymbolAdd(hMod, "Headers", 0 /*iSeg*/, 0, cbImage, 0 /*fFlags*/, NULL); + AssertRC(rc); } + /* Tag the module. */ + rc = RTDbgModSetTag(hMod, DIG_WINNT_MOD_TAG); + AssertRC(rc); + /* * Link the module. */ - RTDBGAS hAs = DBGFR3AsResolveAndRetain(pVM, DBGF_AS_KERNEL); + RTDBGAS hAs = DBGFR3AsResolveAndRetain(pUVM, DBGF_AS_KERNEL); if (hAs != NIL_RTDBGAS) rc = RTDbgAsModuleLink(hAs, hMod, pImageAddr->FlatPtr, RTDBGASLINK_FLAGS_REPLACE /*fFlags*/); else @@ -442,7 +724,7 @@ static void dbgDiggerWinNtProcessImage(PDBGDIGGERWINNT pThis, PVM pVM, const cha /** * @copydoc DBGFOSREG::pfnQueryInterface */ -static DECLCALLBACK(void *) dbgDiggerWinNtQueryInterface(PVM pVM, void *pvData, DBGFOSINTERFACE enmIf) +static DECLCALLBACK(void *) dbgDiggerWinNtQueryInterface(PUVM pUVM, void *pvData, DBGFOSINTERFACE enmIf) { return NULL; } @@ -451,7 +733,7 @@ static DECLCALLBACK(void *) dbgDiggerWinNtQueryInterface(PVM pVM, void *pvData, /** * @copydoc DBGFOSREG::pfnQueryVersion */ -static DECLCALLBACK(int) dbgDiggerWinNtQueryVersion(PVM pVM, void *pvData, char *pszVersion, size_t cchVersion) +static DECLCALLBACK(int) dbgDiggerWinNtQueryVersion(PUVM pUVM, void *pvData, char *pszVersion, size_t cchVersion) { PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData; Assert(pThis->fValid); @@ -463,7 +745,8 @@ static DECLCALLBACK(int) dbgDiggerWinNtQueryVersion(PVM pVM, void *pvData, char case kNtProductType_Server: pszNtProductType = "-Server"; break; default: pszNtProductType = ""; break; } - RTStrPrintf(pszVersion, cchVersion, "%u.%u%s", pThis->NtMajorVersion, pThis->NtMinorVersion, pszNtProductType); + RTStrPrintf(pszVersion, cchVersion, "%u.%u-%s%s", pThis->NtMajorVersion, pThis->NtMinorVersion, + pThis->f32Bit ? "x86" : "AMD64", pszNtProductType); return VINF_SUCCESS; } @@ -471,7 +754,7 @@ static DECLCALLBACK(int) dbgDiggerWinNtQueryVersion(PVM pVM, void *pvData, char /** * @copydoc DBGFOSREG::pfnTerm */ -static DECLCALLBACK(void) dbgDiggerWinNtTerm(PVM pVM, void *pvData) +static DECLCALLBACK(void) dbgDiggerWinNtTerm(PUVM pUVM, void *pvData) { PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData; Assert(pThis->fValid); @@ -483,7 +766,7 @@ static DECLCALLBACK(void) dbgDiggerWinNtTerm(PVM pVM, void *pvData) /** * @copydoc DBGFOSREG::pfnRefresh */ -static DECLCALLBACK(int) dbgDiggerWinNtRefresh(PVM pVM, void *pvData) +static DECLCALLBACK(int) dbgDiggerWinNtRefresh(PUVM pUVM, void *pvData) { PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData; NOREF(pThis); @@ -492,7 +775,7 @@ static DECLCALLBACK(int) dbgDiggerWinNtRefresh(PVM pVM, void *pvData) /* * For now we'll flush and reload everything. */ - RTDBGAS hDbgAs = DBGFR3AsResolveAndRetain(pVM, DBGF_AS_KERNEL); + RTDBGAS hDbgAs = DBGFR3AsResolveAndRetain(pUVM, DBGF_AS_KERNEL); if (hDbgAs != NIL_RTDBGAS) { uint32_t iMod = RTDbgAsModuleCount(hDbgAs); @@ -512,15 +795,15 @@ static DECLCALLBACK(int) dbgDiggerWinNtRefresh(PVM pVM, void *pvData) RTDbgAsRelease(hDbgAs); } - dbgDiggerWinNtTerm(pVM, pvData); - return dbgDiggerWinNtInit(pVM, pvData); + dbgDiggerWinNtTerm(pUVM, pvData); + return dbgDiggerWinNtInit(pUVM, pvData); } /** * @copydoc DBGFOSREG::pfnInit */ -static DECLCALLBACK(int) dbgDiggerWinNtInit(PVM pVM, void *pvData) +static DECLCALLBACK(int) dbgDiggerWinNtInit(PUVM pUVM, void *pvData) { PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData; Assert(!pThis->fValid); @@ -537,8 +820,8 @@ static DECLCALLBACK(int) dbgDiggerWinNtInit(PVM pVM, void *pvData) /* * Figure the NT version. */ - DBGFR3AddrFromFlat(pVM, &Addr, pThis->f32Bit ? NTKUSERSHAREDDATA_WINNT32 : NTKUSERSHAREDDATA_WINNT64); - rc = DBGFR3MemRead(pVM, 0 /*idCpu*/, &Addr, &u, PAGE_SIZE); + DBGFR3AddrFromFlat(pUVM, &Addr, pThis->f32Bit ? NTKUSERSHAREDDATA_WINNT32 : NTKUSERSHAREDDATA_WINNT64); + rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &Addr, &u, PAGE_SIZE); if (RT_FAILURE(rc)) return rc; pThis->NtProductType = u.UserSharedData.ProductTypeIsValid && u.UserSharedData.NtProductType <= kNtProductType_Server @@ -556,7 +839,7 @@ static DECLCALLBACK(int) dbgDiggerWinNtInit(PVM pVM, void *pvData) { /* Read the validate the MTE. */ NTMTE Mte; - rc = DBGFR3MemRead(pVM, 0 /*idCpu*/, &Addr, &Mte, pThis->f32Bit ? sizeof(Mte.vX_32) : sizeof(Mte.vX_64)); + rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &Addr, &Mte, pThis->f32Bit ? sizeof(Mte.vX_32) : sizeof(Mte.vX_64)); if (RT_FAILURE(rc)) break; if (WINNT_UNION(pThis, &Mte, InLoadOrderLinks.Blink) != AddrPrev.FlatPtr) @@ -590,18 +873,18 @@ static DECLCALLBACK(int) dbgDiggerWinNtInit(PVM pVM, void *pvData) /* Read the full name. */ DBGFADDRESS AddrName; - DBGFR3AddrFromFlat(pVM, &AddrName, WINNT_UNION(pThis, &Mte, FullDllName.Buffer)); + DBGFR3AddrFromFlat(pUVM, &AddrName, WINNT_UNION(pThis, &Mte, FullDllName.Buffer)); uint16_t cbName = WINNT_UNION(pThis, &Mte, FullDllName.Length); if (cbName < sizeof(u)) - rc = DBGFR3MemRead(pVM, 0 /*idCpu*/, &AddrName, &u, cbName); + rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &AddrName, &u, cbName); else rc = VERR_OUT_OF_RANGE; if (RT_FAILURE(rc)) { - DBGFR3AddrFromFlat(pVM, &AddrName, WINNT_UNION(pThis, &Mte, BaseDllName.Buffer)); + DBGFR3AddrFromFlat(pUVM, &AddrName, WINNT_UNION(pThis, &Mte, BaseDllName.Buffer)); cbName = WINNT_UNION(pThis, &Mte, BaseDllName.Length); if (cbName < sizeof(u)) - rc = DBGFR3MemRead(pVM, 0 /*idCpu*/, &AddrName, &u, cbName); + rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &AddrName, &u, cbName); else rc = VERR_OUT_OF_RANGE; } @@ -614,12 +897,12 @@ static DECLCALLBACK(int) dbgDiggerWinNtInit(PVM pVM, void *pvData) { /* Read the start of the PE image and pass it along to a worker. */ DBGFADDRESS ImageAddr; - DBGFR3AddrFromFlat(pVM, &ImageAddr, WINNT_UNION(pThis, &Mte, DllBase)); + DBGFR3AddrFromFlat(pUVM, &ImageAddr, WINNT_UNION(pThis, &Mte, DllBase)); uint32_t cbImageBuf = RT_MIN(sizeof(u), WINNT_UNION(pThis, &Mte, SizeOfImage)); - rc = DBGFR3MemRead(pVM, 0 /*idCpu*/, &ImageAddr, &u, cbImageBuf); + rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &ImageAddr, &u, cbImageBuf); if (RT_SUCCESS(rc)) dbgDiggerWinNtProcessImage(pThis, - pVM, + pUVM, pszName, &ImageAddr, WINNT_UNION(pThis, &Mte, SizeOfImage), @@ -631,7 +914,7 @@ static DECLCALLBACK(int) dbgDiggerWinNtInit(PVM pVM, void *pvData) /* next */ AddrPrev = Addr; - DBGFR3AddrFromFlat(pVM, &Addr, WINNT_UNION(pThis, &Mte, InLoadOrderLinks.Flink)); + DBGFR3AddrFromFlat(pUVM, &Addr, WINNT_UNION(pThis, &Mte, InLoadOrderLinks.Flink)); } while ( Addr.FlatPtr != pThis->KernelMteAddr.FlatPtr && Addr.FlatPtr != pThis->PsLoadedModuleListAddr.FlatPtr); @@ -643,7 +926,7 @@ static DECLCALLBACK(int) dbgDiggerWinNtInit(PVM pVM, void *pvData) /** * @copydoc DBGFOSREG::pfnProbe */ -static DECLCALLBACK(bool) dbgDiggerWinNtProbe(PVM pVM, void *pvData) +static DECLCALLBACK(bool) dbgDiggerWinNtProbe(PUVM pUVM, void *pvData) { PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData; DBGFADDRESS Addr; @@ -656,37 +939,41 @@ static DECLCALLBACK(bool) dbgDiggerWinNtProbe(PVM pVM, void *pvData) RTUTF16 wsz[8192/2]; } u; + union + { + NTMTE32 v32; + NTMTE64 v64; + } uMte, uMte2, uMte3; + /* - * Look for the MISYSPTE section name that seems to be a part of all kernels. + * Look for the PAGELK section name that seems to be a part of all kernels. * Then try find the module table entry for it. Since it's the first entry * in the PsLoadedModuleList we can easily validate the list head and report * success. */ - CPUMMODE enmMode = DBGFR3CpuGetMode(pVM, 0 /*idCpu*/); - if (enmMode == CPUMMODE_LONG) + CPUMMODE enmMode = DBGFR3CpuGetMode(pUVM, 0 /*idCpu*/); + uint64_t const uStart = enmMode == CPUMMODE_LONG ? UINT64_C(0xfffff80000000000) : UINT32_C(0x80001000); + uint64_t const uEnd = enmMode == CPUMMODE_LONG ? UINT64_C(0xffffffffffff0000) : UINT32_C(0xffff0000); + DBGFADDRESS KernelAddr; + for (DBGFR3AddrFromFlat(pUVM, &KernelAddr, uStart); + KernelAddr.FlatPtr < uEnd; + KernelAddr.FlatPtr += PAGE_SIZE) { - /** @todo when 32-bit is working, add support for 64-bit windows nt. */ - } - else - { - DBGFADDRESS KernelAddr; - for (DBGFR3AddrFromFlat(pVM, &KernelAddr, UINT32_C(0x80001000)); - KernelAddr.FlatPtr < UINT32_C(0xffff0000); - KernelAddr.FlatPtr += PAGE_SIZE) + int rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &KernelAddr, uEnd - KernelAddr.FlatPtr, + 1, "PAGELK\0", sizeof("PAGELK\0"), &KernelAddr); + if (RT_FAILURE(rc)) + break; + DBGFR3AddrSub(&KernelAddr, KernelAddr.FlatPtr & PAGE_OFFSET_MASK); + + /* MZ + PE header. */ + rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &KernelAddr, &u, sizeof(u)); + if ( RT_SUCCESS(rc) + && u.MzHdr.e_magic == IMAGE_DOS_SIGNATURE + && !(u.MzHdr.e_lfanew & 0x7) + && u.MzHdr.e_lfanew >= 0x080 + && u.MzHdr.e_lfanew <= 0x400) /* W8 is at 0x288*/ { - int rc = DBGFR3MemScan(pVM, 0 /*idCpu*/, &KernelAddr, UINT32_C(0xffff0000) - KernelAddr.FlatPtr, - 1, "MISYSPTE", sizeof("MISYSPTE") - 1, &KernelAddr); - if (RT_FAILURE(rc)) - break; - DBGFR3AddrSub(&KernelAddr, KernelAddr.FlatPtr & PAGE_OFFSET_MASK); - - /* MZ + PE header. */ - rc = DBGFR3MemRead(pVM, 0 /*idCpu*/, &KernelAddr, &u, sizeof(u)); - if ( RT_SUCCESS(rc) - && u.MzHdr.e_magic == IMAGE_DOS_SIGNATURE - && !(u.MzHdr.e_lfanew & 0x7) - && u.MzHdr.e_lfanew >= 0x080 - && u.MzHdr.e_lfanew <= 0x200) + if (enmMode != CPUMMODE_LONG) { IMAGE_NT_HEADERS32 const *pHdrs = (IMAGE_NT_HEADERS32 const *)&u.au8[u.MzHdr.e_lfanew]; if ( pHdrs->Signature == IMAGE_NT_SIGNATURE @@ -696,58 +983,51 @@ static DECLCALLBACK(bool) dbgDiggerWinNtProbe(PVM pVM, void *pvData) && (pHdrs->FileHeader.Characteristics & (IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL)) == IMAGE_FILE_EXECUTABLE_IMAGE && pHdrs->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC && pHdrs->OptionalHeader.NumberOfRvaAndSizes == IMAGE_NUMBEROF_DIRECTORY_ENTRIES - /** @todo need more ntoskrnl signs? */ ) { /* Find the MTE. */ - NTMTE32 Mte; - RT_ZERO(Mte); - Mte.DllBase = KernelAddr.FlatPtr; - Mte.EntryPoint = KernelAddr.FlatPtr + pHdrs->OptionalHeader.AddressOfEntryPoint; - Mte.SizeOfImage = pHdrs->OptionalHeader.SizeOfImage; + RT_ZERO(uMte); + uMte.v32.DllBase = KernelAddr.FlatPtr; + uMte.v32.EntryPoint = KernelAddr.FlatPtr + pHdrs->OptionalHeader.AddressOfEntryPoint; + uMte.v32.SizeOfImage = pHdrs->OptionalHeader.SizeOfImage; DBGFADDRESS HitAddr; - rc = DBGFR3MemScan(pVM, 0 /*idCpu*/, &KernelAddr, UINT32_MAX - KernelAddr.FlatPtr, - 4 /*align*/, &Mte.DllBase, 3 * sizeof(uint32_t), &HitAddr); + rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &KernelAddr, uEnd - KernelAddr.FlatPtr, + 4 /*align*/, &uMte.v32.DllBase, 3 * sizeof(uint32_t), &HitAddr); while (RT_SUCCESS(rc)) { /* check the name. */ - NTMTE32 Mte2; DBGFADDRESS MteAddr = HitAddr; - rc = DBGFR3MemRead(pVM, 0 /*idCpu*/, DBGFR3AddrSub(&MteAddr, RT_OFFSETOF(NTMTE32, DllBase)), - &Mte2, sizeof(Mte2)); + rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrSub(&MteAddr, RT_OFFSETOF(NTMTE32, DllBase)), + &uMte2.v32, sizeof(uMte2.v32)); if ( RT_SUCCESS(rc) - && Mte2.DllBase == Mte.DllBase - && Mte2.EntryPoint == Mte.EntryPoint - && Mte2.SizeOfImage == Mte.SizeOfImage - && WINNT32_VALID_ADDRESS(Mte2.InLoadOrderLinks.Flink) - && Mte2.InLoadOrderLinks.Blink > KernelAddr.FlatPtr /* list head inside ntoskrnl */ - && Mte2.InLoadOrderLinks.Blink < KernelAddr.FlatPtr + Mte.SizeOfImage - && WINNT32_VALID_ADDRESS(Mte2.BaseDllName.Buffer) - && WINNT32_VALID_ADDRESS(Mte2.FullDllName.Buffer) - && Mte2.BaseDllName.Length <= Mte2.BaseDllName.MaximumLength - && Mte2.BaseDllName.Length == WINNT_KERNEL_BASE_NAME_LEN * 2 - && Mte2.FullDllName.Length <= Mte2.FullDllName.MaximumLength - && Mte2.FullDllName.Length <= 256 + && uMte2.v32.DllBase == uMte.v32.DllBase + && uMte2.v32.EntryPoint == uMte.v32.EntryPoint + && uMte2.v32.SizeOfImage == uMte.v32.SizeOfImage + && WINNT32_VALID_ADDRESS(uMte2.v32.InLoadOrderLinks.Flink) + && WINNT32_VALID_ADDRESS(uMte2.v32.BaseDllName.Buffer) + && WINNT32_VALID_ADDRESS(uMte2.v32.FullDllName.Buffer) + && uMte2.v32.BaseDllName.Length <= 128 + && uMte2.v32.FullDllName.Length <= 260 ) { - rc = DBGFR3MemRead(pVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pVM, &Addr, Mte2.BaseDllName.Buffer), - u.wsz, Mte2.BaseDllName.Length); - u.wsz[Mte2.BaseDllName.Length / 2] = '\0'; + rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pUVM, &Addr, uMte2.v32.BaseDllName.Buffer), + u.wsz, uMte2.v32.BaseDllName.Length); + u.wsz[uMte2.v32.BaseDllName.Length / 2] = '\0'; if ( RT_SUCCESS(rc) && ( !RTUtf16ICmp(u.wsz, g_wszKernelNames[0]) /* || !RTUtf16ICmp(u.wsz, g_wszKernelNames[1]) */ ) ) { - NTMTE32 Mte3; - rc = DBGFR3MemRead(pVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pVM, &Addr, Mte2.InLoadOrderLinks.Blink), - &Mte3, RT_SIZEOFMEMB(NTMTE32, InLoadOrderLinks)); + rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, + DBGFR3AddrFromFlat(pUVM, &Addr, uMte2.v32.InLoadOrderLinks.Blink), + &uMte3.v32, RT_SIZEOFMEMB(NTMTE32, InLoadOrderLinks)); if ( RT_SUCCESS(rc) - && Mte3.InLoadOrderLinks.Flink == MteAddr.FlatPtr - && WINNT32_VALID_ADDRESS(Mte3.InLoadOrderLinks.Blink) ) + && uMte3.v32.InLoadOrderLinks.Flink == MteAddr.FlatPtr + && WINNT32_VALID_ADDRESS(uMte3.v32.InLoadOrderLinks.Blink) ) { Log(("DigWinNt: MteAddr=%RGv KernelAddr=%RGv SizeOfImage=%x &PsLoadedModuleList=%RGv (32-bit)\n", - MteAddr.FlatPtr, KernelAddr.FlatPtr, Mte2.SizeOfImage, Addr.FlatPtr)); + MteAddr.FlatPtr, KernelAddr.FlatPtr, uMte2.v32.SizeOfImage, Addr.FlatPtr)); pThis->KernelAddr = KernelAddr; pThis->KernelMteAddr = MteAddr; pThis->PsLoadedModuleListAddr = Addr; @@ -755,13 +1035,100 @@ static DECLCALLBACK(bool) dbgDiggerWinNtProbe(PVM pVM, void *pvData) return true; } } + else if (RT_SUCCESS(rc)) + { + Log2(("DigWinNt: Wrong module: MteAddr=%RGv ImageAddr=%RGv SizeOfImage=%#x '%ls'\n", + MteAddr.FlatPtr, KernelAddr.FlatPtr, uMte2.v32.SizeOfImage, u.wsz)); + break; /* Not NT kernel */ + } } /* next */ DBGFR3AddrAdd(&HitAddr, 4); - if (HitAddr.FlatPtr <= UINT32_C(0xfffff000)) - rc = DBGFR3MemScan(pVM, 0 /*idCpu*/, &HitAddr, UINT32_MAX - HitAddr.FlatPtr, - 4 /*align*/, &Mte.DllBase, 3 * sizeof(uint32_t), &HitAddr); + if (HitAddr.FlatPtr < uEnd) + rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &HitAddr, uEnd - HitAddr.FlatPtr, + 4 /*align*/, &uMte.v32.DllBase, 3 * sizeof(uint32_t), &HitAddr); + else + rc = VERR_DBGF_MEM_NOT_FOUND; + } + } + } + else + { + IMAGE_NT_HEADERS64 const *pHdrs = (IMAGE_NT_HEADERS64 const *)&u.au8[u.MzHdr.e_lfanew]; + if ( pHdrs->Signature == IMAGE_NT_SIGNATURE + && pHdrs->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64 + && pHdrs->FileHeader.SizeOfOptionalHeader == sizeof(pHdrs->OptionalHeader) + && pHdrs->FileHeader.NumberOfSections >= 10 /* the kernel has lots */ + && (pHdrs->FileHeader.Characteristics & (IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL)) == IMAGE_FILE_EXECUTABLE_IMAGE + && pHdrs->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC + && pHdrs->OptionalHeader.NumberOfRvaAndSizes == IMAGE_NUMBEROF_DIRECTORY_ENTRIES + ) + { + /* Find the MTE. */ + RT_ZERO(uMte.v64); + uMte.v64.DllBase = KernelAddr.FlatPtr; + uMte.v64.EntryPoint = KernelAddr.FlatPtr + pHdrs->OptionalHeader.AddressOfEntryPoint; + uMte.v64.SizeOfImage = pHdrs->OptionalHeader.SizeOfImage; + DBGFADDRESS ScanAddr; + DBGFADDRESS HitAddr; + rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pUVM, &ScanAddr, uStart), + uEnd - uStart, 8 /*align*/, &uMte.v64.DllBase, 5 * sizeof(uint32_t), &HitAddr); + while (RT_SUCCESS(rc)) + { + /* check the name. */ + DBGFADDRESS MteAddr = HitAddr; + rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrSub(&MteAddr, RT_OFFSETOF(NTMTE64, DllBase)), + &uMte2.v64, sizeof(uMte2.v64)); + if ( RT_SUCCESS(rc) + && uMte2.v64.DllBase == uMte.v64.DllBase + && uMte2.v64.EntryPoint == uMte.v64.EntryPoint + && uMte2.v64.SizeOfImage == uMte.v64.SizeOfImage + && WINNT64_VALID_ADDRESS(uMte2.v64.InLoadOrderLinks.Flink) + && WINNT64_VALID_ADDRESS(uMte2.v64.BaseDllName.Buffer) + && WINNT64_VALID_ADDRESS(uMte2.v64.FullDllName.Buffer) + && uMte2.v64.BaseDllName.Length <= 128 + && uMte2.v64.FullDllName.Length <= 260 + ) + { + rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pUVM, &Addr, uMte2.v64.BaseDllName.Buffer), + u.wsz, uMte2.v64.BaseDllName.Length); + u.wsz[uMte2.v64.BaseDllName.Length / 2] = '\0'; + if ( RT_SUCCESS(rc) + && ( !RTUtf16ICmp(u.wsz, g_wszKernelNames[0]) + /* || !RTUtf16ICmp(u.wsz, g_wszKernelNames[1]) */ + ) + ) + { + rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, + DBGFR3AddrFromFlat(pUVM, &Addr, uMte2.v64.InLoadOrderLinks.Blink), + &uMte3.v64, RT_SIZEOFMEMB(NTMTE64, InLoadOrderLinks)); + if ( RT_SUCCESS(rc) + && uMte3.v64.InLoadOrderLinks.Flink == MteAddr.FlatPtr + && WINNT64_VALID_ADDRESS(uMte3.v64.InLoadOrderLinks.Blink) ) + { + Log(("DigWinNt: MteAddr=%RGv KernelAddr=%RGv SizeOfImage=%x &PsLoadedModuleList=%RGv (32-bit)\n", + MteAddr.FlatPtr, KernelAddr.FlatPtr, uMte2.v64.SizeOfImage, Addr.FlatPtr)); + pThis->KernelAddr = KernelAddr; + pThis->KernelMteAddr = MteAddr; + pThis->PsLoadedModuleListAddr = Addr; + pThis->f32Bit = false; + return true; + } + } + else if (RT_SUCCESS(rc)) + { + Log2(("DigWinNt: Wrong module: MteAddr=%RGv ImageAddr=%RGv SizeOfImage=%#x '%ls'\n", + MteAddr.FlatPtr, KernelAddr.FlatPtr, uMte2.v64.SizeOfImage, u.wsz)); + break; /* Not NT kernel */ + } + } + + /* next */ + DBGFR3AddrAdd(&HitAddr, 8); + if (HitAddr.FlatPtr < uEnd) + rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &HitAddr, uEnd - HitAddr.FlatPtr, + 8 /*align*/, &uMte.v64.DllBase, 3 * sizeof(uint32_t), &HitAddr); else rc = VERR_DBGF_MEM_NOT_FOUND; } @@ -776,7 +1143,7 @@ static DECLCALLBACK(bool) dbgDiggerWinNtProbe(PVM pVM, void *pvData) /** * @copydoc DBGFOSREG::pfnDestruct */ -static DECLCALLBACK(void) dbgDiggerWinNtDestruct(PVM pVM, void *pvData) +static DECLCALLBACK(void) dbgDiggerWinNtDestruct(PUVM pUVM, void *pvData) { } @@ -785,7 +1152,7 @@ static DECLCALLBACK(void) dbgDiggerWinNtDestruct(PVM pVM, void *pvData) /** * @copydoc DBGFOSREG::pfnConstruct */ -static DECLCALLBACK(int) dbgDiggerWinNtConstruct(PVM pVM, void *pvData) +static DECLCALLBACK(int) dbgDiggerWinNtConstruct(PUVM pUVM, void *pvData) { PDBGDIGGERWINNT pThis = (PDBGDIGGERWINNT)pvData; pThis->fValid = false; |