Inject .net application into native Process menu

User Tag List

Page 2 of 3 FirstFirst 123 LastLast
Results 16 to 30 of 35
  1. #16
    MaiN's Avatar Elite User
    Reputation
    335
    Join Date
    Sep 2006
    Posts
    1,047
    Thanks G/R
    0/10
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Is there any reason not to use C++/CLI? The CLR will automatically be loaded for you if you just inject a C++/CLI DLL in.

    Here is sample code:
    Code:
    #include <Windows.h>
    
    
    using namespace System;
    using namespace System::Diagnostics;
    using namespace System::IO;
    using namespace System::Reflection;
    using namespace System::Text;
    using namespace System::Threading;
    using namespace System::Threading::Tasks;
    
    
    namespace Yayyyy
    {
        public ref class AssemblyLoader : MarshalByRefObject
        {
        public:
            static void RunIndefinitely()
            {
                RunOnce();
    
    
                while (true)
                {
                    bool inForeground = IntPtr(GetForegroundWindow()) == Process::GetCurrentProcess()->MainWindowHandle;
                    if (inForeground && GetAsyncKeyState(VK_F11) != 0)
                    {
                        RunOnce();
                    }
    
    
                    Thread::Sleep(50);
                }
            }
    
    
        private:
            static void RunOnce()
            {
                AppDomain^ domain = AppDomain::CreateDomain("Yayyyy");
                try
                {
                    String^ asmLoc = Assembly::GetExecutingAssembly()->Location;
                    String^ typeFullName = AssemblyLoader::typeid->FullName;
                    AssemblyLoader^ instance = static_cast<AssemblyLoader^>(domain->CreateInstanceFromAndUnwrap(asmLoc, typeFullName));
                    String^ error = instance->LoadAndRunInCurrentDomain();
                    if (error != nullptr)
                        System::Windows::Forms::MessageBox::Show(error, "Error");
                }
                finally
                {
                    AppDomain::Unload(domain);
                }
            }
    
    
            String^ LoadAndRunInCurrentDomain()
            {
                String^ path = Path::Combine(Path::GetDirectoryName(Assembly::GetExecutingAssembly()->Location), "Yayyyy.dll");
                Assembly^ assembly = Assembly::LoadFrom(path);
                MethodInfo^ mi = assembly->GetType("Yayyyy.Program")->GetMethod("Main");
                try
                {
                    mi->Invoke(nullptr, gcnew array<Object^>(0));
                    return nullptr;
                }
                catch (Exception^ ex)
                {
                    return ex->ToString();
                }
            }
        };
    }
    
    
    __declspec(dllexport) int __stdcall Initialize(void* param)
    {
        Task::Run(gcnew Action(Yayyyy::AssemblyLoader::RunIndefinitely));
        return 0;
    }
    
    
    __declspec(dllexport) void __stdcall Shutdown()
    {
        MessageBoxW(nullptr, L"Shutdown!", L"Hello", MB_OK);
    }
    Add this as a C++/CLI project, add a C# project and fix up LoadAndRunInCurrentDomain. Inject and call the Initialize export. Press F11 after recompiling to reload it -- no need to reinject.
    Last edited by MaiN; 08-01-2017 at 05:55 PM.
    [16:15:41] Cypher: caus the CPU is a dick
    [16:16:07] kynox: CPU is mad
    [16:16:15] Cypher: CPU is all like
    [16:16:16] Cypher: whatever, i do what i want

    Inject .net application into native Process
  2. Thanks tutrakan (1 members gave Thanks to MaiN for this useful post)
  3. #17
    tutrakan's Avatar Contributor
    Reputation
    134
    Join Date
    Feb 2013
    Posts
    175
    Thanks G/R
    124/52
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Finally!

    Thank you sir! You returned my hope in the human kind.

  4. #18
    lolp1's Avatar Site Donator CoreCoins Purchaser
    Reputation
    190
    Join Date
    Feb 2013
    Posts
    210
    Thanks G/R
    43/77
    Trade Feedback
    3 (100%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by MaiN View Post
    Is there any reason not to use C++/CLI? The CLR will automatically be loaded for you if you just inject a C++/CLI DLL in.

    Here is sample code:
    Code:
    #include <Windows.h>
    
    
    using namespace System;
    using namespace System::Diagnostics;
    using namespace System::IO;
    using namespace System::Reflection;
    using namespace System::Text;
    using namespace System::Threading;
    using namespace System::Threading::Tasks;
    
    
    namespace Yayyyy
    {
        public ref class AssemblyLoader : MarshalByRefObject
        {
        public:
            static void RunIndefinitely()
            {
                RunOnce();
    
    
                while (true)
                {
                    bool inForeground = IntPtr(GetForegroundWindow()) == Process::GetCurrentProcess()->MainWindowHandle;
                    if (inForeground && GetAsyncKeyState(VK_F11) != 0)
                    {
                        RunOnce();
                    }
    
    
                    Thread::Sleep(50);
                }
            }
    
    
        private:
            static void RunOnce()
            {
                AppDomain^ domain = AppDomain::CreateDomain("Yayyyy");
                try
                {
                    String^ asmLoc = Assembly::GetExecutingAssembly()->Location;
                    String^ typeFullName = AssemblyLoader::typeid->FullName;
                    AssemblyLoader^ instance = static_cast<AssemblyLoader^>(domain->CreateInstanceFromAndUnwrap(asmLoc, typeFullName));
                    String^ error = instance->LoadAndRunInCurrentDomain();
                    if (error != nullptr)
                        System::Windows::Forms::MessageBox::Show(error, "Error");
                }
                finally
                {
                    AppDomain::Unload(domain);
                }
            }
    
    
            String^ LoadAndRunInCurrentDomain()
            {
                String^ path = Path::Combine(Path::GetDirectoryName(Assembly::GetExecutingAssembly()->Location), "Yayyyy.dll");
                Assembly^ assembly = Assembly::LoadFrom(path);
                MethodInfo^ mi = assembly->GetType("Yayyyy.Program")->GetMethod("Main");
                try
                {
                    mi->Invoke(nullptr, gcnew array<Object^>(0));
                    return nullptr;
                }
                catch (Exception^ ex)
                {
                    return ex->ToString();
                }
            }
        };
    }
    
    
    __declspec(dllexport) int __stdcall Initialize(void* param)
    {
        Task::Run(gcnew Action(Yayyyy::AssemblyLoader::RunIndefinitely));
        return 0;
    }
    
    
    __declspec(dllexport) void __stdcall Shutdown()
    {
        MessageBoxW(nullptr, L"Shutdown!", L"Hello", MB_OK);
    }
    Add this as a C++/CLI project, add a C# project and fix up LoadAndRunInCurrentDomain. Inject and call the Initialize export. Press F11 after recompiling to reload it -- no need to reinject.
    The same thing works just using DllExport nuget and leaves behind no extra files and you can inject your C# dll directly.. just export the Init method. The CLR will get loaded automatically.

  5. #19
    MaiN's Avatar Elite User
    Reputation
    335
    Join Date
    Sep 2006
    Posts
    1,047
    Thanks G/R
    0/10
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by lolp1 View Post
    The same thing works just using DllExport nuget and leaves behind no extra files and you can inject your C# dll directly.. just export the Init method. The CLR will get loaded automatically.
    Cool, I have never used that one. Does it allow you to recompile and reload the assembly immediately?
    [16:15:41] Cypher: caus the CPU is a dick
    [16:16:07] kynox: CPU is mad
    [16:16:15] Cypher: CPU is all like
    [16:16:16] Cypher: whatever, i do what i want

  6. #20
    lolp1's Avatar Site Donator CoreCoins Purchaser
    Reputation
    190
    Join Date
    Feb 2013
    Posts
    210
    Thanks G/R
    43/77
    Trade Feedback
    3 (100%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by MaiN View Post
    Cool, I have never used that one. Does it allow you to recompile and reload the assembly immediately?
    Yeah. You can either directly unload in your app domain inside your app, or in the case of using a proxy dll like yours the same idea. Ignore the ugly code, it works though.

    Code:
    using System;
    using System.Diagnostics;
    using System.IO;
    using System.Linq;
    using System.Reflection;
    using System.Runtime.InteropServices;
    using System.Security.Policy;
    using System.Threading;
    using System.Windows.Forms;
    
        public interface IAssemblyLoader
        {
            void LoadAndRun(string file, string args);
        }
    
        public class Startup
        {
    
    
            /// <summary>
            ///     The hotkey that can be pressed to re-inject your assembly
            /// </summary>
            private const Keys ReloadHotKey = Keys.F11;
    
            [DllImport("User32.dll")]
            private static extern short GetAsyncKeyState(int vKey);
    
            [STAThread]
            public static int EntryPoint(string filePath, string args = "")
            {
                var firstLoaded = false;
    
                while (true)
                    //Keep the domain alive to enable reloading, this will hang while the choosen assembly is running
                {
                    if (!firstLoaded)
                    {
                        firstLoaded = true;
                        new SharpDomain(filePath, args);
                    }
    
                    if ((GetAsyncKeyState((int) ReloadHotKey) & 1) == 1)
                        // ReSharper disable once ObjectCreationAsStatement
                        new SharpDomain(filePath, args);
    
                    Thread.Sleep(10);
                }
                // ReSharper disable once HeuristicUnreachableCode
    #pragma warning disable 162
                return 0;
    #pragma warning restore 162
            }
    
            public static class DomainManager
            {
                public static AppDomain CurrentDomain { get; set; }
                public static WSharpAssemblyLoader CurrentAssemblyLoader { get; set; }
            }
    
            public class WSharpAssemblyLoader : MarshalByRefObject, IAssemblyLoader
            {
                public WSharpAssemblyLoader() => AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
    
                public void LoadAndRun(string file, string args)
                {
                    var asm = Assembly.Load(file);
    
                    var staMethods =
                        asm
                            .GetTypes()
                            .SelectMany(type => type.GetMethods())
                            .First(methodInfo =>
                            {
                                var invariant = methodInfo.Name.ToLowerInvariant();
    
                                return invariant.Contains("dllmain")
                                       || invariant == "dllmain";
                            });
    
                    if (staMethods == null)
                    {
                        throw new ArgumentNullException(nameof(staMethods));
                    }
    
                    staMethods.Invoke(null, null);
                }
    
                private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
                {
                    if (args.Name == Assembly.GetExecutingAssembly().FullName)
                    {
                        return Assembly.GetExecutingAssembly();
                    }
    
                    var appDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
                    var shortAsmName = Path.GetFileName(args.Name);
                    Trace.Assert(appDir != null, "appDir != null");
                    Trace.Assert(shortAsmName != null, "shortAsmName != null");
    
                    var fileName = Path.Combine(appDir, shortAsmName);
    
                    if (File.Exists(fileName))
                    {
                        return Assembly.LoadFrom(fileName);
                    }
    
                    return Assembly.GetExecutingAssembly().FullName == args.Name ? Assembly.GetExecutingAssembly() : null;
                }
            }
    
            /// <summary>
            ///     The actual domain object we'll be using to load and run the Dysis binaries.
            /// </summary>
    
            public class SharpDomain
            {
    
                private static readonly Random Random = new Random();
    
                private static string RandomString(int length)
                {
                    const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
                    return new string(Enumerable.Repeat(chars, length)
                        .Select(s => s[Random.Next(s.Length)]).ToArray());
                }
    
                public SharpDomain(string assemblyName, string args)
                {
                    try
                    {
                        var appBase = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
                        var ads = new AppDomainSetup {ApplicationBase = appBase, PrivateBinPath = appBase};
    
                        DomainManager.CurrentDomain = AppDomain.CreateDomain(
                            "SharpDomain_Internal_" + RandomString(20),
                            AppDomain.CurrentDomain.Evidence, ads);
    
                        AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
    
                        DomainManager.CurrentAssemblyLoader =
                            (WSharpAssemblyLoader)
                            DomainManager.CurrentDomain.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName,
                                typeof(WSharpAssemblyLoader).FullName);
    
    	                if (appBase != null)
    	                {
    		                var fileToLoadAndRun = Path.Combine(appBase,
    			                assemblyName);
    		                DomainManager.CurrentAssemblyLoader.LoadAndRun(fileToLoadAndRun, args);
    	                }
                    }
    
                    catch (Exception ex)
                    {
    	                var exception = ex as ReflectionTypeLoadException;
    	                if (exception != null)
                        {
                            var typeLoadException = exception;
                            var loaderExceptions = typeLoadException.LoaderExceptions;
                        }
    
                        SharpLoader.ShowError(ex);
                        // MessageBox.Show(e.ToString());
                    }
                    finally
                    {
                        DomainManager.CurrentAssemblyLoader = null;
                        AppDomain.Unload(DomainManager.CurrentDomain);
                    }
                }
    
                private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
                {
                    try
                    {
                        if (args.Name == Assembly.GetExecutingAssembly().FullName)
                        {
                            return Assembly.GetExecutingAssembly();
                        }
    
                        var assembly = Assembly.Load(args.Name);
                        if (assembly != null)
                        {
                            return assembly;
                        }
                    }
                    catch
                    {
                        // ignore load error
                    }
    
                    // *** NOTE: this doesn't account for special search paths
                    var parts = args.Name.Split(',');
    
                    var file =
                        Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\" + parts[0].Trim() + ".dll";
    
                    return Assembly.LoadFrom(file);
                }
            }
        }
    and the exports something like
    Code:
        public static class SharpLoader {
            /// <summary>
            ///     The arguements for the hosted application
            /// </summary>
            internal static string ApplicationArguments = string.Empty;
    
            /// <summary>
            ///     The application to be hosted name.
            /// </summary>
            internal static string ApplicationToHostName = string.Empty;
    
            /// <summary>
            ///     The application path to be hosted. Must contain the ending '\' slash.
            /// </summary>
            [MarshalAs(UnmanagedType.LPWStr)]
            internal static string ApplicationToHostDirectory = string.Empty;
    
            /// <summary>
            ///     Hosts the given domain.
            /// </summary>
            [DllExport]
            [STAThread]
            public static void HostDomain() {
                if (string.IsNullOrEmpty(ApplicationToHostName) || string.IsNullOrEmpty(ApplicationToHostDirectory)) {
                    var registryKey = Registry.CurrentUser.CreateSubKey("SOFTWARE\\NetProducts\\StylesoftNet");
                    ApplicationToHostDirectory = registryKey?.GetValue("StylesoftDirectory") + @"";
                    ApplicationToHostName = "StylesoftNet.dll";
                    //  throw new InvalidDataException("You must set LoadDomainHostSettings before calling HostDomain()");
                    //  return;
                }
    
                try {
                    if (ApplicationToHostName.EndsWith("exe", StringComparison.Ordinal) || ApplicationToHostName.EndsWith("dll", StringComparison.Ordinal)) {
                        Startup.EntryPoint(Path.Combine(ApplicationToHostDirectory, ApplicationToHostName),
                            ApplicationArguments);
                    }
                    else
                        MessageBox.Show(@"Invalid file type, SharpDomain can only load exe/dll files");
                }
                catch (Exception e) {
                    MessageBox.Show(e.ToString());
                }
            }
    
            /// <summary>
            ///     Loads the domain host settings. Call this with the desired params before calling <see cref="HostDomain()" />.
            /// </summary>
            /// <param name="loadDirectory">The directory the domain is contained in,</param>
            /// <param name="applicationName">Name of the application.</param>
            /// <param name="applicationArguments"></param>
            [DllExport("LoadDomainHostSettings", CallingConvention.Cdecl)]
            public static void LoadDomainHostSettings(string loadDirectory, string applicationName,
                string applicationArguments) {
                ApplicationToHostDirectory = loadDirectory;
                ApplicationToHostName = applicationName;
                ApplicationArguments = applicationArguments;
            }
    
            internal static void ShowError(Exception ex) => MessageBox.Show(ex.ToString(), @"Version Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

  7. #21
    tutrakan's Avatar Contributor
    Reputation
    134
    Join Date
    Feb 2013
    Posts
    175
    Thanks G/R
    124/52
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    "I would recommend you do this the documented way instead of relying on a undocumented hack from an author who doesn't provide support..."
    Source: C# "Unmanaged Exports" - Stack Overflow
    Last edited by tutrakan; 08-01-2017 at 06:54 PM.

  8. #22
    MaiN's Avatar Elite User
    Reputation
    335
    Join Date
    Sep 2006
    Posts
    1,047
    Thanks G/R
    0/10
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by lolp1 View Post
    Yeah. You can either directly unload in your app domain inside your app, or in the case of using a proxy dll like yours the same idea. Ignore the ugly code, it works though.
    ]
    I don't think you can unload the main app domain. So you need the additional DLL in either case (during development). So in that case I would still prefer the C++/CLI solution without a custom build process.

    However, for releases the solution with DllExport definitely looks cleaner.
    [16:15:41] Cypher: caus the CPU is a dick
    [16:16:07] kynox: CPU is mad
    [16:16:15] Cypher: CPU is all like
    [16:16:16] Cypher: whatever, i do what i want

  9. #23
    lolp1's Avatar Site Donator CoreCoins Purchaser
    Reputation
    190
    Join Date
    Feb 2013
    Posts
    210
    Thanks G/R
    43/77
    Trade Feedback
    3 (100%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by MaiN View Post
    I don't think you can unload the main app domain. So you need the additional DLL in either case (during development). So in that case I would still prefer the C++/CLI solution without a custom build process.

    However, for releases the solution with DllExport definitely looks cleaner.
    You can. Credits to the code below to Jadd, you can directly end your dll threads and just re-inject with no issues.

    Code:
        public static class Program {
            private static AppDomain _domain;
    
            [DllExport("Initialize", CallingConvention.StdCall)]
            public static void Export_Initialize() {
                Initialize();
            }
    
            [DllExport("Shutdown", CallingConvention.StdCall)]
            public static void Export_Shutdown() {
                Shutdown();
            }
    
            public static void Initialize() {
                if (_domain != null) {
                    Shutdown();
                }
    
                var currentAssembly = Assembly.GetExecutingAssembly();
                var currentPath = Path.GetDirectoryName(currentAssembly.Location);
    
                _domain = AppDomain.CreateDomain("Gather.NET.Internal", null, currentPath, null, true);
                _domain.DoCallBack(InternalInitialize);
            }
    
            public static void Shutdown() {
                if (_domain == null) {
                    return;
                }
    
                _domain.DoCallBack(InternalShutdown);
                AppDomain.Unload(_domain);
    
                _domain = null;
            }
    
            private static void InternalInitialize() {
    
                AppDomain.CurrentDomain.FirstChanceException += (sender, e) => HandleException("First-chance", e.Exception);
    
                AppDomain.CurrentDomain.UnhandledException +=
                    (sender, e) => HandleException("Unhandled", e.ExceptionObject as Exception);
    
                var process = System.Diagnostics.Process.GetProcessesByName("Wow-64").FirstOrDefault();
                if (process == null) {
                    MessageBox.Show("No process found..");
                    return;
                }
    
                Window.Initialize(process.MainWindowHandle);
                Window.Dispatcher.Invoke(Engine.Initialize);
    
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new MainForm());
            }
    
            private static void InternalShutdown() {
                Window.Detach();
            }
    
            #region Exception handlers
    #if DEBUG
            private static void HandleException(string exceptionType, Exception exception)
            {
                //
            }
    #else
            private static void HandleException(string exceptionType, Exception exception) {
                ...
            }
    #endif
            #endregion

  10. #24
    MaiN's Avatar Elite User
    Reputation
    335
    Join Date
    Sep 2006
    Posts
    1,047
    Thanks G/R
    0/10
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by lolp1 View Post
    You can. Credits to the code below to Jadd, you can directly end your dll threads and just re-inject with no issues.

    Code:
        public static class Program {
            private static AppDomain _domain;
    
            [DllExport("Initialize", CallingConvention.StdCall)]
            public static void Export_Initialize() {
                Initialize();
            }
    
            [DllExport("Shutdown", CallingConvention.StdCall)]
            public static void Export_Shutdown() {
                Shutdown();
            }
    
            public static void Initialize() {
                if (_domain != null) {
                    Shutdown();
                }
    
                var currentAssembly = Assembly.GetExecutingAssembly();
                var currentPath = Path.GetDirectoryName(currentAssembly.Location);
    
                _domain = AppDomain.CreateDomain("Gather.NET.Internal", null, currentPath, null, true);
                _domain.DoCallBack(InternalInitialize);
            }
    
            public static void Shutdown() {
                if (_domain == null) {
                    return;
                }
    
                _domain.DoCallBack(InternalShutdown);
                AppDomain.Unload(_domain);
    
                _domain = null;
            }
    
            private static void InternalInitialize() {
    
                AppDomain.CurrentDomain.FirstChanceException += (sender, e) => HandleException("First-chance", e.Exception);
    
                AppDomain.CurrentDomain.UnhandledException +=
                    (sender, e) => HandleException("Unhandled", e.ExceptionObject as Exception);
    
                var process = System.Diagnostics.Process.GetProcessesByName("Wow-64").FirstOrDefault();
                if (process == null) {
                    MessageBox.Show("No process found..");
                    return;
                }
    
                Window.Initialize(process.MainWindowHandle);
                Window.Dispatcher.Invoke(Engine.Initialize);
    
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new MainForm());
            }
    
            private static void InternalShutdown() {
                Window.Detach();
            }
    
            #region Exception handlers
    #if DEBUG
            private static void HandleException(string exceptionType, Exception exception)
            {
                //
            }
    #else
            private static void HandleException(string exceptionType, Exception exception) {
                ...
            }
    #endif
            #endregion
    You cannot recompile, even if you let the threads end. The assembly will still stay loaded and in use even if no threads are running in its code.
    I am also unable to unload the main app domain in any application, including in my injected code.

    The code you have sent just creates a different app domain and that is the one it unloads -- the assembly will stay in use in the original app domain.
    [16:15:41] Cypher: caus the CPU is a dick
    [16:16:07] kynox: CPU is mad
    [16:16:15] Cypher: CPU is all like
    [16:16:16] Cypher: whatever, i do what i want

  11. #25
    lolp1's Avatar Site Donator CoreCoins Purchaser
    Reputation
    190
    Join Date
    Feb 2013
    Posts
    210
    Thanks G/R
    43/77
    Trade Feedback
    3 (100%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by MaiN View Post
    You cannot recompile, even if you let the threads end. The assembly will still stay loaded and in use even if no threads are running in its code.
    I am also unable to unload the main app domain in any application, including in my injected code.

    The code you have sent just creates a different app domain and that is the one it unloads -- the assembly will stay in use in the original app domain.
    I am able to inject my DLL using this and recompile just fine after closing and re-inject. Maybe it has something to do with the shadow load of assemblies?

  12. #26
    MaiN's Avatar Elite User
    Reputation
    335
    Join Date
    Sep 2006
    Posts
    1,047
    Thanks G/R
    0/10
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by lolp1 View Post
    I am able to inject my DLL using this and recompile just fine after closing and re-inject. Maybe it has something to do with the shadow load of assemblies?
    Maybe, but that just sets up the new app domain. Are you sure you are making any changes so it actually needs to emit a new dll? Are you doing anything to eject?
    [16:15:41] Cypher: caus the CPU is a dick
    [16:16:07] kynox: CPU is mad
    [16:16:15] Cypher: CPU is all like
    [16:16:16] Cypher: whatever, i do what i want

  13. #27
    Jadd's Avatar 🐸 Premium Seller
    Reputation
    1511
    Join Date
    May 2008
    Posts
    2,432
    Thanks G/R
    81/333
    Trade Feedback
    1 (100%)
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by lolp1 View Post
    Yeah. You can either directly unload in your app domain inside your app, or in the case of using a proxy dll like yours the same idea. Ignore the ugly code, it works though.
    Unloading the app domain is not the same as unloading an assembly. You can't do that without a LOT of additional effort and understanding of how 'fusion' works in the CLR. Certainly more than I know, and I've given it a fair bit of research in the past.

    The reason that you are able to modify (ie. recompile) your assemblies is because Assembly.Load actually shadow-copies your assemblies to a temporary directory and loads them from there,
    meaning the original files are never loaded or locked by the process they are loaded into. You can disable this when setting up your AppDomain, you will see that the files are then locked.

    The only advantage of using a C++ CLR host is that you can eject it, but it's kind of pointless since your other assemblies cannot be.

  14. #28
    MaiN's Avatar Elite User
    Reputation
    335
    Join Date
    Sep 2006
    Posts
    1,047
    Thanks G/R
    0/10
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by Jadd View Post
    Unloading the app domain is not the same as unloading an assembly. You can't do that without a LOT of additional effort and understanding of how 'fusion' works in the CLR. Certainly more than I know, and I've given it a fair bit of research in the past.

    The reason that you are able to modify (ie. recompile) your assemblies is because Assembly.Load actually shadow-copies your assemblies to a temporary directory and loads them from there,
    meaning the original files are never loaded or locked by the process they are loaded into. You can disable this when setting up your AppDomain, you will see that the files are then locked.

    The only advantage of using a C++ CLR host is that you can eject it, but it's kind of pointless since your other assemblies cannot be.
    How are you shadow loading them in the main app domain? I searched and it looks like you cannot set up the main app domain to shadow load assemblies.
    [16:15:41] Cypher: caus the CPU is a dick
    [16:16:07] kynox: CPU is mad
    [16:16:15] Cypher: CPU is all like
    [16:16:16] Cypher: whatever, i do what i want

  15. #29
    lolp1's Avatar Site Donator CoreCoins Purchaser
    Reputation
    190
    Join Date
    Feb 2013
    Posts
    210
    Thanks G/R
    43/77
    Trade Feedback
    3 (100%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by MaiN View Post
    How are you shadow loading them in the main app domain? I searched and it looks like you cannot set up the main app domain to shadow load assemblies.
    The code above I posted is working as-is for me assuming you have a way to inject the dll and call the init export function, and you are building a .dll (e.g class library) with no default entry point.

  16. #30
    MaiN's Avatar Elite User
    Reputation
    335
    Join Date
    Sep 2006
    Posts
    1,047
    Thanks G/R
    0/10
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by lolp1 View Post
    The code above I posted is working as-is for me assuming you have a way to inject the dll and call the init export function, and you are building a .dll (e.g class library) with no default entry point.
    I am legitimately curious as to how I can avoid one of these DLLs, but I cannot get this working.
    These are my steps:
    1. Compile the following as a regular .NET DLL using the UnmanagedExports NuGet package:
    Code:
    public static class Program
    {
        private static AppDomain _domain;
    
    
        public static void Main()
        {
    
    
        }
    
    
        [DllExport("Initialize", CallingConvention.StdCall)]
        public static int Export_Initialize(int arg)
        {
            return Initialize();
        }
    
    
        [DllExport("Shutdown", CallingConvention.StdCall)]
        public static void Export_Shutdown(int arg)
        {
            Shutdown();
        }
    
    
        public static int Initialize()
        {
            if (_domain != null)
            {
                Shutdown();
            }
    
    
            var currentAssembly = Assembly.GetExecutingAssembly();
            var currentPath = Path.GetDirectoryName(currentAssembly.Location);
    
    
            _domain = AppDomain.CreateDomain("Gather.NET.Internal", null, currentPath, null, true);
            _domain.DoCallBack(InternalInitialize);
            return 0;
        }
    
    
        public static void Shutdown()
        {
            if (_domain == null)
            {
                return;
            }
    
    
            _domain.DoCallBack(InternalShutdown);
            AppDomain.Unload(_domain);
    
    
            _domain = null;
        }
    
    
        private static void InternalInitialize()
        {
            File.WriteAllText("C:\\running.txt", "blah");
            AppDomain.CurrentDomain.FirstChanceException += (sender, e) => HandleException("First-chance", e.Exception);
    
    
            AppDomain.CurrentDomain.UnhandledException +=
                (sender, e) => HandleException("Unhandled", e.ExceptionObject as Exception);
    
    
            Thread.Sleep(1000);
        }
    
    
        private static void InternalShutdown()
        {
            File.WriteAllText("C:\\shutdown.txt", "blah");
        }
    
    
        #region Exception handlers
    #if DEBUG
        private static void HandleException(string exceptionType, Exception exception)
        {
            //
        }
    #else
        private static void HandleException(string exceptionType, Exception exception)
        {
        }
    #endif
        #endregion
    }
    2. Inject that DLL and call the "Initialize" export. Confirm that "running.txt" was created, and that it returned 0 after 1 second.
    3. Make a small change. For example, I changed
    Code:
        [DllExport("Initialize", CallingConvention.StdCall)]
        public static int Export_Initialize(int arg)
        {
            return Initialize();
        }
    to
    Code:
        [DllExport("Initialize", CallingConvention.StdCall)]
        public static int Export_Initialize(int arg)
        {
            return Initialize() + 1;
        }

    4. Recompile. I am unable to do this because the DLL is still loaded.

    I also tried calling the Shutdown export, but this will crash WoW because the app domain being unloaded will throw an exception in the original "DoCallback" being invoked from the previous thread.

    Are you 100% sure you changing the actual project that includes the app domain loader? If you make no changes to it, VS will not need to recompile it, and it will work fine (since the rest of your project assemblies are not loaded in the main app domain).
    [16:15:41] Cypher: caus the CPU is a dick
    [16:16:07] kynox: CPU is mad
    [16:16:15] Cypher: CPU is all like
    [16:16:16] Cypher: whatever, i do what i want

Page 2 of 3 FirstFirst 123 LastLast

Similar Threads

  1. Replies: 3
    Last Post: 03-03-2017, 08:03 AM
  2. [Release][C#]WhiteMagic - Injected .NET Helper Library
    By Apoc in forum WoW Memory Editing
    Replies: 53
    Last Post: 01-23-2013, 09:58 AM
  3. Replies: 1
    Last Post: 01-19-2012, 03:14 AM
  4. exit/unload injected .net dll
    By YetiHunter in forum Programming
    Replies: 5
    Last Post: 02-28-2010, 06:57 AM
  5. [Show Off] The long process of corrupting Draenei back into Eredar.
    By dagello in forum World of Warcraft Model Editing
    Replies: 32
    Last Post: 09-13-2008, 05:47 AM
All times are GMT -5. The time now is 06:40 PM. Powered by vBulletin® Version 4.2.3
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved. User Alert System provided by Advanced User Tagging (Pro) - vBulletin Mods & Addons Copyright © 2024 DragonByte Technologies Ltd.
Digital Point modules: Sphinx-based search