DBGPlugInWinNt.cpp revision c58f1213e628a545081c70e26c6b67a841cff880
/* $Id$ */
/** @file
* DBGPlugInWindows - Debugger and Guest OS Digger Plugin For Windows NT.
*/
/*
* 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;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#include "DBGPlugIns.h"
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/** @name Internal WinNT structures
* @{ */
/**
* PsLoadedModuleList entry for 32-bit NT aka LDR_DATA_TABLE_ENTRY.
* Tested with XP.
*/
typedef struct NTMTE32
{
struct
{
struct
{
} FullDllName,
/* ... there is more ... */
} NTMTE32;
/**
* PsLoadedModuleList entry for 32-bit NT aka LDR_DATA_TABLE_ENTRY.
* Tested with XP.
*
* @todo This is incomplete and just to get rid of warnings.
*/
typedef struct NTMTE64
{
struct
{
struct
{
} FullDllName,
/* ... there is more ... */
} NTMTE64;
/** MTE union. */
typedef union NTMTE
{
} NTMTE;
/**
* The essential bits of the KUSER_SHARED_DATA structure.
*/
typedef struct NTKUSERSHAREDDATA
{
struct
{
/* uint8_t ProcessorFeatures[64];
...
*/
typedef NTKUSERSHAREDDATA *PNTKUSERSHAREDDATA;
/** KI_USER_SHARED_DATA for i386 */
/** KI_USER_SHARED_DATA for AMD64 */
/** NTKUSERSHAREDDATA::NtProductType */
typedef enum NTPRODUCTTYPE
{
kNtProductType_WinNt = 1,
/**
* PDB v2.0 in image debug info.
* The URL is constructed from the timestamp and the %02x age?
*/
typedef struct CV_INFO_PDB20
{
/** The CV_INFO_PDB20 signature. */
/**
* 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
{
#pragma pack()
/** The CV_INFO_PDB70 signature. */
/** @} */
typedef enum DBGDIGGERWINNTVER
{
/**
* WinNT guest OS digger instance data.
*/
typedef struct DBGDIGGERWINNT
{
/** Whether the information is valid or not.
* (For fending off illegal interface method calls.) */
bool fValid;
/** 32-bit (true) or 64-bit (false) */
bool f32Bit;
/** The NT version. */
/** NTKUSERSHAREDDATA::NtProductType */
/** NTKUSERSHAREDDATA::NtMajorVersion */
/** NTKUSERSHAREDDATA::NtMinorVersion */
/** The address of the ntoskrnl.exe image. */
/** The address of the ntoskrnl.exe module table entry. */
/** The address of PsLoadedModuleList. */
/** Pointer to the linux guest OS digger instance data. */
typedef DBGDIGGERWINNT *PDBGDIGGERWINNT;
/*******************************************************************************
* 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))
/** Validates a kernel address. */
#define WINNT_VALID_ADDRESS(pThis, Addr) ((pThis)->f32Bit ? WINNT32_VALID_ADDRESS(Addr) : WINNT64_VALID_ADDRESS(Addr))
/** Versioned and bitness wrapper. */
#define WINNT_UNION(pThis, pUnion, Member) ((pThis)->f32Bit ? (pUnion)->vX_32. Member : (pUnion)->vX_64. Member )
/** The length (in chars) of the kernel file name (no path). */
#define WINNT_KERNEL_BASE_NAME_LEN 12
/** WindowsNT on little endian ASCII systems. */
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
/*******************************************************************************
* Global Variables *
*******************************************************************************/
/** Kernel names. */
{
{ 'n', 't', 'o', 's', 'k', 'r', 'n', 'l', '.', 'e', 'x', 'e' }
};
/**
* Process a PE image found in guest memory.
*
* @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.
*/
{
/*
* Do some basic validation first.
* This is the usual exteremely verbose and messy code...
*/
if ( cbImage < sizeof(IMAGE_NT_HEADERS64)
{
return;
}
typedef union NTHDRSU
{
} NTHDRS;
{
offHdrs = 0;
}
{
return;
}
{
}
else
{
return;
}
{
return;
}
/* The file header is the same on both archs */
if (pHdrs->vX_32.FileHeader.Machine != (pThis->f32Bit ? IMAGE_FILE_MACHINE_I386 : IMAGE_FILE_MACHINE_AMD64))
{
return;
}
if (pHdrs->vX_32.FileHeader.SizeOfOptionalHeader != (pThis->f32Bit ? sizeof(IMAGE_OPTIONAL_HEADER32) : sizeof(IMAGE_OPTIONAL_HEADER64)))
{
Log(("DigWinNt: %s: Invalid FH.SizeOfOptionalHeader: %#x\n", pszName, pHdrs->vX_32.FileHeader.SizeOfOptionalHeader));
return;
}
/* The optional header is not... */
if (WINNT_UNION(pThis, pHdrs, OptionalHeader.Magic) != (pThis->f32Bit ? IMAGE_NT_OPTIONAL_HDR32_MAGIC : IMAGE_NT_OPTIONAL_HDR64_MAGIC))
{
Log(("DigWinNt: %s: Invalid OH.Magic: %#x\n", pszName, WINNT_UNION(pThis, pHdrs, OptionalHeader.Magic)));
return;
}
{
Log(("DigWinNt: %s: Invalid OH.SizeOfImage: %#x, expected %#x\n", pszName, WINNT_UNION(pThis, pHdrs, OptionalHeader.SizeOfImage), 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)));
return;
}
uint32_t uRvaDebugDir = 0;
uint32_t cbDebugDir = 0;
IMAGE_DATA_DIRECTORY const *pDir = &WINNT_UNION(pThis, pHdrs, OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG]);
)
{
}
/* dig into the section table... */
/*
* Create the module.
*/
if (RT_FAILURE(rc))
return;
/* temp hack: */
/* add sections? */
/*
* Dig out debug info if possible. What we're after is the CODEVIEW part.
*/
if (uRvaDebugDir != 0)
{
if (RT_SUCCESS(rc))
{
for (uint32_t i = 0; i < c; i++)
)
{
}
}
}
/*
* Link the module.
*/
if (hAs != NIL_RTDBGAS)
else
}
/**
* @copydoc DBGFOSREG::pfnQueryInterface
*/
static DECLCALLBACK(void *) dbgDiggerWinNtQueryInterface(PUVM pUVM, void *pvData, DBGFOSINTERFACE enmIf)
{
return NULL;
}
/**
* @copydoc DBGFOSREG::pfnQueryVersion
*/
static DECLCALLBACK(int) dbgDiggerWinNtQueryVersion(PUVM pUVM, void *pvData, char *pszVersion, size_t cchVersion)
{
const char *pszNtProductType;
switch (pThis->NtProductType)
{
default: pszNtProductType = ""; break;
}
RTStrPrintf(pszVersion, cchVersion, "%u.%u%s", pThis->NtMajorVersion, pThis->NtMinorVersion, pszNtProductType);
return VINF_SUCCESS;
}
/**
* @copydoc DBGFOSREG::pfnTerm
*/
{
}
/**
* @copydoc DBGFOSREG::pfnRefresh
*/
{
/*
* For now we'll flush and reload everything.
*/
if (hDbgAs != NIL_RTDBGAS)
{
while (iMod-- > 0)
{
if (hMod != NIL_RTDBGMOD)
{
{
}
}
}
}
}
/**
* @copydoc DBGFOSREG::pfnInit
*/
{
union
{
} u;
int rc;
/*
* Figure the NT version.
*/
DBGFR3AddrFromFlat(pUVM, &Addr, pThis->f32Bit ? NTKUSERSHAREDDATA_WINNT32 : NTKUSERSHAREDDATA_WINNT64);
if (RT_FAILURE(rc))
return rc;
pThis->NtProductType = u.UserSharedData.ProductTypeIsValid && u.UserSharedData.NtProductType <= kNtProductType_Server
/*
* Dig out the module chain.
*/
do
{
/* Read the validate the MTE. */
rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &Addr, &Mte, pThis->f32Bit ? sizeof(Mte.vX_32) : sizeof(Mte.vX_64));
if (RT_FAILURE(rc))
break;
{
break;
}
{
break;
}
{
Log(("DigWinNt: Bad Mte at %RGv - BaseDllName=%llx\n", Addr.FlatPtr, WINNT_UNION(pThis, &Mte, BaseDllName.Buffer)));
break;
}
{
Log(("DigWinNt: Bad Mte at %RGv - FullDllName=%llx\n", Addr.FlatPtr, WINNT_UNION(pThis, &Mte, FullDllName.Buffer)));
break;
}
|| WINNT_UNION(pThis, &Mte, EntryPoint) - WINNT_UNION(pThis, &Mte, DllBase) > WINNT_UNION(pThis, &Mte, SizeOfImage) )
{
Log(("DigWinNt: Bad Mte at %RGv - EntryPoint=%llx SizeOfImage=%x DllBase=%llx\n",
Addr.FlatPtr, WINNT_UNION(pThis, &Mte, EntryPoint), WINNT_UNION(pThis, &Mte, SizeOfImage), WINNT_UNION(pThis, &Mte, DllBase)));
break;
}
/* Read the full name. */
if (cbName < sizeof(u))
else
if (RT_FAILURE(rc))
{
if (cbName < sizeof(u))
else
}
if (RT_SUCCESS(rc))
{
char *pszName;
if (RT_SUCCESS(rc))
{
/* Read the start of the PE image and pass it along to a worker. */
if (RT_SUCCESS(rc))
pUVM,
&u.au8[0],
sizeof(u));
}
}
/* next */
return VINF_SUCCESS;
}
/**
* @copydoc DBGFOSREG::pfnProbe
*/
{
union
{
} u;
/*
* Look for the MISYSPTE 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.
*/
if (enmMode == CPUMMODE_LONG)
{
/** @todo when 32-bit is working, add support for 64-bit windows nt. */
}
else
{
{
if (RT_FAILURE(rc))
break;
/* MZ + PE header. */
if ( RT_SUCCESS(rc)
{
&& (pHdrs->FileHeader.Characteristics & (IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DLL)) == IMAGE_FILE_EXECUTABLE_IMAGE
/** @todo need more ntoskrnl signs? */
)
{
/* Find the MTE. */
while (RT_SUCCESS(rc))
{
/* check the name. */
if ( RT_SUCCESS(rc)
)
{
if ( RT_SUCCESS(rc)
/* || !RTUtf16ICmp(u.wsz, g_wszKernelNames[1]) */
)
)
{
if ( RT_SUCCESS(rc)
{
Log(("DigWinNt: MteAddr=%RGv KernelAddr=%RGv SizeOfImage=%x &PsLoadedModuleList=%RGv (32-bit)\n",
return true;
}
}
}
/* next */
else
}
}
}
}
}
return false;
}
/**
* @copydoc DBGFOSREG::pfnDestruct
*/
{
}
/**
* @copydoc DBGFOSREG::pfnConstruct
*/
{
return VINF_SUCCESS;
}
const DBGFOSREG g_DBGDiggerWinNt =
{
/* .u32Magic = */ DBGFOSREG_MAGIC,
/* .fFlags = */ 0,
/* .cbData = */ sizeof(DBGDIGGERWINNT),
/* .szName = */ "WinNT",
/* .pfnConstruct = */ dbgDiggerWinNtConstruct,
/* .pfnDestruct = */ dbgDiggerWinNtDestruct,
/* .pfnProbe = */ dbgDiggerWinNtProbe,
/* .pfnInit = */ dbgDiggerWinNtInit,
/* .pfnRefresh = */ dbgDiggerWinNtRefresh,
/* .pfnTerm = */ dbgDiggerWinNtTerm,
/* .pfnQueryVersion = */ dbgDiggerWinNtQueryVersion,
/* .pfnQueryInterface = */ dbgDiggerWinNtQueryInterface,
/* .u32EndMagic = */ DBGFOSREG_MAGIC
};