📄 kdhandle.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//
/*++
Module Name:
kdhandle.c
Abstract:
This module contains code to implement handle queries and deletions.
--*/
// C4200: nonstandard extension used : zero-sized array in struct/union
#pragma warning(disable:4200)
// C4228: nonstandard extension used : qualifiers after comma in declarator list are ignored
#pragma warning(disable:4228)
#include <cmnintrin.h>
#include "kdp.h"
// We pull in these from filesys.h
typedef struct fsopenfile_t
{
DWORD filepos;
struct fsopenfile_t *next;
WORD flags;
HANDLE hFile;
HANDLE hNotify;
} fsopenfile_t;
#ifdef _DEBUG
#define CODE_NEVER_REACHED() ASSERT(0)
#else
#define CODE_NEVER_REACHED() __assume(0)
#endif /* _DEBUG */
// Declare a KD_HANDLE_DESC that describes a field inside a structure
// id = one of the KD_HDATA_xxx IDs
// t = one of the KD_FIELD_xxx type IDs
// s = structure name
// p = field name in above structure
#define DESC_OFF(id,t,s,p) {NULL, offsetof(s, p), sizeof(((s *) NULL)->p), id, t}
// Declare KD_HANDLE_DESC for data returned by a callback function
// id = one of the KD_HDATA_xxx IDs
// t = one of the KD_FIELD_xxx type IDs
// f = function to call to get the data
#define DESC_FUN(id,t,f) {f, 0, 0, id, t}
// Declare KD_API_DESC
// p = KD_API_DESC array (KD_API_DESC[], not KD_API_DESC*)
// f = function to validate extra handle data for this particular API
#define APIDESC(p,f) {p, lengthof(p), f}
// Declare an empty KD_API_DESC
// p = KD_API_DESC array (KD_API_DESC[], not KD_API_DESC*)
// f = function to validate extra handle data for this particular API
//
// Note that p and f are ignored; this is used as a placeholder. Once the API
// has a description, change APINULL -> APIDESC macro and you're good to go.
#define APINULL(p,f) {NULL, 0, KdDontValidate}
typedef struct _KD_HANDLE_DESC
{
// For extremely special fields that are annoying to encode. If this is
// NULL, we copy a 4-byte variable at the specified offset.
UINT32 (* pfnReadField)(PCVOID pvData);
size_t nOffset;
size_t nSize;
UINT16 nFieldId;
UINT16 nType;
} KD_HANDLE_DESC;
typedef KD_HANDLE_DESC *PKD_HANDLE_DESC;
typedef const KD_HANDLE_DESC *PCKD_HANDLE_DESC;
typedef struct
{
PCKD_HANDLE_DESC pDesc;
UINT cEntries;
BOOL (* pfnValidateHandle)(HDATA *ph);
} KD_API_DESC;
typedef KD_API_DESC *PKD_API_DESC;
typedef const KD_API_DESC *PCKD_API_DESC;
// Function to extract position of least-significant one
static UINT _CountTrailingZeros(UINT32 nMask);
// Function to convert a KD_HANDLE_DESC into a DBGKD_HANDLE_FIELD_DATA
static void KdHandleGetField(PDBGKD_HANDLE_FIELD_DATA pField, PCKD_HANDLE_DESC pDesc, LPCVOID pvStruct);
// Some handle validation helper functions
static BOOL KdDontValidate(HDATA *ph);
static BOOL KdValidateThread(HDATA *ph);
static BOOL KdValidateProcess(HDATA *ph);
// Some handle data helper functions
static UINT32 KdReadGlobalRefCount(PCVOID pvData);
static UINT32 KdReadHandleType(PCVOID pvData);
static UINT32 KdReadHandleName(PCVOID pvData);
static UINT32 KdReadThreadPID(PCVOID pvData);
static UINT32 KdReadMutexOwner(PCVOID pvData);
// Constants for _CountTrailingZeros emulation
#if !_INTRINSIC_IS_SUPPORTED(_CountLeadingZeros)
static const UINT32 g_nCntLeadMagic32 = 0xF04653AE;
static const BYTE g_abCntLeadTbl32[32] =
{0, 31, 4, 5, 6, 10, 7, 15, 11, 20, 8, 18, 16, 25, 12, 27,
21, 30, 3, 9, 14, 19, 17, 24, 26, 29, 2, 13, 23, 28, 1, 22};
#endif /* !_INTRINSIC_IS_SUPPORTED(_CountLeadingZeros) */
// Describe the HDATA structure.
static const KD_HANDLE_DESC g_pGenericDesc[] =
{DESC_OFF(KD_HDATA_HANDLE, KD_FIELD_HANDLE, HDATA, hValue),
DESC_OFF(KD_HDATA_AKY, KD_FIELD_BITS, HDATA, lock),
DESC_FUN(KD_HDATA_REFCNT, KD_FIELD_UINT, KdReadGlobalRefCount),
DESC_FUN(KD_HDATA_TYPE, KD_FIELD_WIDE_STR, KdReadHandleType),
DESC_FUN(KD_HDATA_NAME, KD_FIELD_WIDE_STR, KdReadHandleName)};
// These descriptors correspond to handle types (_HDATA.pci->type)
//static const KD_HANDLE_DESC g_pWin32Desc[] = {};
static const KD_HANDLE_DESC g_pThreadDesc[] =
{DESC_OFF(KD_HDATA_THREAD_SUSPEND, KD_FIELD_UINT, THREAD, bSuspendCnt),
DESC_FUN(KD_HDATA_THREAD_PID, KD_FIELD_UINT, KdReadThreadPID),
DESC_OFF(KD_HDATA_THREAD_BPRIO, KD_FIELD_UINT, THREAD, bBPrio),
DESC_OFF(KD_HDATA_THREAD_CPRIO, KD_FIELD_UINT, THREAD, bCPrio),
DESC_OFF(KD_HDATA_THREAD_KTIME, KD_FIELD_UINT, THREAD, dwKernTime),
DESC_OFF(KD_HDATA_THREAD_UTIME, KD_FIELD_UINT, THREAD, dwUserTime)};
static const KD_HANDLE_DESC g_pProcessDesc[] =
{DESC_OFF(KD_HDATA_PROC_PID, KD_FIELD_UINT, PROCESS, procnum),
DESC_OFF(KD_HDATA_PROC_TRUST, KD_FIELD_UINT, PROCESS, bTrustLevel),
DESC_OFF(KD_HDATA_PROC_VMBASE, KD_FIELD_PTR, PROCESS, dwVMBase),
DESC_OFF(KD_HDATA_PROC_BASEPTR, KD_FIELD_PTR, PROCESS, BasePtr),
DESC_OFF(KD_HDATA_PROC_CMDLINE, KD_FIELD_WIDE_STR, PROCESS, pcmdline)};
static const KD_HANDLE_DESC g_pEventDesc[] =
{DESC_OFF(KD_HDATA_EVENT_STATE, KD_FIELD_BOOL, EVENT, state),
DESC_OFF(KD_HDATA_EVENT_RESET, KD_FIELD_BOOL, EVENT, manualreset)};
static const KD_HANDLE_DESC g_pMutexDesc[] =
{DESC_OFF(KD_HDATA_MUTEX_LOCKCNT, KD_FIELD_UINT, MUTEX, LockCount),
DESC_FUN(KD_HDATA_MUTEX_OWNER, KD_FIELD_HANDLE, KdReadMutexOwner)};
//static const KD_HANDLE_DESC g_pAPISetDesc[] = {};
//static const KD_HANDLE_DESC g_pFileDesc[] = {};
//static const KD_HANDLE_DESC g_pFindDesc[] = {};
//static const KD_HANDLE_DESC g_pDBFileDesc[] = {};
//static const KD_HANDLE_DESC g_pDBFindDesc[] = {};
//static const KD_HANDLE_DESC g_pSocketDesc[] = {};
//static const KD_HANDLE_DESC g_pInterfaceDesc[] = {};
static const KD_HANDLE_DESC g_pSemaphoreDesc[] =
{DESC_OFF(KD_HDATA_SEM_COUNT, KD_FIELD_SINT, SEMAPHORE, lCount),
DESC_OFF(KD_HDATA_SEM_MAXCOUNT, KD_FIELD_SINT, SEMAPHORE, lMaxCount)};
//static const KD_HANDLE_DESC g_pFSMapDesc[] = {};
//static const KD_HANDLE_DESC g_pWNetEnumDesc[] = {};
// NULL API set (no API-specific data). This is useful for simplifying the code
// later on.
const KD_API_DESC g_descNull = {NULL, 0, KdDontValidate};
static BOOL KdDontValidate(HDATA *ph);
static BOOL KdValidateThread(HDATA *ph);
static BOOL KdValidateProcess(HDATA *ph);
// APINULL macros correspond to unimplemented descriptors
KD_API_DESC g_pTypeMap[] =
{APINULL(g_pWin32Desc, KdDontValidate), // 0 = SH_WIN32
APIDESC(g_pThreadDesc, KdValidateThread), // 1 = SH_CURTHREAD
APIDESC(g_pProcessDesc, KdValidateProcess), // 2 = SH_CURPROC
APINULL(g_pKWin32Desc, KdDontValidate), // 3 = SH_KWIN32
APIDESC(g_pEventDesc, KdDontValidate), // 4 = HT_EVENT
APIDESC(g_pMutexDesc, KdDontValidate), // 5 = HT_MUTEX
APINULL(g_pAPISetDesc, KdDontValidate), // 6 = HT_APISET
APINULL(g_pFileDesc, KdDontValidate), // 7 = HT_FILE
APINULL(g_pFindDesc, KdDontValidate), // 8 = HT_FIND
APINULL(g_pDBFileDesc, KdDontValidate), // 9 = HT_DBFILE
APINULL(g_pDBFindDesc, KdDontValidate), // 10 = HT_DBFIND
APINULL(g_pSocketDesc, KdDontValidate), // 11 = HT_SOCKET
APINULL(g_pInterfaceDesc, KdDontValidate), // 12 = HT_INTERFACE
APIDESC(g_pSemaphoreDesc, KdDontValidate), // 13 = HT_SEMAPHORE
APINULL(g_pFSMapDesc, KdDontValidate), // 14 = HT_FSMAP
APINULL(g_pWNetEnumDesc, KdDontValidate), // 15 = HT_WNETENUM
};
static LPCWSTR g_apszHandleTypeNames[] =
{L"Win32",
L"Thread",
L"Process",
L"[Unused]",
L"Event",
L"Mutex",
L"API set",
L"File",
L"Find",
L"DB File",
L"DB Find",
L"Socket",
L"Interface",
L"Semaphore",
L"FS Map",
L"WNet Enum",
};
/*++
Routine Name:
KdHandleToPtr
Routine Description:
This routine converts a Windows CE HANDLE into the associated HDATA
structure.
Arguments:
hHandle - [in] Handle to convert
Return Value:
If the handle is invalid, this routine returns NULL. Otherwise it returns
a pointer to the HDATA structure for the handle.
--*/
HDATA *KdHandleToPtr(HANDLE hHandle)
{
HDATA *phCurHandle;
for(phCurHandle = (HDATA *) pHandleList->linkage.fwd;
phCurHandle != pHandleList;
phCurHandle = (HDATA *) phCurHandle->linkage.fwd)
{
if (phCurHandle->hValue == hHandle)
{
DEBUGGERMSG(KDZONE_HANDLEEX, (L"KdHandleToPtr: Handle %08p = HDATA@%08p\r\n", hHandle, phCurHandle));
return phCurHandle;
}
}
DEBUGGERMSG(KDZONE_HANDLEEX, (L"KdHandleToPtr: Handle %08p not valid\r\n", hHandle));
return NULL;
}
/*++
Routine Name:
KdValidateHandle
Routine Description:
This routine verifies that a handle is valid.
Arguments:
hHandle - [in] Handle to check
Return Value:
TRUE Handle is valid
FALSE Handle is invalid
--*/
BOOL KdValidateHandle(HANDLE hHandle)
{
HDATA *phCurHandle;
UINT nType;
DEBUGGERMSG(KDZONE_HANDLEEX, (L"KdValidateHandlePtr: Validating handle %08p\r\n", hHandle));
phCurHandle = KdHandleToPtr(hHandle);
if (phCurHandle == NULL)
return FALSE;
nType = phCurHandle->pci->type;
if (nType < lengthof(g_pTypeMap) &&
!g_pTypeMap[nType].pfnValidateHandle(phCurHandle))
return FALSE;
return TRUE;
}
/*++
Routine Name:
KdValidateHandlePtr
Routine Description:
This routine verifies that a pointer to a handle is valid.
Arguments:
phHandle - [in] Handle to check
Return Value:
TRUE Handle is valid
FALSE Handle is invalid
--*/
BOOL KdValidateHandlePtr(HDATA *phHandle)
{
HDATA *phCurHandle;
UINT nType;
DEBUGGERMSG(KDZONE_HANDLEEX, (L"KdValidateHandlePtr: Validating handle pointer %08p\r\n", phHandle));
for(phCurHandle = (HDATA *) pHandleList->linkage.fwd;
phCurHandle != pHandleList;
phCurHandle = (HDATA *) phCurHandle->linkage.fwd)
{
if (phCurHandle == phHandle)
break;
}
if (phCurHandle == pHandleList)
return FALSE;
nType = phHandle->pci->type;
if (nType < lengthof(g_pTypeMap) &&
!g_pTypeMap[nType].pfnValidateHandle(phHandle))
return FALSE;
return TRUE;
}
/*++
Routine Name:
KdGetProcHandleRef
Routine Description:
This routine obtains the reference count for a particular process on an
arbitrary handle.
Arguments:
hHandle - [in] Handle to check
nPID - [in] Process ID to obtain reference count for
Return Value:
Number of references or -1 on invalid input
--*/
UINT KdGetProcHandleRef(HDATA *phHandle, UINT nPID)
{
if (nPID >= MAX_PROCESSES)
return -1;
else if (phHandle->ref.count >= 0x10000)
return phHandle->ref.pFr->usRefs[nPID];
else if ((phHandle->lock & (1 << nPID)) != 0)
return phHandle->ref.count;
else
return 0;
}
/*++
Routine Name:
KdQueryHandleFields
Routine Description:
This routine traverses the kernel handle list. It returns in the buffer a
list of handles matching specific APIs or owned by specific processes.
Arguments:
pHandleFields - [in/out] List of common fields for the handles
cbBufLen - [in] Length of pHandleFields buffer in bytes
The caller should fill out the "in" structure in pHandleFields according to
its description. The "out" structure is used to return results. See kdp.h
for more information about how this structure is used. If the length of the
buffer indicates that pHandleFields.out.nFields is valid, it will always
contain the number of fields on return. If the buffer is too small to hold
all data available, STATUS_BUFFER_TOO_SMALL will be returned and the buffer
will be filled with part of the data. For any other error, the contents of
pHandleFields is undefined.
Return Value:
STATUS_SUCCESS Success
STATUS_INVALID_PARAMETER Buffer lacks space for in/out headers
STATUS_BUFFER_TOO_SMALL Buffer is not large enough
--*/
NTSTATUS KdQueryHandleFields(PDBGKD_HANDLE_DESC_DATA pHandleFields,
UINT cbBufLen)
{
const UINT32 nAPIFilter = pHandleFields->in.nAPIFilter;
NTSTATUS status = STATUS_SUCCESS;
PCKD_API_DESC pAPIDesc;
UINT i, j, cFields, cBufFields;
DEBUGGERMSG(KDZONE_HANDLEEX, (L"++KdQueryHandleFields\r\n"));
DEBUGGERMSG(KDZONE_HANDLEEX, (L" PID Mask: %08lX, API Mask: %08lX\r\n",
pHandleFields->in.nPIDFilter, pHandleFields->in.nAPIFilter));
if (cbBufLen < sizeof(*pHandleFields))
{
status = STATUS_INVALID_PARAMETER;
goto CommonExit;
}
// Compute number of fields buffer has space for
cBufFields = (cbBufLen - sizeof(pHandleFields->out)) / sizeof(DBGKD_HANDLE_FIELD_DESC);
DEBUGGERMSG(KDZONE_HANDLEEX, (L" Buffer (addr=%08p, length=%u) has room for %u fields\r\n", pHandleFields, cbBufLen, cBufFields));
// If we're only looking at a single API, add some extra fields
if ((nAPIFilter & (nAPIFilter - 1)) == 0)
pAPIDesc = &g_pTypeMap[_CountTrailingZeros(nAPIFilter)];
else
pAPIDesc = &g_descNull;
cFields = lengthof(g_pGenericDesc) + pAPIDesc->cEntries;
if (cBufFields > cFields)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -