Die Freude über HRESULT = 0×00000000 - CLRHosting Reloaded
Zunächst einmal muss ich etwas loswerden: COM-Objekte und ihre GUID/CLSID/IDDs sind BLÖD! Seid Stunden sitze ich an einem kleinen Problem, welches sich HRESULT REGDB_E_CLASSNOTREG bzw E_NOINTERFACE nennt. Laut Google müssen CLSID und IID identisch sein, aber hier…:
CLSID_CLRRuntimeHost = 90F1A06E-7712-4762-86B5-7A5EBA6BDB02
IID_CLRRuntimeHost = 90F1A06C-7712-4762-86B5-7A5EBA6BDB02
Suche und finde den Fehler. Jap, ein Zeichen unterschied der GUIDs und alles für den A…..
So, nach diesem kleinen Ausraster direkt zur Einleitung. Es geht um CLRHosting durch Managed FASM, wie bereits in einem Post vor ziemlich genau einem Jahr erklärt. Dabei ist es möglich von .NET ASM-Code in eine native Assembly zu injecten, welche wiederrum eine CLR-Runtime läd um dort .NET Assemblys zu laden und auszuführen. Wozu braucht man das? Zum Beispiel um auf native Bootstrap DLLs verzichten zu können oder böse Malware in nativen Programmen zu verstecken.
In dem erwähnten Post wurde die CLRRuntime 2.X über die Funktion CorBindToRuntimeEx geladen, dies ist allerdings nicht zu höheren Versionen des .NET Frameworks kompatibel. Nun wurde eine andere Lösung gesucht, da viele Libraries inzwischen auf .NET 4 portiert sind.
Die hier vorgestellte Methode ist etwas komplizierter, dafür funktioniert sie für .NET v4.0.30319 und ist abwärtskompatibel. Bei dem früheren CLRHosting reichte es, eine statische Funktion aufzurufen um ein Interface-Handle zu bekommen. Von diesem Interface-Handle reichte es, wiederum eine Funktion aufzurufen, um die CLRRuntime zu starten.
Nun laufen andere Schritte ab und wir haben es mit 3 Runtime-Interfaces zu tun: ICLRMetaHost, ICLRRuntimeInfo und ICLRRuntimeHost. Wir erstellen über die statische Funktion CLRCreateInstance ein MetaHost, von diesem rufen wir über “GetRuntime” und der Versionsnummer eine CLRRuntimeInfo ab, von dieser wir ein CLRRuntimeHost starten können. Dieser kann nun .NET DLLs laden und ausführen.
Ich würde selbst bei den ganzen Interfaces&Co nicht durchblicken, daher belasse ich es bei dieser “kurzen” Erklärung. Interessanter ist eh der, übrigens komplett selbst geschriebene, ASM Code, welchen ich in eine Klasse verpackt habe.
Die Begeisterung kann sich noch in Grenzen halten, aber spätestens wenn ich das nächste Projekt präsentationsfähig habe wird man sehen, wie mächtig CLRHosting ist!
namespace Injection_Helper.CLR { public static class CLRHosting { private static Guid CLSID_CLRMetaHost = new Guid("9280188D-0E8E-4867-B30C-7FA83884E8DE"); private static Guid IID_ICLRMetaHost = new Guid("D332DB9E-B9B3-4125-8207-A14884F53216"); private static Guid IID_ICLRRuntimeInfo = new Guid("BD39D1D2-BA2F-486A-89B0-B4B0CB466891"); private static Guid CLSID_CLRRuntimeHost = new Guid("90F1A06E-7712-4762-86B5-7A5EBA6BDB02"); private static Guid IID_CLRRuntimeHost = new Guid("90F1A06C-7712-4762-86B5-7A5EBA6BDB02"); public static System.Diagnostics.ProcessModule GetMsCoree { get { foreach (System.Diagnostics.ProcessModule pm in System.Diagnostics.Process.GetCurrentProcess().Modules) if (pm.ModuleName.ToLower() == "mscoree.dll") return pm; return null; } } public static void HostCLR_RunMethod(Int32 PID, String AssemblyPath, String TypeName, String MethodName, String Args, String Version = "v4.0.30319") { UIntPtr CLRCreateInstancePtr = GreyMagic.Native.Imports.GetProcAddress(GreyMagic.Native.Imports.GetModuleHandle("mscoree.dll"), "CLRCreateInstance"); if (CLRCreateInstancePtr == UIntPtr.Zero) { Console.WriteLine("Unable to found CLRCreateInstancePtr"); return; } GreyMagic.ExternalProcessReader Reader = new GreyMagic.ExternalProcessReader(System.Diagnostics.Process.GetProcessById(PID)); Reader.InjectDllCreateThread(GetMsCoree.FileName); IntPtr CLSID_CLRMetaHostPtr = Reader.AllocateMemory(CLSID_CLRMetaHost.ToByteArray().Length * 4); IntPtr IID_ICLRMetaHostPtr = Reader.AllocateMemory(IID_ICLRMetaHost.ToByteArray().Length); IntPtr IID_ICLRRuntimeInfoPtr = Reader.AllocateMemory(IID_ICLRRuntimeInfo.ToByteArray().Length); IntPtr CLSID_CLRRuntimeHostPtr = Reader.AllocateMemory(CLSID_CLRRuntimeHost.ToByteArray().Length * 4); IntPtr IID_CLRRuntimeHostPtr = Reader.AllocateMemory(IID_CLRRuntimeHost.ToByteArray().Length); IntPtr dwRetPtr = Reader.AllocateMemory(0x4); IntPtr codeCave_Code = Reader.AllocateMemory(0x512); IntPtr AssemblyPathPtr = Reader.AllocateMemory(AssemblyPath.Length + 1); IntPtr TypeNamePtr = Reader.AllocateMemory(TypeName.Length + 1); IntPtr MethodNamePtr = Reader.AllocateMemory(MethodName.Length + 1); IntPtr ArgsPtr = Reader.AllocateMemory(Args.Length + 1); IntPtr MetaHostPtr = Reader.AllocateMemory(0x04); IntPtr RuntimeInfoPtr = Reader.AllocateMemory(0x04); IntPtr RuntimeVersionPtr = Reader.AllocateMemory(Version.Length + 1); IntPtr RuntimeHostPtr = Reader.AllocateMemory(0x04); Reader.WriteString(AssemblyPathPtr, AssemblyPath, Encoding.Unicode); Reader.WriteString(TypeNamePtr, TypeName, Encoding.Unicode); Reader.WriteString(MethodNamePtr, MethodName, Encoding.Unicode); Reader.WriteString(ArgsPtr, Args, Encoding.Unicode); Reader.WriteString(RuntimeVersionPtr, Version, Encoding.Unicode); Reader.WriteBytes(CLSID_CLRMetaHostPtr, CLSID_CLRMetaHost.ToByteArray()); Reader.WriteBytes(IID_ICLRMetaHostPtr, IID_ICLRMetaHost.ToByteArray()); Reader.WriteBytes(IID_ICLRRuntimeInfoPtr, IID_ICLRRuntimeInfo.ToByteArray()); Reader.WriteBytes(CLSID_CLRRuntimeHostPtr, CLSID_CLRRuntimeHost.ToByteArray()); Reader.WriteBytes(IID_CLRRuntimeHostPtr, IID_CLRRuntimeHost.ToByteArray()); ManagedFasm fasm = Reader.Asm; fasm.AddLine("mov eax, " + MetaHostPtr); fasm.AddLine("push eax"); fasm.AddLine("push " + IID_ICLRMetaHostPtr); fasm.AddLine("push " + CLSID_CLRMetaHostPtr); fasm.AddLine("call " + CLRCreateInstancePtr); // Call CLRCreateInstance fasm.AddLine("mov eax, " + RuntimeInfoPtr); fasm.AddLine("push eax"); fasm.AddLine("push " + IID_ICLRRuntimeInfoPtr); fasm.AddLine("push " + RuntimeVersionPtr); fasm.AddLine("mov ecx, [{0}]", MetaHostPtr); fasm.AddLine("mov edx, [ecx]"); fasm.AddLine("mov eax, [{0}]", MetaHostPtr); fasm.AddLine("push eax"); fasm.AddLine("mov ecx, [edx+0Ch]"); fasm.AddLine("call ecx"); //Call pMetaHost->GetRuntime fasm.AddLine("mov eax, {0}", RuntimeHostPtr); fasm.AddLine("push eax"); fasm.AddLine("push " + IID_CLRRuntimeHostPtr); fasm.AddLine("push " + CLSID_CLRRuntimeHostPtr); fasm.AddLine("mov ecx, [{0}]", RuntimeInfoPtr); fasm.AddLine("mov edx, [ecx]"); fasm.AddLine("mov eax, [{0}]", RuntimeInfoPtr); fasm.AddLine("push eax"); fasm.AddLine("mov ecx, [edx+24h]"); fasm.AddLine("call ecx"); //Call pRuntimeInfo->GetInterface fasm.AddLine("mov eax, [{0}]", RuntimeHostPtr); fasm.AddLine("mov ecx, [eax]"); fasm.AddLine("mov edx, [{0}]", RuntimeHostPtr); fasm.AddLine("push edx"); fasm.AddLine("mov eax, [ecx+0Ch]"); fasm.AddLine("call eax"); // Call pRuntimeHost->Start fasm.AddLine("push " + dwRetPtr); fasm.AddLine("push " + ArgsPtr); fasm.AddLine("push " + MethodNamePtr); fasm.AddLine("push " + TypeNamePtr); fasm.AddLine("push " + AssemblyPathPtr); fasm.AddLine("mov eax, [" + RuntimeHostPtr + "]"); fasm.AddLine("mov ecx, [eax]"); fasm.AddLine("push eax"); fasm.AddLine("mov eax, [ecx+0x2C]"); fasm.AddLine("call eax"); fasm.AddLine("retn"); // Call pRuntimeHost->ExecuteInDefaultAppDomain fasm.InjectAndExecute((uint)codeCave_Code); } } |
Ich kann nirgends die von dir verwendete Version der GreyMagic.dll finden. Könntest du diese bitte verlinken?
Hier der offizielle Link: http://www.ownedcore.com/forums/world-of-warcraft/world-of-warcraft-bots-programs/wow-memory-editing/379821-greymagic-best-of-both-worlds-then-some.html . Der DL im Post 1 ist down, daher nutze den DL Link hier: http://www.mediafire.com/download/404zf9ejpc1zr2t/GreyMagic.7z