mirror of
https://github.com/scrt/PowerChell
synced 2026-06-06 16:44:30 +00:00
700 lines
24 KiB
C++
700 lines
24 KiB
C++
#include "common.h"
|
|
#include "clr.h"
|
|
|
|
BOOL clr::InitializeCommonLanguageRuntime(PCLR_CONTEXT pClrContext, mscorlib::_AppDomain** ppAppDomain)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
HRESULT hr;
|
|
ICLRMetaHost* pMetaHost = NULL;
|
|
ICLRRuntimeInfo* pRuntimeInfo = NULL;
|
|
ICorRuntimeHost* pRuntimeHost = NULL;
|
|
IUnknown* pAppDomainThunk = NULL;
|
|
BOOL bIsLoadable;
|
|
|
|
mscorlib::_AppDomain* pAppDomain = NULL;
|
|
|
|
hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, reinterpret_cast<PVOID*>(&pMetaHost));
|
|
EXIT_ON_HRESULT_ERROR(L"CLRCreateInstance", hr);
|
|
|
|
hr = pMetaHost->GetRuntime(L"v4.0.30319", IID_ICLRRuntimeInfo, reinterpret_cast<PVOID*>(&pRuntimeInfo));
|
|
EXIT_ON_HRESULT_ERROR(L"IMetaHost->GetRuntime", hr);
|
|
|
|
hr = pRuntimeInfo->IsLoadable(&bIsLoadable);
|
|
EXIT_ON_HRESULT_ERROR(L"IRuntimeInfo->IsLoadable", hr);
|
|
|
|
hr = pRuntimeInfo->GetInterface(CLSID_CorRuntimeHost, IID_ICorRuntimeHost, reinterpret_cast<PVOID*>(&pRuntimeHost));
|
|
EXIT_ON_HRESULT_ERROR(L"IRuntimeInfo->GetInterface", hr);
|
|
|
|
hr = pRuntimeHost->Start();
|
|
EXIT_ON_HRESULT_ERROR(L"IRuntimeHost->Start", hr);
|
|
|
|
hr = pRuntimeHost->CreateDomain(APP_DOMAIN, nullptr, &pAppDomainThunk);
|
|
EXIT_ON_HRESULT_ERROR(L"IRuntimeHost->CreateDomain", hr);
|
|
|
|
hr = pAppDomainThunk->QueryInterface(IID_PPV_ARGS(&pAppDomain));
|
|
EXIT_ON_HRESULT_ERROR(L"IAppDomainThunk->QueryInterface", hr);
|
|
|
|
pClrContext->pMetaHost = pMetaHost;
|
|
pClrContext->pRuntimeInfo = pRuntimeInfo;
|
|
pClrContext->pRuntimeHost = pRuntimeHost;
|
|
pClrContext->pAppDomainThunk = pAppDomainThunk;
|
|
*ppAppDomain = pAppDomain;
|
|
bResult = TRUE;
|
|
|
|
exit:
|
|
if (!bResult && pAppDomain) pAppDomain->Release();
|
|
if (!bResult && pAppDomainThunk) pAppDomainThunk->Release();
|
|
if (!bResult && pRuntimeHost) pRuntimeHost->Release();
|
|
if (!bResult && pRuntimeInfo) pRuntimeInfo->Release();
|
|
if (!bResult && pMetaHost) pMetaHost->Release();
|
|
|
|
return bResult;
|
|
}
|
|
|
|
void clr::DestroyCommonLanguageRuntime(PCLR_CONTEXT pClrContext, mscorlib::_AppDomain* pAppDomain)
|
|
{
|
|
if (pAppDomain) pAppDomain->Release();
|
|
if (pClrContext->pAppDomainThunk) pClrContext->pAppDomainThunk->Release();
|
|
if (pClrContext->pRuntimeHost) pClrContext->pRuntimeHost->Release();
|
|
if (pClrContext->pRuntimeInfo) pClrContext->pRuntimeInfo->Release();
|
|
if (pClrContext->pMetaHost) pClrContext->pMetaHost->Release();
|
|
}
|
|
|
|
BOOL clr::FindAssemblyPath(LPCWSTR pwszAssemblyName, LPWSTR* ppwszAssemblyPath)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
WIN32_FIND_DATA ffd = { 0 };
|
|
LPCWSTR pwszAssemblyFolderPath = L"C:\\Windows\\Microsoft.NET\\assembly\\GAC_MSIL";
|
|
LPWSTR pwszSearchPath = NULL;
|
|
LPWSTR pwszAssemblyPath = NULL;
|
|
HANDLE hFind = NULL;
|
|
HANDLE hAssemblyFile = NULL;
|
|
|
|
pwszSearchPath = (LPWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_PATH * sizeof(*pwszSearchPath));
|
|
EXIT_ON_WIN32_ERROR(L"HeapAlloc", pwszSearchPath == NULL);
|
|
|
|
pwszAssemblyPath = (LPWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_PATH * sizeof(*pwszAssemblyPath));
|
|
EXIT_ON_WIN32_ERROR(L"HeapAlloc", pwszAssemblyPath == NULL);
|
|
|
|
swprintf_s(pwszSearchPath, MAX_PATH, L"%ws\\%ws\\*", pwszAssemblyFolderPath, pwszAssemblyName);
|
|
|
|
hFind = FindFirstFileW(pwszSearchPath, &ffd);
|
|
EXIT_ON_WIN32_ERROR(L"FindFirstFileW", hFind == INVALID_HANDLE_VALUE);
|
|
|
|
do
|
|
{
|
|
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
{
|
|
swprintf_s(pwszAssemblyPath, MAX_PATH, L"%ws\\%ws\\%ws\\%ws.dll", pwszAssemblyFolderPath, pwszAssemblyName, ffd.cFileName, pwszAssemblyName);
|
|
hAssemblyFile = CreateFileW(pwszAssemblyPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if (hAssemblyFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
bResult = TRUE;
|
|
CloseHandle(hAssemblyFile);
|
|
break;
|
|
}
|
|
}
|
|
} while (FindNextFileW(hFind, &ffd) != 0);
|
|
|
|
if (!bResult) goto exit;
|
|
|
|
*ppwszAssemblyPath = pwszAssemblyPath;
|
|
|
|
exit:
|
|
if (hFind && hFind != INVALID_HANDLE_VALUE) FindClose(hFind);
|
|
if (!bResult && pwszAssemblyPath) HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, pwszAssemblyPath);
|
|
if (pwszSearchPath) HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, pwszSearchPath);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
BOOL clr::GetAssembly(mscorlib::_AppDomain* pAppDomain, LPCWSTR pwszAssemblyName, mscorlib::_Assembly** ppAssembly)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
HRESULT hr;
|
|
LONG lAssembliesLowerBound, lAssembliesUpperBound;
|
|
LONG lTargetAssemblyNameLength, lCurrentAssemblyNameLength, lAssemblyNameIndex;
|
|
BSTR bstrAssemblyFullName;
|
|
SAFEARRAY* pLoadedAssembliesArray = NULL;
|
|
mscorlib::_Assembly** ppLoadedAssemblies = NULL;
|
|
|
|
lTargetAssemblyNameLength = (LONG)wcslen(pwszAssemblyName);
|
|
|
|
hr = pAppDomain->GetAssemblies(&pLoadedAssembliesArray);
|
|
EXIT_ON_HRESULT_ERROR(L"AppDomain->GetAssemblies", hr);
|
|
|
|
SafeArrayGetLBound(pLoadedAssembliesArray, 1, &lAssembliesLowerBound);
|
|
SafeArrayGetUBound(pLoadedAssembliesArray, 1, &lAssembliesUpperBound);
|
|
|
|
hr = SafeArrayAccessData(pLoadedAssembliesArray, (void**)&ppLoadedAssemblies);
|
|
EXIT_ON_HRESULT_ERROR(L"SafeArrayAccessData", hr);
|
|
|
|
for (int i = 0; i < lAssembliesUpperBound - lAssembliesLowerBound + 1; i++)
|
|
{
|
|
bstrAssemblyFullName = NULL;
|
|
hr = ppLoadedAssemblies[i]->get_FullName(&bstrAssemblyFullName);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// If the target assembly name is 'Some.Assembly.Name', check whether
|
|
// the current assembly's full name starts with 'Some.Assembly.Name,'.
|
|
// As an example, the full name of the 'System.Management.Automation'
|
|
// assembly would be something like:
|
|
// System.Management.Automation, Version=3.0.0.0, Culture=neutral,
|
|
// PublicKeyToken=31bf3856ad364e35
|
|
//
|
|
|
|
lCurrentAssemblyNameLength = (LONG)wcslen(bstrAssemblyFullName);
|
|
|
|
if (lCurrentAssemblyNameLength > lTargetAssemblyNameLength)
|
|
{
|
|
for (lAssemblyNameIndex = 0; lAssemblyNameIndex < lTargetAssemblyNameLength; lAssemblyNameIndex++)
|
|
{
|
|
if (pwszAssemblyName[lAssemblyNameIndex] != bstrAssemblyFullName[lAssemblyNameIndex])
|
|
break;
|
|
}
|
|
|
|
if (lAssemblyNameIndex == lTargetAssemblyNameLength)
|
|
{
|
|
if (bstrAssemblyFullName[lAssemblyNameIndex] == L',')
|
|
{
|
|
bResult = TRUE;
|
|
*ppAssembly = ppLoadedAssemblies[i];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
SysFreeString(bstrAssemblyFullName);
|
|
}
|
|
}
|
|
|
|
exit:
|
|
if (pLoadedAssembliesArray) SafeArrayDestroy(pLoadedAssembliesArray);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
BOOL clr::LoadAssembly(mscorlib::_AppDomain* pAppDomain, LPCWSTR pwszAssemblyName, mscorlib::_Assembly** ppAssembly)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
HRESULT hr;
|
|
DWORD dwBytesRead;
|
|
HANDLE hAssemblyFile = NULL;
|
|
LPWSTR pwszAssemblyPath = NULL;
|
|
LARGE_INTEGER liAssemblyFileSize = { 0 };
|
|
SAFEARRAYBOUND sab = { 0 };
|
|
SAFEARRAY* pSafeAssembly = NULL;
|
|
mscorlib::_Assembly* pAssembly = NULL;
|
|
|
|
// Check if assembly is already loaded
|
|
if (!clr::GetAssembly(pAppDomain, pwszAssemblyName, &pAssembly))
|
|
{
|
|
if (!clr::FindAssemblyPath(pwszAssemblyName, &pwszAssemblyPath))
|
|
goto exit;
|
|
|
|
hAssemblyFile = CreateFileW(pwszAssemblyPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
EXIT_ON_WIN32_ERROR(L"CreateFileW", hAssemblyFile == INVALID_HANDLE_VALUE);
|
|
EXIT_ON_WIN32_ERROR(L"GetFileSizeEx", GetFileSizeEx(hAssemblyFile, &liAssemblyFileSize) == FALSE);
|
|
|
|
sab = { (ULONG)liAssemblyFileSize.QuadPart, 0 };
|
|
pSafeAssembly = SafeArrayCreate(VT_UI1, 1, &sab);
|
|
|
|
EXIT_ON_WIN32_ERROR(L"ReadFile", ReadFile(hAssemblyFile, pSafeAssembly->pvData, (DWORD)liAssemblyFileSize.QuadPart, &dwBytesRead, NULL) == FALSE);
|
|
|
|
hr = pAppDomain->Load_3(pSafeAssembly, &pAssembly);
|
|
EXIT_ON_HRESULT_ERROR(L"AppDomain->Load_3", hr);
|
|
}
|
|
|
|
*ppAssembly = pAssembly;
|
|
bResult = TRUE;
|
|
|
|
exit:
|
|
if (pSafeAssembly) SafeArrayDestroy(pSafeAssembly);
|
|
if (hAssemblyFile && hAssemblyFile != INVALID_HANDLE_VALUE) CloseHandle(hAssemblyFile);
|
|
if (pwszAssemblyPath) HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, pwszAssemblyPath);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
BOOL clr::CreateInstance(mscorlib::_AppDomain* pAppDomain, LPCWSTR pwszAssemblyName, LPCWSTR pwszClassName, VARIANT* pvtInstance)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
HRESULT hr;
|
|
BSTR bstrClassName = SysAllocString(pwszClassName);
|
|
VARIANT vtInstance = { 0 };
|
|
mscorlib::_Assembly* pAssembly = NULL;
|
|
|
|
if (!clr::LoadAssembly(pAppDomain, pwszAssemblyName, &pAssembly))
|
|
goto exit;
|
|
|
|
hr = pAssembly->CreateInstance(bstrClassName, &vtInstance);
|
|
EXIT_ON_HRESULT_ERROR(L"Assembly->CreateInstance", hr);
|
|
|
|
memcpy_s(pvtInstance, sizeof(*pvtInstance), &vtInstance, sizeof(vtInstance));
|
|
bResult = TRUE;
|
|
|
|
exit:
|
|
if (bstrClassName) SysFreeString(bstrClassName);
|
|
if (pAssembly) pAssembly->Release();
|
|
|
|
return bResult;
|
|
}
|
|
|
|
BOOL clr::GetType(mscorlib::_AppDomain* pAppDomain, LPCWSTR pwszAssemblyName, LPCWSTR pwszTypeFullName, mscorlib::_Type** ppType)
|
|
{
|
|
HRESULT hr;
|
|
BOOL bResult = FALSE;
|
|
BSTR bstrTypeFullName = SysAllocString(pwszTypeFullName);
|
|
mscorlib::_Assembly* pAssembly = NULL;
|
|
mscorlib::_Type* pType = NULL;
|
|
|
|
if (!clr::LoadAssembly(pAppDomain, pwszAssemblyName, &pAssembly))
|
|
goto exit;
|
|
|
|
hr = pAssembly->GetType_2(bstrTypeFullName, &pType);
|
|
EXIT_ON_HRESULT_ERROR(L"Assembly->GetType_2", hr);
|
|
EXIT_ON_NULL_POINTER(pwszTypeFullName, pType);
|
|
|
|
*ppType = pType;
|
|
bResult = TRUE;
|
|
|
|
exit:
|
|
if (bstrTypeFullName) SysFreeString(bstrTypeFullName);
|
|
if (pAssembly) pAssembly->Release();
|
|
|
|
return bResult;
|
|
}
|
|
|
|
BOOL clr::GetProperty(mscorlib::_Type* pType, mscorlib::BindingFlags bindingFlags, LPCWSTR pwszPropertyName, mscorlib::_PropertyInfo** ppPropertyInfo)
|
|
{
|
|
HRESULT hr;
|
|
BOOL bResult = FALSE;
|
|
BSTR bstrPropertyName = SysAllocString(pwszPropertyName);
|
|
mscorlib::_PropertyInfo* pPropertyInfo = NULL;
|
|
|
|
hr = pType->GetProperty(bstrPropertyName, bindingFlags, &pPropertyInfo);
|
|
EXIT_ON_HRESULT_ERROR(L"Type->GetProperty", hr);
|
|
EXIT_ON_NULL_POINTER(pwszPropertyName, pPropertyInfo);
|
|
|
|
*ppPropertyInfo = pPropertyInfo;
|
|
bResult = TRUE;
|
|
|
|
exit:
|
|
if (bstrPropertyName) SysFreeString(bstrPropertyName);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
BOOL clr::GetPropertyValue(mscorlib::_Type* pType, mscorlib::BindingFlags bindingFlags, VARIANT vtObject, LPCWSTR pwszPropertyName, VARIANT* pvtPropertyValue)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
HRESULT hr;
|
|
VARIANT vtPropertyValue = { 0 };
|
|
mscorlib::_PropertyInfo* pPropertyInfo = NULL;
|
|
|
|
if (!clr::GetProperty(pType, bindingFlags, pwszPropertyName, &pPropertyInfo))
|
|
goto exit;
|
|
|
|
hr = pPropertyInfo->GetValue(vtObject, NULL, &vtPropertyValue);
|
|
EXIT_ON_HRESULT_ERROR(L"PropertyInfo->GetValue", hr);
|
|
|
|
memcpy_s(pvtPropertyValue, sizeof(*pvtPropertyValue), &vtPropertyValue, sizeof(vtPropertyValue));
|
|
bResult = TRUE;
|
|
|
|
exit:
|
|
if (pPropertyInfo) pPropertyInfo->Release();
|
|
|
|
return bResult;
|
|
}
|
|
|
|
BOOL clr::GetField(mscorlib::_Type* pType, mscorlib::BindingFlags bindingFlags, LPCWSTR pwszFieldName, mscorlib::_FieldInfo** ppFieldInfo)
|
|
{
|
|
HRESULT hr;
|
|
BOOL bResult = FALSE;
|
|
BSTR bstrFieldName = SysAllocString(pwszFieldName);
|
|
mscorlib::_FieldInfo* pFieldInfo = NULL;
|
|
|
|
hr = pType->GetField(bstrFieldName, bindingFlags, &pFieldInfo);
|
|
EXIT_ON_HRESULT_ERROR(L"Type->GetField", hr);
|
|
EXIT_ON_NULL_POINTER(pwszFieldName, pFieldInfo);
|
|
|
|
*ppFieldInfo = pFieldInfo;
|
|
bResult = TRUE;
|
|
|
|
exit:
|
|
if (bstrFieldName) SysFreeString(bstrFieldName);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
BOOL clr::GetFieldValue(mscorlib::_Type* pType, mscorlib::BindingFlags bindingFlags, VARIANT vtObject, LPCWSTR pwszFieldName, VARIANT* pvtFieldValue)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
HRESULT hr;
|
|
VARIANT vtValue = { 0 };
|
|
mscorlib::_FieldInfo* pFieldInfo = NULL;
|
|
|
|
if (!clr::GetField(pType, bindingFlags, pwszFieldName, &pFieldInfo))
|
|
goto exit;
|
|
|
|
hr = pFieldInfo->GetValue(vtObject, &vtValue);
|
|
EXIT_ON_HRESULT_ERROR(L"FieldInfo->GetValue", hr);
|
|
|
|
memcpy_s(pvtFieldValue, sizeof(*pvtFieldValue), &vtValue, sizeof(vtValue));
|
|
bResult = TRUE;
|
|
|
|
exit:
|
|
if (pFieldInfo) pFieldInfo->Release();
|
|
|
|
return bResult;
|
|
}
|
|
|
|
BOOL clr::GetMethod(mscorlib::_Type* pType, mscorlib::BindingFlags bindingFlags, LPCWSTR pwszMethodName, LONG lNbArg, mscorlib::_MethodInfo** ppMethodInfo)
|
|
{
|
|
HRESULT hr;
|
|
BOOL bResult = FALSE;
|
|
SAFEARRAY* pMethods = NULL;
|
|
mscorlib::_MethodInfo* pMethodInfo;
|
|
|
|
hr = pType->GetMethods(bindingFlags, &pMethods);
|
|
EXIT_ON_HRESULT_ERROR(L"Type->GetMethods", hr);
|
|
|
|
if (!clr::FindMethodInArray(pMethods, pwszMethodName, lNbArg, &pMethodInfo))
|
|
goto exit;
|
|
|
|
*ppMethodInfo = pMethodInfo;
|
|
bResult = TRUE;
|
|
|
|
exit:
|
|
if (pMethods) SafeArrayDestroy(pMethods);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
BOOL clr::InvokeMethod(mscorlib::_MethodInfo* pMethodInfo, VARIANT vtObject, SAFEARRAY* pParameters, VARIANT* pvtResult)
|
|
{
|
|
HRESULT hr;
|
|
BOOL bResult = FALSE;
|
|
|
|
hr = pMethodInfo->Invoke_3(vtObject, pParameters, pvtResult);
|
|
EXIT_ON_HRESULT_ERROR(L"MethodInfo->Invoke_3", hr);
|
|
|
|
bResult = TRUE;
|
|
|
|
exit:
|
|
return bResult;
|
|
}
|
|
|
|
BOOL clr::FindMethodInArray(SAFEARRAY* pMethods, LPCWSTR pwszMethodName, LONG lNbArgs, mscorlib::_MethodInfo** ppMethodInfo)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
HRESULT hr;
|
|
LONG lMethodsLowerBound, lMethodsUpperBound;
|
|
LONG lParametersLowerBound, lParametersUpperBound;
|
|
BSTR bstrMethodName;
|
|
SAFEARRAY* pParameters = NULL;
|
|
mscorlib::_MethodInfo** ppMethods = NULL;
|
|
mscorlib::_MethodInfo* pTargetMethodInfo = NULL;
|
|
|
|
SafeArrayGetLBound(pMethods, 1, &lMethodsLowerBound);
|
|
SafeArrayGetUBound(pMethods, 1, &lMethodsUpperBound);
|
|
|
|
hr = SafeArrayAccessData(pMethods, (void**)&ppMethods);
|
|
EXIT_ON_HRESULT_ERROR(L"SafeArrayAccessData", hr);
|
|
|
|
for (int i = 0; i < lMethodsUpperBound - lMethodsLowerBound + 1; i++)
|
|
{
|
|
bstrMethodName = NULL;
|
|
hr = ppMethods[i]->get_name(&bstrMethodName);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (_wcsicmp(bstrMethodName, pwszMethodName) == 0)
|
|
{
|
|
hr = ppMethods[i]->GetParameters(&pParameters);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
SafeArrayGetLBound(pParameters, 1, &lParametersLowerBound);
|
|
SafeArrayGetUBound(pParameters, 1, &lParametersUpperBound);
|
|
|
|
if (lParametersUpperBound - lParametersLowerBound + 1 == lNbArgs)
|
|
{
|
|
pTargetMethodInfo = ppMethods[i];
|
|
break;
|
|
}
|
|
|
|
SafeArrayDestroy(pParameters);
|
|
}
|
|
}
|
|
|
|
SysFreeString(bstrMethodName);
|
|
}
|
|
}
|
|
|
|
if (!pTargetMethodInfo)
|
|
{
|
|
PRINT_ERROR("Could not find a method named '%ws' with %d arguments.\n", pwszMethodName, lNbArgs);
|
|
goto exit;
|
|
}
|
|
|
|
bResult = TRUE;
|
|
*ppMethodInfo = pTargetMethodInfo;
|
|
|
|
exit:
|
|
return bResult;
|
|
}
|
|
|
|
BOOL clr::PrepareMethod(mscorlib::_AppDomain* pAppDomain, VARIANT* pvtMethodHandle)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
LONG lArgumentIndex;
|
|
SAFEARRAY* pPrepareMethodArguments = NULL;
|
|
VARIANT vtEmpty = { 0 };
|
|
VARIANT vtResult = { 0 };
|
|
mscorlib::_Type* pRuntimeHelpersType = NULL;
|
|
mscorlib::_MethodInfo* pPrepareMethod = NULL;
|
|
|
|
if (!clr::GetType(pAppDomain, ASSEMBLY_NAME_SYSTEM_RUNTIME, L"System.Runtime.CompilerServices.RuntimeHelpers", &pRuntimeHelpersType))
|
|
goto exit;
|
|
|
|
if (!clr::GetMethod(pRuntimeHelpersType, static_cast<mscorlib::BindingFlags>(BINDING_FLAGS_PUBLIC_STATIC), L"PrepareMethod", 1, &pPrepareMethod))
|
|
goto exit;
|
|
|
|
pPrepareMethodArguments = SafeArrayCreateVector(VT_VARIANT, 0, 1);
|
|
|
|
lArgumentIndex = 0;
|
|
SafeArrayPutElement(pPrepareMethodArguments, &lArgumentIndex, pvtMethodHandle);
|
|
|
|
if (!clr::InvokeMethod(pPrepareMethod, vtEmpty, pPrepareMethodArguments, &vtResult))
|
|
goto exit;
|
|
|
|
bResult = TRUE;
|
|
|
|
exit:
|
|
if (pPrepareMethodArguments) SafeArrayDestroy(pPrepareMethodArguments);
|
|
|
|
if (pPrepareMethod) pPrepareMethod->Release();
|
|
if (pRuntimeHelpersType) pRuntimeHelpersType->Release();
|
|
|
|
VariantClear(&vtResult);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
BOOL clr::GetFunctionPointer(mscorlib::_AppDomain* pAppDomain, VARIANT* pvtMethodHandle, PULONG_PTR pFunctionPointer)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
VARIANT vtFunctionPointer = { 0 };
|
|
mscorlib::_Type* pRuntimeMethodHandleType = NULL;
|
|
mscorlib::_MethodInfo* pGetFunctionPointerInfo = NULL;
|
|
|
|
if (!clr::GetType(pAppDomain, ASSEMBLY_NAME_SYSTEM_RUNTIME, L"System.RuntimeMethodHandle", &pRuntimeMethodHandleType))
|
|
goto exit;
|
|
|
|
if (!clr::GetMethod(pRuntimeMethodHandleType, static_cast<mscorlib::BindingFlags>(BINDING_FLAGS_PUBLIC_INSTANCE), L"GetFunctionPointer", 0, &pGetFunctionPointerInfo))
|
|
goto exit;
|
|
|
|
if (!clr::InvokeMethod(pGetFunctionPointerInfo, *pvtMethodHandle, NULL, &vtFunctionPointer))
|
|
goto exit;
|
|
|
|
*pFunctionPointer = vtFunctionPointer.ullVal;
|
|
bResult = TRUE;
|
|
|
|
exit:
|
|
if (pGetFunctionPointerInfo) pGetFunctionPointerInfo->Release();
|
|
if (pRuntimeMethodHandleType) pRuntimeMethodHandleType->Release();
|
|
|
|
return bResult;
|
|
}
|
|
|
|
BOOL clr::GetJustInTimeMethodAddress(mscorlib::_AppDomain* pAppDomain, LPCWSTR pwszAssemblyName, LPCWSTR pwszClassName, LPCWSTR pwszMethodName, DWORD dwNbArgs, PULONG_PTR pMethodAddress)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
VARIANT vtMethodHandlePtr = { 0 };
|
|
VARIANT vtMethodHandleVal = { 0 };
|
|
mscorlib::_Type* pType = NULL;
|
|
mscorlib::_Type* pMethodInfoType = NULL;
|
|
mscorlib::_MethodInfo* pTargetMethodInfo = NULL;
|
|
|
|
// Here, we include as many binding flags as we can so that we can list
|
|
// ALL the methods of the target class.
|
|
mscorlib::BindingFlags flags = static_cast<mscorlib::BindingFlags>(
|
|
mscorlib::BindingFlags::BindingFlags_Instance |
|
|
mscorlib::BindingFlags::BindingFlags_Static |
|
|
mscorlib::BindingFlags::BindingFlags_Public |
|
|
mscorlib::BindingFlags::BindingFlags_NonPublic |
|
|
mscorlib::BindingFlags::BindingFlags_DeclaredOnly
|
|
);
|
|
|
|
if (!clr::GetType(pAppDomain, pwszAssemblyName, pwszClassName, &pType))
|
|
goto exit;
|
|
|
|
if (!clr::GetMethod(pType, flags, pwszMethodName, dwNbArgs, &pTargetMethodInfo))
|
|
goto exit;
|
|
|
|
//
|
|
// The method for obtaining the MethodHandle from the MethodInfo object is
|
|
// taken from this article.
|
|
//
|
|
// Credit:
|
|
// - https://www.outflank.nl/blog/2024/02/01/unmanaged-dotnet-patching/
|
|
//
|
|
|
|
if (!clr::GetType(pAppDomain, ASSEMBLY_NAME_SYSTEM_REFLECTION, L"System.Reflection.MethodInfo", &pMethodInfoType))
|
|
goto exit;
|
|
|
|
vtMethodHandlePtr.vt = VT_UNKNOWN;
|
|
vtMethodHandlePtr.punkVal = pTargetMethodInfo;
|
|
|
|
if (!clr::GetPropertyValue(pMethodInfoType, static_cast<mscorlib::BindingFlags>(BINDING_FLAGS_PUBLIC_INSTANCE), vtMethodHandlePtr, L"MethodHandle", &vtMethodHandleVal))
|
|
goto exit;
|
|
|
|
//
|
|
// Next, we can invoke 'RuntimeHelpers.PrepareMethod' to make sure the target
|
|
// method is JIT-compiled, and finally get its effective address.
|
|
//
|
|
// Credit:
|
|
// - https://github.com/calebstewart/bypass-clm
|
|
// - https://www.mdsec.co.uk/2020/08/massaging-your-clr-preventing-environment-exit-in-in-process-net-assemblies/
|
|
//
|
|
|
|
if (!PrepareMethod(pAppDomain, &vtMethodHandleVal))
|
|
goto exit;
|
|
|
|
if (!GetFunctionPointer(pAppDomain, &vtMethodHandleVal, pMethodAddress))
|
|
goto exit;
|
|
|
|
bResult = TRUE;
|
|
|
|
exit:
|
|
if (pTargetMethodInfo) pTargetMethodInfo->Release();
|
|
if (pType) pType->Release();
|
|
if (pMethodInfoType) pMethodInfoType->Release();
|
|
|
|
VariantClear(&vtMethodHandleVal);
|
|
VariantClear(&vtMethodHandlePtr);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
BOOL dotnet::System_Object_GetType(mscorlib::_AppDomain* pAppDomain, VARIANT vtObject, VARIANT* pvtObjectType)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
VARIANT vtGetTypeResult = { 0 };
|
|
mscorlib::_Type* pObjectType = NULL;
|
|
mscorlib::_MethodInfo* pGetTypeMethodInfo = NULL;
|
|
|
|
if (!clr::GetType(pAppDomain, ASSEMBLY_NAME_SYSTEM_RUNTIME, L"System.Object", &pObjectType))
|
|
goto exit;
|
|
|
|
if (!clr::GetMethod(pObjectType, static_cast<mscorlib::BindingFlags>(BINDING_FLAGS_PUBLIC_INSTANCE), L"GetType", 0, &pGetTypeMethodInfo))
|
|
goto exit;
|
|
|
|
if (!clr::InvokeMethod(pGetTypeMethodInfo, vtObject, NULL, &vtGetTypeResult))
|
|
goto exit;
|
|
|
|
memcpy_s(pvtObjectType, sizeof(*pvtObjectType), &vtGetTypeResult, sizeof(vtGetTypeResult));
|
|
bResult = TRUE;
|
|
|
|
exit:
|
|
if (pGetTypeMethodInfo) pGetTypeMethodInfo->Release();
|
|
if (pObjectType) pObjectType->Release();
|
|
|
|
return bResult;
|
|
}
|
|
|
|
BOOL dotnet::System_Type_GetProperty(mscorlib::_AppDomain* pAppDomain, VARIANT vtTypeObject, LPCWSTR pwszPropertyName, VARIANT* pvtPropertyInfo)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
LONG lArgumentIndex;
|
|
VARIANT vtPropertyName = { 0 };
|
|
VARIANT vtPropertyInfo = { 0 };
|
|
SAFEARRAY* pGetPropertyArguments = NULL;
|
|
mscorlib::_Type* pTypeType = NULL;
|
|
mscorlib::_MethodInfo* pGetPropertyMethodInfo = NULL;
|
|
|
|
if (!clr::GetType(pAppDomain, ASSEMBLY_NAME_SYSTEM_RUNTIME, L"System.Type", &pTypeType))
|
|
goto exit;
|
|
|
|
if (!clr::GetMethod(pTypeType, static_cast<mscorlib::BindingFlags>(BINDING_FLAGS_PUBLIC_INSTANCE), L"GetProperty", 1, &pGetPropertyMethodInfo))
|
|
goto exit;
|
|
|
|
InitVariantFromString(pwszPropertyName, &vtPropertyName);
|
|
pGetPropertyArguments = SafeArrayCreateVector(VT_VARIANT, 0, 1);
|
|
|
|
lArgumentIndex = 0;
|
|
SafeArrayPutElement(pGetPropertyArguments, &lArgumentIndex, &vtPropertyName);
|
|
|
|
if (!clr::InvokeMethod(pGetPropertyMethodInfo, vtTypeObject, pGetPropertyArguments, &vtPropertyInfo))
|
|
goto exit;
|
|
|
|
memcpy_s(pvtPropertyInfo, sizeof(*pvtPropertyInfo), &vtPropertyInfo, sizeof(vtPropertyInfo));
|
|
bResult = TRUE;
|
|
|
|
exit:
|
|
if (pGetPropertyArguments) SafeArrayDestroy(pGetPropertyArguments);
|
|
|
|
if (pGetPropertyMethodInfo) pGetPropertyMethodInfo->Release();
|
|
if (pTypeType) pTypeType->Release();
|
|
|
|
VariantClear(&vtPropertyName);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
BOOL dotnet::System_Reflection_PropertyInfo_GetValue(mscorlib::_AppDomain* pAppDomain, VARIANT vtPropertyInfo, VARIANT vtObject, SAFEARRAY* pIndex, VARIANT* pvtValue)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
LONG lNbArguments;
|
|
LONG lArgumentIndex;
|
|
VARIANT vtIndexArray = { 0 };
|
|
VARIANT vtValue = { 0 };
|
|
SAFEARRAY* pGetValueArguments = NULL;
|
|
mscorlib::_Type* pPropertyInfoType = NULL;
|
|
mscorlib::_MethodInfo* pGetValueMethodInfo = NULL;
|
|
|
|
lNbArguments = pIndex != NULL ? 2 : 1;
|
|
|
|
if (!clr::GetType(pAppDomain, ASSEMBLY_NAME_SYSTEM_REFLECTION, L"System.Reflection.PropertyInfo", &pPropertyInfoType))
|
|
goto exit;
|
|
|
|
if (!clr::GetMethod(pPropertyInfoType, static_cast<mscorlib::BindingFlags>(BINDING_FLAGS_PUBLIC_INSTANCE), L"GetValue", lNbArguments, &pGetValueMethodInfo))
|
|
goto exit;
|
|
|
|
pGetValueArguments = SafeArrayCreateVector(VT_VARIANT, 0, lNbArguments);
|
|
|
|
lArgumentIndex = 0;
|
|
SafeArrayPutElement(pGetValueArguments, &lArgumentIndex, &vtObject);
|
|
|
|
if (pIndex != NULL)
|
|
{
|
|
vtIndexArray.vt = VT_ARRAY | VT_VARIANT;
|
|
vtIndexArray.parray = pIndex;
|
|
|
|
lArgumentIndex = 1;
|
|
SafeArrayPutElement(pGetValueArguments, &lArgumentIndex, &vtIndexArray);
|
|
}
|
|
|
|
if (!clr::InvokeMethod(pGetValueMethodInfo, vtPropertyInfo, pGetValueArguments, &vtValue))
|
|
goto exit;
|
|
|
|
memcpy_s(pvtValue, sizeof(*pvtValue), &vtValue, sizeof(vtValue));
|
|
bResult = TRUE;
|
|
|
|
exit:
|
|
if (pGetValueArguments) SafeArrayDestroy(pGetValueArguments);
|
|
|
|
if (pGetValueMethodInfo) pGetValueMethodInfo->Release();
|
|
if (pPropertyInfoType) pPropertyInfoType->Release();
|
|
|
|
return bResult;
|
|
}
|
|
|
|
BOOL dotnet::System_Reflection_PropertyInfo_GetValue(mscorlib::_AppDomain* pAppDomain, VARIANT vtPropertyInfo, VARIANT vtObject, VARIANT* pvtValue)
|
|
{
|
|
return dotnet::System_Reflection_PropertyInfo_GetValue(pAppDomain, vtPropertyInfo, vtObject, NULL, pvtValue);
|
|
}
|