[C#] CLR hosting using C# and BlackMagic (ASM) menu

Shout-Out

User Tag List

Results 1 to 10 of 10
  1. #1
    JuJuBoSc's Avatar Banned for scamming CoreCoins Purchaser
    Reputation
    1019
    Join Date
    May 2007
    Posts
    922
    Thanks G/R
    1/3
    Trade Feedback
    1 (100%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    [C#] CLR hosting using C# and BlackMagic (ASM)

    Hello,

    Few days ago I saw a post talking about CLR hosting, and the idea of run directly asm code with CreateRemoteThread without doing it from C++ dll.

    I liked the idea and give it a try, here is a working, with no really error handling, I was lazy.

    Code:
            // From mscoree.h
            static byte[] CLSID_CLRRuntimeHost = new byte[] { 0x6E, 0xA0, 0xF1, 0x90, 0x12, 0x77, 0x62, 0x47, 0x86, 0xB5, 0x7A, 0x5E, 0xBA, 0x6B, 0xDB, 0x02 };
            static byte[] IID_ICLRRuntimeHost = new byte[] { 0x6C, 0xA0, 0xF1, 0x90, 0x12, 0x77, 0x62, 0x47, 0x86, 0xB5, 0x7A, 0x5E, 0xBA, 0x6B, 0xDB, 0x02 };
    
            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 ExecuteInDefaultAppDomain(Int32 PID, String AssemblyPath, String TypeName, String MethodName, String Args)
            {
    
                Magic.BlackMagic BM = new Magic.BlackMagic();
    
                if (!BM.OpenProcessAndThread(PID))
                {
                    Console.WriteLine("Unable to open PID {0} !", PID);
                    return;
                }
    
                if (GetMsCoree == null)
                {
                    Console.WriteLine("Unable to found mscoree.dll !");
                    return;
                }
    
                UIntPtr CorBindToRuntimeExPtr = Magic.Imports.GetProcAddress(Magic.Imports.GetModuleHandle("mscoree.dll"), "CorBindToRuntimeEx");
    
                if (CorBindToRuntimeExPtr == UIntPtr.Zero)
                {
                    Console.WriteLine("Unable to found CorBindToRuntimeExPtr");
                    return;
                }
    
                BM.InjectDllCreateThread(GetMsCoree.FileName);
    
                uint CLSID_CLRRuntimeHostPtr = BM.AllocateMemory(CLSID_CLRRuntimeHost.Length * 4);
                uint IID_ICLRRuntimeHostPtr = BM.AllocateMemory(IID_ICLRRuntimeHost.Length);
                uint ClrHostPtr = BM.AllocateMemory(0x4);
                uint dwRetPtr = BM.AllocateMemory(0x4);
                uint codeCave_Code = BM.AllocateMemory(0x256);
                uint AssemblyPathPtr = BM.AllocateMemory(AssemblyPath.Length + 1);
                uint TypeNamePtr = BM.AllocateMemory(TypeName.Length + 1);
                uint MethodNamePtr = BM.AllocateMemory(MethodName.Length + 1);
                uint ArgsPtr = BM.AllocateMemory(Args.Length + 1);
                uint BuildFlavorPtr = BM.AllocateMemory(0x10);
    
                BM.WriteUnicodeString(BuildFlavorPtr, "wks");
                BM.WriteUnicodeString(AssemblyPathPtr, AssemblyPath);
                BM.WriteUnicodeString(TypeNamePtr, TypeName);
                BM.WriteUnicodeString(MethodNamePtr, MethodName);
                BM.WriteUnicodeString(ArgsPtr, Args);
                BM.WriteBytes(CLSID_CLRRuntimeHostPtr, CLSID_CLRRuntimeHost);
                BM.WriteBytes(IID_ICLRRuntimeHostPtr, IID_ICLRRuntimeHost);
    
                Fasm.ManagedFasm fasm = new Fasm.ManagedFasm(BM.ProcessHandle);
    
                fasm.AddLine("push " + ClrHostPtr);
                fasm.AddLine("push " + IID_ICLRRuntimeHostPtr);
                fasm.AddLine("push " + CLSID_CLRRuntimeHostPtr);
                fasm.AddLine("push 0");
                fasm.AddLine("push " + BuildFlavorPtr);
                fasm.AddLine("push 0");
                fasm.AddLine("call " + CorBindToRuntimeExPtr);
                fasm.AddLine("mov eax, [" + ClrHostPtr + "]");
                fasm.AddLine("mov ecx, [eax]");
                fasm.AddLine("mov edx, [ecx+0xC]");
                fasm.AddLine("push eax");
                fasm.AddLine("call edx");
                fasm.AddLine("push " + dwRetPtr);
                fasm.AddLine("push " + ArgsPtr);
                fasm.AddLine("push " + MethodNamePtr);
                fasm.AddLine("push " + TypeNamePtr);
                fasm.AddLine("push " + AssemblyPathPtr);
                fasm.AddLine("mov eax, [" + ClrHostPtr + "]");
                fasm.AddLine("mov ecx, [eax]");
                fasm.AddLine("push eax");
                fasm.AddLine("mov eax, [ecx+0x2C]");
                fasm.AddLine("call eax");
                fasm.AddLine("retn");
    
                fasm.InjectAndExecute(codeCave_Code);
    
                BM.FreeMemory(CLSID_CLRRuntimeHostPtr);
                BM.FreeMemory(IID_ICLRRuntimeHostPtr);
                BM.FreeMemory(ClrHostPtr);
                BM.FreeMemory(dwRetPtr);
                BM.FreeMemory(codeCave_Code);
                BM.FreeMemory(AssemblyPathPtr);
                BM.FreeMemory(TypeNamePtr);
                BM.FreeMemory(MethodNamePtr);
                BM.FreeMemory(ArgsPtr);
                BM.FreeMemory(BuildFlavorPtr);
    
            }
    I'm sure this code can be improved, feel free to add your suggestions

    Credit to Shynd for BlackMagic and _Mike for the idea.

    [C#] CLR hosting using C# and BlackMagic (ASM)
  2. #2
    !@^^@!'s Avatar Active Member
    Reputation
    23
    Join Date
    Feb 2007
    Posts
    155
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Suggestion: Use reflection! Make ExecuteInDefaultAppDomain take a MethodInfo as parameter instead of AssemblyPath, TypeName and MethodName because you can get all 3 of them from MethodeInfo
    Or if you wanna go even more into the reflection you can specify an attribute and use it on a static method in a class and have ExecuteInDefaultAppDomain take a Type as the parameter and then search for which method that has the attribute implemented/marked like this:

    Code:
    public static uint Inject(int id, Type type, string args = "")
            {
                var pid = (uint) id;
                if (pid == 0)
                    throw new ArgumentNullException("id","ID can't be zero or below");
                if (type == null)
                    throw new ArgumentNullException("type");
    
                uint ret = 0;
    
    
                MethodInfo startMethod = type.GetMethods(BindingFlags.Static | BindingFlags.Public).First(
                    m => m.GetCustomAttributes(false).OfType<EntryPointAttribute>().Any());
    
                if (startMethod == null)
                {
                    throw new EntryPointException(
                        "Please make sure the [EntryPoint] attribute is set on a public static method in the class");
                }
    
                var path = (new Uri(type.Module.Assembly.CodeBase)).AbsolutePath;
                var methodName = startMethod.DeclaringType.FullName + "." + startMethod.Name;
    
                //inject here
               }
    “Programmers are in a race with the Universe to create bigger and better idiot-proof programs, while the Universe is trying to create bigger and better idiots. So far the Universe is winning.” - Rich Cook

  3. #3
    JuJuBoSc's Avatar Banned for scamming CoreCoins Purchaser
    Reputation
    1019
    Join Date
    May 2007
    Posts
    922
    Thanks G/R
    1/3
    Trade Feedback
    1 (100%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ha didn't know about all these information in MethodInfo, really good for the EntryPoint attribute, I will use it thanks

  4. #4
    !@^^@!'s Avatar Active Member
    Reputation
    23
    Join Date
    Feb 2007
    Posts
    155
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Yeah reflection is amazing Just remember to define the attribute like this and either in an external "Contracts" dll or in the "to be injected dll" so you avoid having to reference the main project in the injected dll:

    Code:
    [AttributeUsage(AttributeTargets.Method,AllowMultiple = false, Inherited = false)] //We don't want this to be used in more than one place
        public class EntryPointAttribute : Attribute
        {
            
        }
    And just to not have your type definition floating around in some random class i like to do this:

    Code:
    public static readonly Type Type = typeof (Injected.Startup.Main);
    “Programmers are in a race with the Universe to create bigger and better idiot-proof programs, while the Universe is trying to create bigger and better idiots. So far the Universe is winning.” - Rich Cook

  5. #5
    -Ryuk-'s Avatar Elite User CoreCoins Purchaser Authenticator enabled
    Reputation
    529
    Join Date
    Nov 2009
    Posts
    1,028
    Thanks G/R
    38/51
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Just out of interest, would this inject a .Net 4.0 dll? or just 3.5 and below?
    |Leacher:11/2009|Donor:02/2010|Established Member:09/2010|Contributor:09/2010|Elite:08/2013|

  6. #6
    JuJuBoSc's Avatar Banned for scamming CoreCoins Purchaser
    Reputation
    1019
    Join Date
    May 2007
    Posts
    922
    Thanks G/R
    1/3
    Trade Feedback
    1 (100%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Haven't worked with 4.0 but I'm sure it will don't work.

  7. #7
    Jens's Avatar Contributor
    Reputation
    179
    Join Date
    Sep 2006
    Posts
    251
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Great concept!
    But using FASM essentially just moves the need for a native library, you should in theory (read: i haven't tested it) be able to completely do away with it by writing the entire function to load the CLR into memory in bytes as well as the strings needed, and then creating a new thread to call the function, I'm going to have to test this!
    Last edited by Jens; 05-10-2011 at 05:49 AM.

  8. #8
    _Mike's Avatar Contributor
    Reputation
    310
    Join Date
    Apr 2008
    Posts
    531
    Thanks G/R
    0/2
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by Jens View Post
    ...by writing the entire function to load the CLR into memory in bytes as well as the strings needed, and then creating a new thread to call the function...
    Why would you want to mess with byte code directly? Your idea is exactly what a JIT assembler does, except in a much much more maintainable and reliable way.
    It certainly isn't impossible, but it is stupid though

  9. #9
    Jens's Avatar Contributor
    Reputation
    179
    Join Date
    Sep 2006
    Posts
    251
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by _Mike View Post
    Why would you want to mess with byte code directly? Your idea is exactly what a JIT assembler does, except in a much much more maintainable and reliable way.
    It certainly isn't impossible, but it is stupid though
    Yeah, but with that mentality i might as well stay with my current scheme of injecting a bootstrapper to load the CLR, that way i wont even have to bother with the ASM that FASM needs .

    It's more of a mental exercise really!

  10. #10
    _Mike's Avatar Contributor
    Reputation
    310
    Join Date
    Apr 2008
    Posts
    531
    Thanks G/R
    0/2
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by Jens View Post
    Yeah, but with that mentality i might as well stay with my current scheme of injecting a bootstrapper to load the CLR, that way i wont even have to bother with the ASM that FASM needs .

    It's more of a mental exercise really!
    Yeah if it's just for testing then I'm all for it I'm just trying to say that it's not something that I would use or recommend for public releases or something I plan on maintaining for a long time. Rewriting assembler code is a lot less painful than raw byte arrays

Similar Threads

  1. [Sample Code] EndScene Hook with ASM and blackmagic
    By RivaLfr in forum WoW Memory Editing
    Replies: 90
    Last Post: 4 Weeks Ago, 04:06 PM
  2. Hosting a Website and using FTP!!!
    By Iceknight001 in forum WoW EMU Guides & Tutorials
    Replies: 6
    Last Post: 03-31-2008, 05:29 AM
  3. A question for those using Ascent and Chrispee packs.
    By Cross_1985 in forum World of Warcraft Emulator Servers
    Replies: 0
    Last Post: 10-03-2007, 02:08 PM
  4. Replies: 3
    Last Post: 03-24-2007, 05:04 AM
  5. Suspended using FishBot...and how I recovered
    By sol82 in forum World of Warcraft Bots and Programs
    Replies: 15
    Last Post: 03-08-2007, 08:40 PM
All times are GMT -5. The time now is 10:10 PM. Powered by vBulletin® Version 4.2.3
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved. User Alert System provided by Advanced User Tagging (Pro) - vBulletin Mods & Addons Copyright © 2025 DragonByte Technologies Ltd.
Google Authenticator verification provided by Two-Factor Authentication (Free) - vBulletin Mods & Addons Copyright © 2025 DragonByte Technologies Ltd.
Digital Point modules: Sphinx-based search