/*
* Process Hacker .NET Tools -
* CLR data access functions
*
* Copyright (C) 2011-2015 wj32
*
* This file is part of Process Hacker.
*
* Process Hacker is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Process Hacker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Process Hacker. If not, see .
*/
#ifndef CLRSUP_H
#define CLRSUP_H
#define CINTERFACE
#define COBJMACROS
#include
#undef CINTERFACE
#undef COBJMACROS
// General interfaces
typedef struct _CLR_PROCESS_SUPPORT
{
struct IXCLRDataProcess *DataProcess;
} CLR_PROCESS_SUPPORT, *PCLR_PROCESS_SUPPORT;
PCLR_PROCESS_SUPPORT CreateClrProcessSupport(
_In_ HANDLE ProcessId
);
VOID FreeClrProcessSupport(
_In_ PCLR_PROCESS_SUPPORT Support
);
PPH_STRING GetRuntimeNameByAddressClrProcess(
_In_ PCLR_PROCESS_SUPPORT Support,
_In_ ULONG64 Address,
_Out_opt_ PULONG64 Displacement
);
PPH_STRING GetNameXClrDataAppDomain(
_In_ PVOID AppDomain
);
PVOID LoadMscordacwks(
_In_ BOOLEAN IsClrV4
);
HRESULT CreateXCLRDataProcess(
_In_ HANDLE ProcessId,
_In_ ICLRDataTarget *Target,
_Out_ struct IXCLRDataProcess **DataProcess
);
// xclrdata
typedef ULONG64 CLRDATA_ENUM;
typedef struct IXCLRDataProcess IXCLRDataProcess;
typedef struct IXCLRDataAppDomain IXCLRDataAppDomain;
typedef struct IXCLRDataTask IXCLRDataTask;
typedef struct IXCLRDataStackWalk IXCLRDataStackWalk;
typedef struct IXCLRDataFrame IXCLRDataFrame;
typedef struct IXCLRDataProcessVtbl
{
HRESULT (STDMETHODCALLTYPE *QueryInterface)(
_In_ IXCLRDataProcess *This,
_In_ REFIID riid,
_Outptr_ void **ppvObject
);
ULONG (STDMETHODCALLTYPE *AddRef)(
_In_ IXCLRDataProcess *This
);
ULONG (STDMETHODCALLTYPE *Release)(
_In_ IXCLRDataProcess *This
);
HRESULT (STDMETHODCALLTYPE *Flush)(
_In_ IXCLRDataProcess *This
);
HRESULT (STDMETHODCALLTYPE *StartEnumTasks)(
_In_ IXCLRDataProcess *This,
_Out_ CLRDATA_ENUM *handle
);
HRESULT (STDMETHODCALLTYPE *EnumTask)(
_In_ IXCLRDataProcess *This,
_Inout_ CLRDATA_ENUM *handle,
_Out_ IXCLRDataTask **task
);
HRESULT (STDMETHODCALLTYPE *EndEnumTasks)(
_In_ IXCLRDataProcess *This,
_In_ CLRDATA_ENUM handle
);
HRESULT (STDMETHODCALLTYPE *GetTaskByOSThreadID)(
_In_ IXCLRDataProcess *This,
_In_ ULONG32 osThreadID,
_Out_ IXCLRDataTask **task
);
PVOID GetTaskByUniqueID;
PVOID GetFlags;
PVOID IsSameObject;
PVOID GetManagedObject;
PVOID GetDesiredExecutionState;
PVOID SetDesiredExecutionState;
PVOID GetAddressType;
HRESULT (STDMETHODCALLTYPE *GetRuntimeNameByAddress)(
_In_ IXCLRDataProcess *This,
_In_ CLRDATA_ADDRESS address,
_In_ ULONG32 flags,
_In_ ULONG32 bufLen,
_Out_ ULONG32 *nameLen,
_Out_ WCHAR *nameBuf,
_Out_ CLRDATA_ADDRESS *displacement
);
// ...
} IXCLRDataProcessVtbl;
typedef struct IXCLRDataProcess
{
struct IXCLRDataProcessVtbl *lpVtbl;
} IXCLRDataProcess;
#define IXCLRDataProcess_QueryInterface(This, riid, ppvObject) \
((This)->lpVtbl->QueryInterface(This, riid, ppvObject))
#define IXCLRDataProcess_AddRef(This) \
((This)->lpVtbl->AddRef(This))
#define IXCLRDataProcess_Release(This) \
((This)->lpVtbl->Release(This))
#define IXCLRDataProcess_GetRuntimeNameByAddress(This, address, flags, bufLen, nameLen, nameBuf, displacement) \
((This)->lpVtbl->GetRuntimeNameByAddress(This, address, flags, bufLen, nameLen, nameBuf, displacement))
#define IXCLRDataProcess_Flush(This) \
((This)->lpVtbl->Flush(This))
#define IXCLRDataProcess_StartEnumTasks(This, handle) \
((This)->lpVtbl->StartEnumTasks(This, handle))
#define IXCLRDataProcess_EnumTask(This, handle, task) \
((This)->lpVtbl->EnumTask(This, handle, task))
#define IXCLRDataProcess_EndEnumTasks(This, handle) \
((This)->lpVtbl->EndEnumTasks(This, handle))
#define IXCLRDataProcess_GetTaskByOSThreadID(This, osThreadID, task) \
((This)->lpVtbl->GetTaskByOSThreadID(This, osThreadID, task))
typedef struct IXCLRDataAppDomainVtbl
{
HRESULT (STDMETHODCALLTYPE *QueryInterface)(
_In_ IXCLRDataAppDomain *This,
_In_ REFIID riid,
_Outptr_ void **ppvObject
);
ULONG (STDMETHODCALLTYPE *AddRef)(
_In_ IXCLRDataAppDomain *This
);
ULONG (STDMETHODCALLTYPE *Release)(
_In_ IXCLRDataAppDomain *This
);
HRESULT (STDMETHODCALLTYPE *GetProcess)(
_In_ IXCLRDataAppDomain *This,
_Out_ IXCLRDataProcess **process
);
HRESULT (STDMETHODCALLTYPE *GetName)(
_In_ IXCLRDataAppDomain *This,
_In_ ULONG32 bufLen,
_Out_ ULONG32 *nameLen,
_Out_ WCHAR *name
);
HRESULT (STDMETHODCALLTYPE *GetUniqueID)(
_In_ IXCLRDataAppDomain *This,
_Out_ ULONG64 *id
);
// ...
} IXCLRDataAppDomainVtbl;
typedef struct IXCLRDataAppDomain
{
struct IXCLRDataAppDomainVtbl *lpVtbl;
} IXCLRDataAppDomain;
#define IXCLRDataAppDomain_QueryInterface(This, riid, ppvObject) \
((This)->lpVtbl->QueryInterface(This, riid, ppvObject))
#define IXCLRDataAppDomain_AddRef(This) \
((This)->lpVtbl->AddRef(This))
#define IXCLRDataAppDomain_Release(This) \
((This)->lpVtbl->Release(This))
#define IXCLRDataAppDomain_GetProcess(This, process) \
((This)->lpVtbl->GetProcess(This, process))
#define IXCLRDataAppDomain_GetName(This, bufLen, nameLen, name) \
((This)->lpVtbl->GetName(This, bufLen, nameLen, name))
#define IXCLRDataAppDomain_GetUniqueID(This, id) \
((This)->lpVtbl->GetUniqueID(This, id))
typedef struct IXCLRDataTaskVtbl
{
HRESULT (STDMETHODCALLTYPE *QueryInterface)(
_In_ IXCLRDataTask *This,
_In_ REFIID riid,
_Outptr_ void **ppvObject
);
ULONG (STDMETHODCALLTYPE *AddRef)(
_In_ IXCLRDataTask *This
);
ULONG (STDMETHODCALLTYPE *Release)(
_In_ IXCLRDataTask *This
);
HRESULT (STDMETHODCALLTYPE *GetProcess)(
_In_ IXCLRDataTask *This,
_Out_ IXCLRDataProcess **process
);
HRESULT (STDMETHODCALLTYPE *GetCurrentAppDomain)(
_In_ IXCLRDataTask *This,
_Out_ IXCLRDataAppDomain **appDomain
);
HRESULT (STDMETHODCALLTYPE *GetUniqueID)(
_In_ IXCLRDataTask *This,
_Out_ ULONG64 *id
);
HRESULT (STDMETHODCALLTYPE *GetFlags)(
_In_ IXCLRDataTask *This,
_Out_ ULONG32 *flags
);
PVOID IsSameObject;
PVOID GetManagedObject;
PVOID GetDesiredExecutionState;
PVOID SetDesiredExecutionState;
HRESULT (STDMETHODCALLTYPE *CreateStackWalk)(
_In_ IXCLRDataTask *This,
_In_ ULONG32 flags,
_Out_ IXCLRDataStackWalk **stackWalk
);
HRESULT (STDMETHODCALLTYPE *GetOSThreadID)(
_In_ IXCLRDataTask *This,
_Out_ ULONG32 *id
);
PVOID GetContext;
PVOID SetContext;
PVOID GetCurrentExceptionState;
PVOID Request;
HRESULT (STDMETHODCALLTYPE *GetName)(
_In_ IXCLRDataTask *This,
_In_ ULONG32 bufLen,
_Out_ ULONG32 *nameLen,
_Out_ WCHAR *name
);
PVOID GetLastExceptionState;
} IXCLRDataTaskVtbl;
typedef struct IXCLRDataTask
{
struct IXCLRDataTaskVtbl *lpVtbl;
} IXCLRDataTask;
#define IXCLRDataTask_QueryInterface(This, riid, ppvObject) \
((This)->lpVtbl->QueryInterface(This, riid, ppvObject))
#define IXCLRDataTask_AddRef(This) \
((This)->lpVtbl->AddRef(This))
#define IXCLRDataTask_Release(This) \
((This)->lpVtbl->Release(This))
#define IXCLRDataTask_GetProcess(This, process) \
((This)->lpVtbl->GetProcess(This, process))
#define IXCLRDataTask_GetCurrentAppDomain(This, appDomain) \
((This)->lpVtbl->GetCurrentAppDomain(This, appDomain))
#define IXCLRDataTask_GetUniqueID(This, id) \
((This)->lpVtbl->GetUniqueID(This, id))
#define IXCLRDataTask_GetFlags(This, flags) \
((This)->lpVtbl->GetFlags(This, flags))
#define IXCLRDataTask_CreateStackWalk(This, flags, stackWalk) \
((This)->lpVtbl->CreateStackWalk(This, flags, stackWalk))
#define IXCLRDataTask_GetOSThreadID(This, id) \
((This)->lpVtbl->GetOSThreadID(This, id))
#define IXCLRDataTask_GetName(This, bufLen, nameLen, name) \
((This)->lpVtbl->GetName(This, bufLen, nameLen, name))
typedef enum
{
CLRDATA_SIMPFRAME_UNRECOGNIZED = 0x1,
CLRDATA_SIMPFRAME_MANAGED_METHOD = 0x2,
CLRDATA_SIMPFRAME_RUNTIME_MANAGED_CODE = 0x4,
CLRDATA_SIMPFRAME_RUNTIME_UNMANAGED_CODE = 0x8
} CLRDataSimpleFrameType;
typedef enum
{
CLRDATA_DETFRAME_UNRECOGNIZED,
CLRDATA_DETFRAME_UNKNOWN_STUB,
CLRDATA_DETFRAME_CLASS_INIT,
CLRDATA_DETFRAME_EXCEPTION_FILTER,
CLRDATA_DETFRAME_SECURITY,
CLRDATA_DETFRAME_CONTEXT_POLICY,
CLRDATA_DETFRAME_INTERCEPTION,
CLRDATA_DETFRAME_PROCESS_START,
CLRDATA_DETFRAME_THREAD_START,
CLRDATA_DETFRAME_TRANSITION_TO_MANAGED,
CLRDATA_DETFRAME_TRANSITION_TO_UNMANAGED,
CLRDATA_DETFRAME_COM_INTEROP_STUB,
CLRDATA_DETFRAME_DEBUGGER_EVAL,
CLRDATA_DETFRAME_CONTEXT_SWITCH,
CLRDATA_DETFRAME_FUNC_EVAL,
CLRDATA_DETFRAME_FINALLY
} CLRDataDetailedFrameType;
typedef enum
{
CLRDATA_STACK_SET_UNWIND_CONTEXT = 0x00000000,
CLRDATA_STACK_SET_CURRENT_CONTEXT = 0x00000001
} CLRDataStackSetContextFlag;
typedef struct IXCLRDataStackWalkVtbl
{
HRESULT (STDMETHODCALLTYPE *QueryInterface)(
_In_ IXCLRDataStackWalk *This,
_In_ REFIID riid,
_Outptr_ void **ppvObject
);
ULONG (STDMETHODCALLTYPE *AddRef)(
_In_ IXCLRDataStackWalk *This
);
ULONG (STDMETHODCALLTYPE *Release)(
_In_ IXCLRDataStackWalk *This
);
HRESULT (STDMETHODCALLTYPE *GetContext)(
_In_ IXCLRDataStackWalk *This,
_In_ ULONG32 contextFlags,
_In_ ULONG32 contextBufSize,
_Out_ ULONG32 *contextSize,
_Out_ BYTE *contextBuf
);
PVOID SetContext;
HRESULT (STDMETHODCALLTYPE *Next)(
_In_ IXCLRDataStackWalk *This
);
HRESULT (STDMETHODCALLTYPE *GetStackSizeSkipped)(
_In_ IXCLRDataStackWalk *This,
_Out_ ULONG64 *stackSizeSkipped
);
HRESULT (STDMETHODCALLTYPE *GetFrameType)(
_In_ IXCLRDataStackWalk *This,
_Out_ CLRDataSimpleFrameType *simpleType,
_Out_ CLRDataDetailedFrameType *detailedType
);
HRESULT (STDMETHODCALLTYPE *GetFrame)(
_In_ IXCLRDataStackWalk *This,
_Out_ PVOID *frame
);
HRESULT (STDMETHODCALLTYPE *Request)(
_In_ IXCLRDataStackWalk *This,
_In_ ULONG32 reqCode,
_In_ ULONG32 inBufferSize,
_In_ BYTE *inBuffer,
_In_ ULONG32 outBufferSize,
_Out_ BYTE *outBuffer
);
HRESULT (STDMETHODCALLTYPE *SetContext2)(
_In_ IXCLRDataStackWalk *This,
_In_ ULONG32 flags,
_In_ ULONG32 contextSize,
_In_ BYTE *context
);
} IXCLRDataStackWalkVtbl;
typedef struct IXCLRDataStackWalk
{
struct IXCLRDataStackWalkVtbl *lpVtbl;
} IXCLRDataStackWalk;
#define IXCLRDataStackWalk_QueryInterface(This, riid, ppvObject) \
((This)->lpVtbl->QueryInterface(This, riid, ppvObject))
#define IXCLRDataStackWalk_AddRef(This) \
((This)->lpVtbl->AddRef(This))
#define IXCLRDataStackWalk_Release(This) \
((This)->lpVtbl->Release(This))
#define IXCLRDataStackWalk_GetContext(This, contextFlags, contextBufSize, contextSize, contextBuf) \
((This)->lpVtbl->GetContext(This, contextFlags, contextBufSize, contextSize, contextBuf))
#define IXCLRDataStackWalk_Next(This) \
((This)->lpVtbl->Next(This))
#define IXCLRDataStackWalk_GetStackSizeSkipped(This, stackSizeSkipped) \
((This)->lpVtbl->GetStackSizeSkipped(This, stackSizeSkipped))
#define IXCLRDataStackWalk_GetFrameType(This, simpleType, detailedType) \
((This)->lpVtbl->GetFrameType(This, simpleType, detailedType))
#define IXCLRDataStackWalk_GetFrame(This, frame) \
((This)->lpVtbl->GetFrame(This, frame))
#define IXCLRDataStackWalk_Request(This, reqCode, inBufferSize, inBuffer, outBufferSize, outBuffer) \
((This)->lpVtbl->SetContext2(This, reqCode, inBufferSize, inBuffer, outBufferSize, outBuffer))
#define IXCLRDataStackWalk_SetContext2(This, flags, contextSize, context) \
((This)->lpVtbl->SetContext2(This, flags, contextSize, context))
typedef struct IXCLRDataFrameVtbl
{
HRESULT (STDMETHODCALLTYPE *QueryInterface)(
_In_ IXCLRDataFrame *This,
_In_ REFIID riid,
_Outptr_ void **ppvObject
);
ULONG (STDMETHODCALLTYPE *AddRef)(
_In_ IXCLRDataFrame *This
);
ULONG (STDMETHODCALLTYPE *Release)(
_In_ IXCLRDataFrame *This
);
HRESULT (STDMETHODCALLTYPE *GetFrameType)(
_In_ IXCLRDataFrame *This,
_Out_ CLRDataSimpleFrameType *simpleType,
_Out_ CLRDataDetailedFrameType *detailedType
);
HRESULT (STDMETHODCALLTYPE *GetContext)(
_In_ IXCLRDataFrame *This,
_In_ ULONG32 contextFlags,
_In_ ULONG32 contextBufSize,
_Out_ ULONG32 *contextSize,
_Out_ BYTE *contextBuf
);
PVOID GetAppDomain;
PVOID GetNumArguments;
PVOID GetArgumentByIndex;
PVOID GetNumLocalVariables;
PVOID GetLocalVariableByIndex;
HRESULT (STDMETHODCALLTYPE *GetCodeName)(
_In_ IXCLRDataFrame *This,
_In_ ULONG32 *flags,
_In_ ULONG32 *bufLen,
_Out_ ULONG32 *nameLen,
_Out_ WCHAR *nameBuf
);
} IXCLRDataFrameVtbl;
typedef struct IXCLRDataFrame
{
IXCLRDataFrameVtbl *lpVtbl;
} IXCLRDataFrame;
#define IXCLRDataFrame_QueryInterface(This, riid, ppvObject) \
((This)->lpVtbl->QueryInterface(This, riid, ppvObject))
#define IXCLRDataFrame_AddRef(This) \
((This)->lpVtbl->AddRef(This))
#define IXCLRDataFrame_Release(This) \
((This)->lpVtbl->Release(This))
#define IXCLRDataFrame_GetFrameType(This, simpleType, detailedType) \
((This)->lpVtbl->GetFrameType(This, simpleType, detailedType))
#define IXCLRDataFrame_GetContext(This, contextFlags, contextBufSize, contextSize, contextBuf) \
((This)->lpVtbl->GetContext(This, contextFlags, contextBufSize, contextSize, contextBuf))
#define IXCLRDataFrame_GetCodeName(This, flags, bufLen, nameLen, nameBuf) \
((This)->lpVtbl->GetCodeName(This, flags, bufLen, nameLen, nameBuf))
// DnCLRDataTarget
typedef struct
{
ICLRDataTargetVtbl *VTable;
ULONG RefCount;
HANDLE ProcessId;
HANDLE ProcessHandle;
BOOLEAN IsWow64;
} DnCLRDataTarget;
ICLRDataTarget *DnCLRDataTarget_Create(
_In_ HANDLE ProcessId
);
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_QueryInterface(
_In_ ICLRDataTarget *This,
_In_ REFIID Riid,
_Out_ PVOID *Object
);
ULONG STDMETHODCALLTYPE DnCLRDataTarget_AddRef(
_In_ ICLRDataTarget *This
);
ULONG STDMETHODCALLTYPE DnCLRDataTarget_Release(
_In_ ICLRDataTarget *This
);
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetMachineType(
_In_ ICLRDataTarget *This,
_Out_ ULONG32 *machineType
);
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetPointerSize(
_In_ ICLRDataTarget *This,
_Out_ ULONG32 *pointerSize
);
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetImageBase(
_In_ ICLRDataTarget *This,
_In_ LPCWSTR imagePath,
_Out_ CLRDATA_ADDRESS *baseAddress
);
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_ReadVirtual(
_In_ ICLRDataTarget *This,
_In_ CLRDATA_ADDRESS address,
_Out_ BYTE *buffer,
_In_ ULONG32 bytesRequested,
_Out_ ULONG32 *bytesRead
);
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_WriteVirtual(
_In_ ICLRDataTarget *This,
_In_ CLRDATA_ADDRESS address,
_In_ BYTE *buffer,
_In_ ULONG32 bytesRequested,
_Out_ ULONG32 *bytesWritten
);
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetTLSValue(
_In_ ICLRDataTarget *This,
_In_ ULONG32 threadID,
_In_ ULONG32 index,
_Out_ CLRDATA_ADDRESS *value
);
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_SetTLSValue(
_In_ ICLRDataTarget *This,
_In_ ULONG32 threadID,
_In_ ULONG32 index,
_In_ CLRDATA_ADDRESS value
);
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetCurrentThreadID(
_In_ ICLRDataTarget *This,
_Out_ ULONG32 *threadID
);
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetThreadContext(
_In_ ICLRDataTarget *This,
_In_ ULONG32 threadID,
_In_ ULONG32 contextFlags,
_In_ ULONG32 contextSize,
_Out_ BYTE *context
);
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_SetThreadContext(
_In_ ICLRDataTarget *This,
_In_ ULONG32 threadID,
_In_ ULONG32 contextSize,
_In_ BYTE *context
);
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_Request(
_In_ ICLRDataTarget *This,
_In_ ULONG32 reqCode,
_In_ ULONG32 inBufferSize,
_In_ BYTE *inBuffer,
_In_ ULONG32 outBufferSize,
_Out_ BYTE *outBuffer
);
typedef struct _PHP_GET_IMAGE_BASE_CONTEXT
{
UNICODE_STRING ImagePath;
PVOID BaseAddress;
} PHP_GET_IMAGE_BASE_CONTEXT, *PPHP_GET_IMAGE_BASE_CONTEXT;
#endif