OutdatedSharpMonoInjector - a Mono/Unity injector written in C#

Posts 1–8 of 8 · Page 1 of 1
SharpMonoInjector - a Mono/Unity injector written in C#
Hello.
After some trial and error, I figured out how to inject assemblies into Mono embedded processes and I'm going to share the method here.

I am using the Process.NET library written by lolp1 to invoke functions in the target process, and Fasm.NET written by ZenLulz as the assembler that Process.NET requires.

The target process does not have to be restarted in order to inject an updated version of the assembly. Instead, you need to properly eject the assembly which this tool simplifies, and then inject again.

Compiled binaries + source code is included in the attached archive.

Below is a much simplified version of the source code for those that want a quick look.

Code:
using System;
using System****;
using Process.NET;
using Process.NE*****mory;
using Process.NET.Assembly;
using Process.NET.Native.Types;
using Binarysharp.Assemblers.Fasm;
using Process.NET.Assembly.Assemblers;

namespace Injector
{
    class Assembler : IAssembler
    {
        public static bool Attach = false;
        public static IntPtr MonoThreadAttach;
        public static IntPtr MonoRootDomain;

        public byte[] Assemble(string asm)
        {
            return Assemble(asm, IntPtr.Zero);
        }

        public byte[] Assemble(string asm, IntPtr baseAddress)
        {
            if (!Attach)
                asm = $"use32\norg {baseAddress}\n" + asm;
            else
                // Ensure mono_thread_attach is called first
                asm = $"use32\norg {baseAddress}\npush {MonoRootDomain}\ncall {MonoThreadAttach}\nadd esp, 4\n" + asm;
            return FasmNet.Assemble(asm);
        }
    }

    class Program
    {
        static ProcessSharp target;
        static AssemblyFactory factory;

        static void Main(string[] args)
        {
            System.Diagnostics.Process p =
                System.Diagnostics.Process.GetProcessesByName("target")[0];

            target = new ProcessSharp(p, MemoryType.Remote);
            factory = new AssemblyFactory(target, new Assembler());

            byte[] data = File.ReadAllBytes("ExampleAssembly.dll");

            string nameSpace = "ExampleAssembly",
                   klass = "Loader",
                   method = "Load";

            IntPtr rawImage = OpenImageFromData(data);

            /* From this point on, the threads created by AssemblyFactory.Execute
               will have to be registered with the Mono runtime since we
               are accessing Mono objects. Otherwise the target process crashes. */

            Assembler.MonoThreadAttach = target.ModuleFactory["mono.dll"]["mono_thread_attach"].BaseAddress;
            Assembler.MonoRootDomain = GetRootDomain();

            Assembler.Attach = true;

            RuntimeInvoke(
                GetMethodFromName(
                    GetClassFromName(
                        GetImageFromAssembly(
                            OpenAssemblyFromImage(
                                rawImage)), 
                        nameSpace, klass), 
                    method));

            factory.Dispose();
            target.Dispose();
        }

        static IntPtr GetRootDomain()
        {
            IntPtr addr = target.ModuleFactory["mono.dll"]["mono_get_root_domain"].BaseAddress;
            return factory.Execute<IntPtr>(addr, CallingConventions.Cdecl);
        }

        static IntPtr OpenImageFromData(byte[] assembly)
        {
            IntPtr addr = target.ModuleFactory["mono.dll"]["mono_image_open_from_data"].BaseAddress;
            IAllocatedMemory alloc = targe*****moryFactory.Allocate("assembly", assembly.Length);
            alloc.Write(0, assembly);
            IntPtr image = factory.Execute<IntPtr>(addr, CallingConventions.Cdecl, alloc.BaseAddress, assembly.Length, 1, IntPtr.Zero);
            targe*****moryFactory.Deallocate(alloc);
            return image;
        }

        static IntPtr OpenAssemblyFromImage(IntPtr image)
        {
            IntPtr addr = target.ModuleFactory["mono.dll"]["mono_assembly_load_from_full"].BaseAddress;
            return factory.Execute<IntPtr>(addr, CallingConventions.Cdecl, image, "UNUSED", IntPtr.Zero, 0);
        }

        static IntPtr GetImageFromAssembly(IntPtr assembly)
        {
            IntPtr addr = target.ModuleFactory["mono.dll"]["mono_assembly_get_image"].BaseAddress;
            return factory.Execute<IntPtr>(addr, CallingConventions.Cdecl, assembly);
        }

        static IntPtr GetClassFromName(IntPtr image, string name_space, string klass)
        {
            IntPtr addr = target.ModuleFactory["mono.dll"]["mono_class_from_name"].BaseAddress;
            return factory.Execute<IntPtr>(addr, CallingConventions.Cdecl, image, name_space, klass);
        }

        static IntPtr GetMethodFromName(IntPtr klass, string method)
        {
            IntPtr addr = target.ModuleFactory["mono.dll"]["mono_class_get_method_from_name"].BaseAddress;
            return factory.Execute<IntPtr>(addr, CallingConventions.Cdecl, klass, method, 0);
        }

        static int RuntimeInvoke(IntPtr method)
        {
            IntPtr addr = target.ModuleFactory["mono.dll"]["mono_runtime_invoke"].BaseAddress;
            return factory.Execute<int>(addr, CallingConventions.Cdecl, method, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
        }
    }
}
https://virusscan.jotti.org/en-US/fi...job/lqr49ac4aa
https://www.virustotal.com/#/file/0b...3c06/detection

SharpMonoInjector_mpgh.net.zip529 KB · 659 downloads Clean
Approved .
I can't see porcess in "Target process", Refresh button doesn't change anything
Quote Originally Posted by axeldu95 View Post
I can't see porcess in "Target process", Refresh button doesn't change anything
That's either because the process is not a mono embedded process or it is an x64 process which is currently not supported.
I came to read this as I was writing an update for an anti-cheat for a few games. I shouldn't tell the public this but the way this injector hides the data in an image and using mono any heuristic memory scaning method around currently can not detect this. Very nice peice of code, Ill have to read it a few more time before I can think up a soultion to detect injection. Pretty stumped currently.
Posts 1–8 of 8 · Page 1 of 1

Post a Reply

Similar Threads

Talk with us