Beispiel #1
0
		static void Main(string[] args)
		{
			if (args.Length < 2)
			{
				Console.WriteLine("Usage: Hooker.exe [GameName_Data directory] [hooks file]");
				return;
			}
			var dataPath = args[0];
			var inStream = File.Open("Assembly-CSharp.dll", FileMode.Open, FileAccess.Read);
			var scriptAssembly = AssemblyDefinition.ReadAssembly(inStream);
			var hooker = new Hooker(scriptAssembly.MainModule);
			using (var fs = new FileStream(args[1], FileMode.Open, FileAccess.Read))
			using (var sr = new StreamReader(fs))
			while (!sr.EndOfStream)
			{
				var line = sr.ReadLine();
				var dotI = line.IndexOf('.');
				if (dotI > 0)
				{
					hooker.AddHookBySuffix(line.Substring(0, dotI), line.Substring(dotI + 1));
				}
			}

			scriptAssembly.Write("Assembly-CSharp.out.dll");

			foreach (var assemblyName in new []{"Assembly-CSharp", "HookRegistry", "Newtonsoft.Json"})
			{
				var srcName = assemblyName + ".dll";
				if (File.Exists(assemblyName + ".out.dll"))
				{
					srcName = assemblyName + ".out.dll";
				}
				File.Copy(srcName, Path.Combine(dataPath, @"Managed", assemblyName + ".dll"), true);
			}
		}
Beispiel #2
0
        public static Hooker New(ModuleDefinition module, HookSubOptions options)
        {
            /*
             * These things have to be recreated for every module!
             * This is because a reference is specifically generated from a certain module and cannot be reused
             * by another module!
             */

            // Fetch types and references
            TypeDefinition _hookRegistryType = options.HookRegistryType;
            // RuntimeMethodHandle gives us information about the hooked function.
            // By doing this import we FAIL EARLY if the Type could not be found. (headache prevention)
            // var rmhTypeRef = module.Import(typeof(RuntimeMethodHandle));
            // Look for the HookRegistry.onCall(..) method
            var onCallMethod    = _hookRegistryType.Methods.First(mi => mi.Name.Equals("OnCall"));
            var onCallMethodRef = module.Import(onCallMethod);
            // The (reference) name for in the manifest of the hooked library. The runtime loads all referenced libraries
            // into application domain. Once in application domain, methods and types can resolve.
            // var hrAssemblyName = AssemblyNameReference.Parse(options.HooksRegistryAssembly.FullName);
            // By adding a new reference (pointing to our HookRegistry assembly), we are certain
            // that Module can resolve the calls to our hooks.
            // MARK; CECIL DOES THIS FOR US
            // module.AssemblyReferences.Add(hrAssemblyName);

            var newObj = new Hooker
            {
                Module          = module,
                onCallMethodRef = onCallMethodRef,
            };

            return(newObj);
        }
Beispiel #3
0
        static void Main(string[] args)
        {
            var dataPath = "D:\\Program Files (x86)\\Hearthstone\\Hearthstone_Data";

            foreach (var s in new[] { "Assembly-CSharp-firstpass", "Assembly-CSharp" })
            {
                var inStream       = File.Open(s + ".dll", FileMode.Open, FileAccess.Read);
                var scriptAssembly = AssemblyDefinition.ReadAssembly(inStream);
                var hooker         = new Hooker(scriptAssembly.MainModule);
                using (var fs = new FileStream("../../example_hooks", FileMode.Open, FileAccess.Read))
                    using (var sr = new StreamReader(fs))
                        while (!sr.EndOfStream)
                        {
                            var line = sr.ReadLine();
                            var dotI = line.IndexOf('.');
                            if (dotI > 0)
                            {
                                hooker.AddHookBySuffix(line.Substring(0, dotI), line.Substring(dotI + 1));
                            }
                        }

                scriptAssembly.Write(s + ".out.dll");
            }

            foreach (var assemblyName in new [] { "Assembly-CSharp", "Assembly-CSharp-firstpass", "HookRegistry", "Newtonsoft.Json" })
            {
                var srcName = assemblyName + ".dll";
                if (File.Exists(assemblyName + ".out.dll"))
                {
                    srcName = assemblyName + ".out.dll";
                }
                File.Copy(srcName, Path.Combine(dataPath, @"Managed", assemblyName + ".dll"), true);
            }
        }
Beispiel #4
0
        public static Hooker New(ModuleDefinition module, HookSubOptions options)
        {
            /*
             *  These things have to be recreated for every module!
             *  This is because a reference is specifically generated from a certain module and cannot be reused
             *  by another module!
             */

            // Fetch types and references
            TypeDefinition _hookRegistryType = options.HookRegistryType;
            // Look for the HookRegistry.onCall(..) method
            var onCallMethod    = _hookRegistryType.Methods.First(mi => mi.Name.Equals("OnCall"));
            var onCallMethodRef = module.Import(onCallMethod);

            var newObj = new Hooker
            {
                Module          = module,
                onCallMethodRef = onCallMethodRef,
            };

            return(newObj);
        }
Beispiel #5
0
        static void Main(string[] args)
        {
            if (args.Length < 2)
            {
                Console.WriteLine("Usage: Hooker.exe [GameName_Data directory] [hooks file]");
                return;
            }
            var dataPath = args[0];

            foreach (var s in new[] { "Assembly-CSharp-firstpass", "Assembly-CSharp" })
            {
                var inStream       = File.Open(s + ".dll", FileMode.Open, FileAccess.Read);
                var scriptAssembly = AssemblyDefinition.ReadAssembly(inStream);
                var hooker         = new Hooker(scriptAssembly.MainModule);
                using (var fs = new FileStream(args[1], FileMode.Open, FileAccess.Read))
                    using (var sr = new StreamReader(fs))
                        while (!sr.EndOfStream)
                        {
                            var line = sr.ReadLine();
                            var dotI = line.IndexOf('.');
                            if (dotI > 0)
                            {
                                hooker.AddHookBySuffix(line.Substring(0, dotI), line.Substring(dotI + 1));
                            }
                        }

                scriptAssembly.Write(s + ".out.dll");
            }

            foreach (var assemblyName in new [] { "Assembly-CSharp", "Assembly-CSharp-firstpass", "HookRegistry", "Newtonsoft.Json" })
            {
                var srcName = assemblyName + ".dll";
                if (File.Exists(assemblyName + ".out.dll"))
                {
                    srcName = assemblyName + ".out.dll";
                }
                File.Copy(srcName, Path.Combine(dataPath, @"Managed", assemblyName + ".dll"), true);
            }
        }
Beispiel #6
0
        public void TryHook()
        {
            // Validate all options
            CheckOptions();
            // Copy our injected library to the location of the 'to patch' assemblies
            CopyHooksLibrary();
            // Find all needed types
            FindNecessaryTypes();
            // Find all method fullnames that the hookregistry expects
            FetchExpectedMethods();

            // Read all hook functions into memory
            var hookEntries = ReadHooksFile(_options.HooksFilePath);

            // Initialise the AssemblyStore with the given path.
            // All assemblies are parsed from their own location.
            var asStore = AssemblyStore.Get(_options.GamePath);

            // Loop all libraries looking for methods to hook       ! important - core
            // Library is a reference to the filename of the assembly file containing the actual
            // code we want to patch.
            foreach (AssemblyStore.LIB_TYPE library in AssemblyStore.GetAllLibraryTypes())
            {
                // Skip invalid lib!
                if (library == AssemblyStore.LIB_TYPE.INVALID)
                {
                    continue;
                }

                // Full path to current assembly
                string libraryPath = library.GetPath();
                // Full path to processed assembly
                string libraryOutPath = library.GetPathOut();

                // Load the assembly file
                AssemblyDefinition assembly;
                AssemblyStore.GetAssembly(library, out assembly);
                if (assembly.HasPatchMark())
                {
                    Program.Log.Warn(ASSEMBLY_ALREADY_PATCHED, libraryPath);
                    continue;
                }

                // Construct a hooker wrapper around the main Module of the assembly.
                // The wrapper facilitates hooking into method calls.
                ModuleDefinition mainModule = assembly.MainModule;
                Hooker           wrapper    = Hooker.New(mainModule, _options);
                Program.Log.Info(CHECKING_ASSEMBLY, libraryPath);

                // Keep track of hooked methods
                bool isHooked = false;
                // Loop each hook entry looking for registered types and methods
                foreach (HOOK_ENTRY hookEntry in hookEntries)
                {
                    try
                    {
                        wrapper.AddHookBySuffix(hookEntry.TypeName, hookEntry.MethodName, ExpectedMethods);
                        isHooked = true;
                    }
                    catch (MissingMethodException)
                    {
                        // The method is not found in the current assembly.
                        // This is no error because we run all hook entries against all libraries!
                    }
                }

                try
                {
                    // Only save if the file actually changed!
                    if (isHooked)
                    {
                        // Generate backup from original file
                        library.Backup();
                        // Save the manipulated assembly
                        library.Save();

                        // TODO UNCOMMENT
                        // Overwrite the original with the hooked one
                        File.Copy(libraryOutPath, libraryPath, true);
                    }
                    else
                    {
                        Program.Log.Debug(ASSEMBLY_NOT_PATCHED, libraryPath);
                    }
                }
                catch (IOException e)
                {
                    // The file could be locked! Notify user.
                    // .. or certain libraries could not be resolved..
                    // Try to find the path throwing an exception.. but this method is not foolproof!
                    var path = typeof(IOException).GetField("_maybeFullPath", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase)?.GetValue(e);
                    Program.Log.Exception(ERR_WRITE_FILE, null, e?.ToString());

                    throw;
                }
            } // End foreach LIB_TYPE
        }
Beispiel #7
0
        public void TryHook(GameKB gameKnowledge)
        {
            // Validate all command line options.
            CheckOptions();
            // Copy our injected library to the location of the 'to hook' assemblies.
            CopyHooksLibrary();
            //
            FindNecessaryTypes();
            // Find all expected method fullnames by HookRegistry.
            FetchExpectedMethods();

            var hookEntries = ReadHooksFile(_options.HooksFilePath);

            // Iterate all libraries known for the provided game.
            // An assembly blueprint will be created from the yielded filenames.
            // The blueprints will be edited, saved and eventually replaces the original assembly.
            foreach (string libraryFilePath in gameKnowledge)
            {
                var libBackupPath  = AssemblyHelper.GetPathBackup(libraryFilePath);
                var libPatchedPath = AssemblyHelper.GetPathOut(libraryFilePath);

                // Load the assembly file
                AssemblyDefinition assembly = AssemblyHelper.LoadAssembly(libraryFilePath,
                                                                          gameKnowledge.LibraryPath);
                if (assembly.HasPatchMark())
                {
                    Program.Log.Warn(ASSEMBLY_ALREADY_PATCHED, libraryFilePath);
                    continue;
                }

                // Construct a hooker wrapper around the main Module of the assembly.
                // The wrapper facilitates hooking into method calls.
                ModuleDefinition mainModule = assembly.MainModule;
                Hooker           wrapper    = Hooker.New(mainModule, _options);
                Program.Log.Info(CHECKING_ASSEMBLY, libraryFilePath);

                // Keep track of hooked methods
                bool isHooked = false;
                // Loop each hook entry looking for registered types and methods
                foreach (HOOK_ENTRY hookEntry in hookEntries)
                {
                    try
                    {
                        wrapper.AddHookBySuffix(hookEntry.TypeName, hookEntry.MethodName, ExpectedMethods);
                        isHooked = true;
                    }
                    catch (MissingMethodException)
                    {
                        // The method is not found in the current assembly.
                        // This is no error because we run all hook entries against all libraries!
                    }
                }

                try
                {
                    // Only save if the file actually changed!
                    if (isHooked)
                    {
                        // Generate backup from original file
                        try
                        {
                            // This throws if the file already exists.
                            File.Copy(libraryFilePath, libBackupPath, false);
                        }
                        catch (Exception)
                        {
                            // Do nothing
                        }

                        // Save the manipulated assembly.
                        assembly.Save(libPatchedPath);

                        // Overwrite the original with the hooked one
                        File.Copy(libPatchedPath, libraryFilePath, true);
                    }
                    else
                    {
                        Program.Log.Debug(ASSEMBLY_NOT_PATCHED, libraryFilePath);
                    }
                }
                catch (IOException e)
                {
                    // The file could be locked! Notify user.
                    // .. or certain libraries could not be resolved..
                    // Try to find the path throwing an exception.. but this method is not foolproof!
                    var path = typeof(IOException).GetField("_maybeFullPath",
                                                            BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase)?.GetValue(e);
                    Program.Log.Exception(ERR_WRITE_FILE, null, e?.ToString());

                    throw;
                }
            }
        }