Endscene Detour menu

Shout-Out

User Tag List

Results 1 to 11 of 11
  1. #1
    unbekannt1's Avatar Member
    Reputation
    -6
    Join Date
    Apr 2009
    Posts
    54
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Endscene Detour

    Hi,
    i successfully hooked the directx endscene method in heathstone with easyhook, but when i try to call game functions like GameState.Get().GetLocalPlayer() it throws an exception. Someone knows why its not working? I mean, i am calling the functions from the hooked endscene, which is running in the main thread, so in my opinion it should work fine, but it doesnt....

    Endscene Detour
  2. #2
    Apoc's Avatar Angry Penguin
    Reputation
    1388
    Join Date
    Jan 2008
    Posts
    2,750
    Thanks G/R
    0/13
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by unbekannt1 View Post
    Hi,
    i successfully hooked the directx endscene method in heathstone with easyhook, but when i try to call game functions like GameState.Get().GetLocalPlayer() it throws an exception. Someone knows why its not working? I mean, i am calling the functions from the hooked endscene, which is running in the main thread, so in my opinion it should work fine, but it doesnt....
    Because you're trying to call .NET functions from a native environment.

  3. #3
    unbekannt1's Avatar Member
    Reputation
    -6
    Join Date
    Apr 2009
    Posts
    54
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I am injecting a .NET dll written in C#. So i am calling the game methods from an .NET enviroment, or am i getting it wrong?

  4. #4
    Maddin1803's Avatar Member
    Reputation
    25
    Join Date
    Mar 2012
    Posts
    40
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    If you want to go this route, you have to hook function related to loading of assemblys in the mono.dll, get the mainthread and load another dll there.

    After your hook, you are in context of the native hearstone client, this process hosts a .NET ByteCode VM, you need to get you dll loaded within it, after that you should be able to call the functions.

  5. #5
    Apoc's Avatar Angry Penguin
    Reputation
    1388
    Join Date
    Jan 2008
    Posts
    2,750
    Thanks G/R
    0/13
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by Maddin1803 View Post
    If you want to go this route, you have to hook function related to loading of assemblys in the mono.dll, get the mainthread and load another dll there.

    After your hook, you are in context of the native hearstone client, this process hosts a .NET ByteCode VM, you need to get you dll loaded within it, after that you should be able to call the functions.
    Well, you really don't need all that...

    You can inject assemblies in the Unity process with zero hooks.

    Edit; ok, one hook. You just need to execute some stuff from the "main thread" (which EndScene is called from)
    Last edited by Apoc; 04-03-2014 at 04:21 PM.

  6. #6
    Maddin1803's Avatar Member
    Reputation
    25
    Join Date
    Mar 2012
    Posts
    40
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    You are absolutly right

    Dont know what i was thinking, ofcourse its enough to call the function related to assembly loading after you are somewhere in the mainthread.

  7. #7
    unbekannt1's Avatar Member
    Reputation
    -6
    Join Date
    Apr 2009
    Posts
    54
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks for your answers!

    I think i got it nearly working, but mono_jit_execute won't call the static main method of my managed dll...

    Assembly loading from hooked EndScene:
    Code:
    HRESULT __stdcall hkEndScene(LPDIRECT3DDEVICE9 pDevice) 
    {
    	if(!loaded)
    	{
    		MonoAssembly *assembly;
    	        assembly = mono_domain_assembly_open(mono_domain_get(), "D:\\loadDll.dll");
    
    	        if (!assembly)
    		     MessageBoxA(NULL,"ERROR", "ERROR", MB_OK);
    
    	        int retval = mono_jit_exec (mono_domain_get(), assembly, 0, NULL);
    
    		loaded = true;
    	}
    }
    c# loadDll.dll Source
    Code:
    using System;
    using System.Collections.Generic;
    using System.Text;
    
    
        public class Class1
        {
            public static void Main()
            {
                System.Windows.Forms.MessageBox.Show("asdasd");
            }
        }
    Someone got an idea?

  8. #8
    Apoc's Avatar Angry Penguin
    Reputation
    1388
    Join Date
    Jan 2008
    Posts
    2,750
    Thanks G/R
    0/13
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    That's because mono_jit_exec only works for starting up the domain. You need to use mono_runtime_invoke to call things at runtime.

  9. #9
    unbekannt1's Avatar Member
    Reputation
    -6
    Join Date
    Apr 2009
    Posts
    54
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ok, tried that and i am able to open the assembly, get the image, get the class of the correct namespace and finally get the method, but when i am invoking it nothing happens...

    Code:
    			MonoDomain *domain = mono_domain_get();
    			MonoAssembly *monoAssembly = mono_domain_assembly_open(domain, "D:\\loadDll.dll");
    
    			MonoImage *image = mono_assembly_get_image (monoAssembly);
    		    MonoClass *my_class = mono_class_from_name (image, "MyNamespace", "Loader");
    
    			MonoObject* obj = mono_object_new (domain, my_class);
    
    			MonoMethod *method = NULL, *m = NULL;
    			void* iter;
    			iter = NULL;
    			while ((m = mono_class_get_methods (my_class, &iter))) {
    				if (strcmp (mono_method_get_name (m), "testMethod") == 0) {
    					method = m;
    				} 
    			}
    			void *args[1];
    			args[0] = mono_string_new(mono_domain_get(), "blup");
    			mono_runtime_invoke(method, obj, args, NULL);
    I am looping through all methods, because MonoMethodDesc* mmd = mono_method_desc_new("testMethod", TRUE); is crashing Hearthstone...


    The loaderDll
    Code:
    namespace MyNamespace
    {
        public class Loader
        {
            public Loader()
            {
                System.Windows.Forms.MessageBox.Show("aus dll");
            }
    
            public void testMethod(String a)
            {
                System.Windows.Forms.MessageBox.Show("aus testMethod");
            }
        }
    
    }
    Last edited by unbekannt1; 04-05-2014 at 11:17 AM.

  10. #10
    Apoc's Avatar Angry Penguin
    Reputation
    1388
    Join Date
    Jan 2008
    Posts
    2,750
    Thanks G/R
    0/13
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Wasn't going to share this right away, but since "HREngine" already uses this approach... here's a full bootstrapper. It doesn't contain any EndScene hooks, or the like. However, it is visible to any anti-cheat as an injected module. So you'll need to be careful with it. If you're using it privately, you should be fine. However, be very, very careful, if you intend to use it in a public project. You'll likely see a ban-hammer once Warden is activated.

    Code:
    #define WIN32_LEAN_AND_MEAN#include <windows.h>
    #include <string>
    #include <vector>
    #include <fstream>
    
    
    typedef void* (* _mono_image_open_from_data_with_name) (char* data, DWORD data_len, int need_copy, int* status, int refOnly, const char* name);
    typedef void* (* _mono_assembly_load_from_full) (void* image, const char* fname, int* status, int refonly);
    typedef void* (*_mono_assembly_get_image)(void* assembly);
    typedef int (*_mono_image_get_table_rows)(void* image, int table);
    typedef void* (*_mono_class_get)(void* image, int type_token);
    typedef const char* (*_mono_class_get_name)(void* klass);
    typedef const char* (*_mono_class_get_namespace)(void* klass);
    typedef void* (*_mono_class_get_methods)(void* klass, void* itr);
    typedef const char* (*_mono_method_get_name)(void* method);
    typedef void* (*_mono_domain_get)();
    typedef void* (*_mono_string_new)(void* domain, const char* text);
    typedef void* (*_mono_runtime_invoke)(void* method, void* obj, void** params, void** exc);
    
    
    #define ASSEMBLY_NAME "Unityject.dll"
    
    
    _mono_image_open_from_data_with_name mono_image_open_from_data_with_name;
    _mono_assembly_load_from_full mono_assembly_load_from_full;
    _mono_assembly_get_image mono_assembly_get_image;
    _mono_image_get_table_rows mono_image_get_table_rows;
    _mono_class_get mono_class_get;
    _mono_class_get_name mono_class_get_name;
    _mono_class_get_namespace mono_class_get_namespace;
    _mono_class_get_methods mono_class_get_methods;
    _mono_method_get_name mono_method_get_name;
    _mono_domain_get mono_domain_get;
    _mono_string_new mono_string_new;
    _mono_runtime_invoke mono_runtime_invoke;
    
    
    void PopulateMethods()
    {
        HMODULE m = GetModuleHandle(L"mono.dll");
        mono_image_open_from_data_with_name = (_mono_image_open_from_data_with_name)GetProcAddress(m, "mono_image_open_from_data_with_name");
        mono_assembly_load_from_full = (_mono_assembly_load_from_full)GetProcAddress(m, "mono_assembly_load_from_full");
        mono_assembly_get_image = (_mono_assembly_get_image)GetProcAddress(m, "mono_assembly_get_image");
        mono_image_get_table_rows = (_mono_image_get_table_rows)GetProcAddress(m, "mono_image_get_table_rows");
        mono_class_get = (_mono_class_get)GetProcAddress(m, "mono_class_get");
        
        mono_class_get_name = (_mono_class_get_name)GetProcAddress(m, "mono_class_get_name");
        mono_class_get_namespace = (_mono_class_get_name)GetProcAddress(m, "mono_class_get_namespace");
    
    
        mono_class_get_methods = (_mono_class_get_methods)GetProcAddress(m, "mono_class_get_methods");
        mono_method_get_name = (_mono_method_get_name)GetProcAddress(m, "mono_method_get_name");
    
    
        mono_domain_get = (_mono_domain_get)GetProcAddress(m, "mono_domain_get");
        mono_string_new = (_mono_string_new)GetProcAddress(m, "mono_string_new");
    
    
        mono_runtime_invoke = (_mono_runtime_invoke)GetProcAddress(m, "mono_runtime_invoke");
    
    
        CloseHandle(m);
    }
    
    
    void* FindClass(void* image, const char* className, const char* classNamespace)
    {
        // Now find the class in the assembly we just loaded.
        // We do it this way, because the "generic" lookup stuff seems to be pitiful with Unity.
        // Sometimes it works, but most of the time, it doesn't. This resolves that entirely.
    
    
        int numTypes = mono_image_get_table_rows(image, 0x2); // MONO_TABLE_TYPEDEF
        void* foundClass = 0;
    
    
        // Note: start at 1, go 1 beyond the end
        // This expects 0x02000001, 0x02000002, etc
        // Passing 0x02000000 will cause an error (sometimes), or return nothing.
        for (int i = 1; i < numTypes+1; i++)
        {
            void* klass = mono_class_get(image, i | 0x02000000); // MONO_TOKEN_TYPE_DEF
    
    
            if(!klass)
                continue;
    
    
            std::string name = mono_class_get_name(klass);
            std::string ns = mono_class_get_namespace(klass);
    
    
            if(name == className && ns == classNamespace)
            {
                foundClass = klass;
                break;
            }
        }
        return foundClass;
    }
    
    
    void* FindMethod(void* classPtr, const char* methodName)
    {
        void* itr = 0;
        void* method = 0;
        while((method = mono_class_get_methods(classPtr, itr)))
        {
            std::string name = mono_method_get_name(method);
    
    
            if(name == methodName)
                return method;
        }
        return NULL;
    }
    
    
    extern "C" __declspec( dllexport ) 
    void Run(char* assemblyData, int assemblyDataLength, const char* classNamespace, const char* className, const char* functionName, const char* functionArgs)
    {
        // Ensure we have methods mapped.
        if(!mono_runtime_invoke)
            PopulateMethods();
    
    
        int status = 0;
        void* image = mono_image_open_from_data_with_name(assemblyData, assemblyDataLength, 1, &status, 0, ASSEMBLY_NAME);
        if(!image || status != 0)
        {
            MessageBoxA(0, "Could not open image!", "Error", 0);
            return;
        }
    
    
        void* assembly = mono_assembly_load_from_full(image, ASSEMBLY_NAME, &status, false);    
        if(!assembly || status != 0)
        {
            MessageBoxA(0, "Could not open image!", "Error", 0);
            return;
        }
    
    
        // Ensure we can get an image from the assembly.
        if(!mono_assembly_get_image(assembly))
        {
            MessageBoxA(0, "Assembly image could not be retrieved! (Sanity Check)", "Error", 0);
            return;
        }
    
    
        // Now find the class in the assembly we just loaded.
        // We do it this way, because the "generic" lookup stuff seems to be pitiful with Unity.
        // Sometimes it works, but most of the time, it doesn't. This resolves that entirely.
    
    
        int numTypes = mono_image_get_table_rows(image, 0x2); // MONO_TABLE_TYPEDEF
    
    
        void* foundClass = FindClass(image, className, classNamespace);
        if(!foundClass)
        {
            MessageBoxA(0, "Class type could not be found!", "Error", 0);
            return;
        }
    
    
        void* foundMethod = FindMethod(foundClass, functionName);
        if(!foundMethod)
        {
            MessageBoxA(0, "Method could not be found!", "Error", 0);
            return;
        }
        
        if(functionArgs)
        {
            void* str = mono_string_new(mono_domain_get(), functionArgs);
            void* args[1];
            args[0] = str;
            // Invoke the method on a "NULL" object (static call), with the specified arguments.
            mono_runtime_invoke(foundMethod, NULL, args, NULL);
        }
        else
        {
            void** args = NULL;
            mono_runtime_invoke(foundMethod, NULL, args, NULL);
        }
    
    
    }
    
    
    // Simple method wrapper for reading the bytes of a file.
    // We don't want to load into the game with a full path. Just have Mono generate a name.
    // However, this does break things like Assembly.GetExecutingAssembly() and whatnot. You'll probably need to use
    // something like... System.Diagnostics.Process.GetCurrentProcess().MainModule for path-related things.
    // Optionally, just pass the "bin path" for your lib to your entry point method.
    static std::vector<char> ReadAllBytes(char const* filename)
    {
        std::ifstream ifs(filename, std::ios::binary|std::ios::ate);
        std::ifstream::pos_type pos = ifs.tellg();
    
    
        std::vector<char>  result(pos);
    
    
        ifs.seekg(0, std::ios::beg);
        ifs.read(&result[0], pos);
    
    
        return result;
    }
    
    
    void Example()
    {
        // NOTE: DON'T DO this here, "Run" is an export. Call it from the main mono thread. This is just an example!
        std::vector<char> bytes = ReadAllBytes("C:\\SomeEntrypointDll.dll");
    
    
        Run(&bytes[0], bytes.size(), "MyNamespace", "MyClassName", "MyEntryPointMethod", "this is just any arguments you decide to pass, in string form");
    }
    
    
    BOOL APIENTRY DllMain( HMODULE hModule,
                           DWORD  ul_reason_for_call,
                           LPVOID lpReserved
                         )
    {
        switch (ul_reason_for_call)
        {
        case DLL_PROCESS_ATTACH:
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
            break;
        }
        return TRUE;
    }
    Re-use all you want. It resolves a few issues with Unity doing weird things. (Especially when loading assemblies without full paths!)

  11. #11
    Kane49's Avatar Member
    Reputation
    1
    Join Date
    Oct 2006
    Posts
    21
    Thanks G/R
    1/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks man, that saved me alot of headache
    I can see why you chose the more complicated approach of wrapping all the objects yourself in your wide commercial release though

Similar Threads

  1. EndScene detour question
    By bad6oy30 in forum WoW Memory Editing
    Replies: 4
    Last Post: 02-23-2011, 05:37 PM
  2. Replies: 11
    Last Post: 01-06-2011, 02:59 PM
  3. C# Troubleshooting my endscene detour 3.3.5 (12340)
    By opulent in forum WoW Memory Editing
    Replies: 11
    Last Post: 07-26-2010, 05:00 AM
  4. Grabbing the DX device in endscene detour
    By ggg898 in forum WoW Memory Editing
    Replies: 0
    Last Post: 09-08-2009, 06:41 AM
All times are GMT -5. The time now is 06:35 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