Ejemplo n.º 1
0
        /// <summary>
        /// Assembles an absolute jump to a user specified address and returns
        /// the resultant bytes of the assembly process.
        /// </summary>
        /// <param name="functionAddress">The address to assemble the absolute call to.</param>
        /// <param name="reloadedFunction">Structure containing the details of the actual function in question.</param>
        /// <returns>A set of X64 assembler bytes to absolute jump to a specified address.</returns>
        public static List <string> X64AssembleAbsoluteCallMnemonics(IntPtr functionAddress, X64ReloadedFunctionAttribute reloadedFunction)
        {
            // List of ASM Instructions to be Compiled
            List <string> assemblyCode = new List <string>();

            // Assemble the call to the game function in question.
            // With the rewrite of MemoryBuffer, this piece of code has been greatly simplified.
            IntPtr gameFunctionPointer;

            if ((gameFunctionPointer = MemoryBufferManager.Add(functionAddress, IntPtr.Zero)) != IntPtr.Zero)
            {
                // Jump to Game Function Pointer (gameFunctionPointer is address at which our function address is written)
                assemblyCode.Add("call qword [qword 0x" + gameFunctionPointer.ToString("X") + "]");
            }
            // Cannot get buffer in 2GB range.
            else
            {
                // Get register to delegate function calling to.
                X64ReloadedFunctionAttribute.Register jmpRegister = FunctionCommon.GetCallRegister(reloadedFunction);

                // Call Game Function Pointer (gameFunctionPointer is address at which our function address is written)
                assemblyCode.Add($"mov {jmpRegister}, 0x{functionAddress.ToString("X")}");
                assemblyCode.Add($"call {jmpRegister}");
            }

            // Assemble the individual bytes.
            return(assemblyCode);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Returns a register to be used for calling of the target function.
        /// </summary>
        /// <param name="reloadedFunction">
        ///     Structure containing the details of the actual function in question.
        ///     The source registers (parameters) are considered to be a blacklist of registers that cannot be used.
        ///     The return register is considered by default as the starting candidate.
        /// </param>
        public static X64ReloadedFunctionAttribute.Register GetCallRegister(X64ReloadedFunctionAttribute reloadedFunction)
        {
            // X86-64 doesn't support 64bit immediates in most instructions, meaning that we must, unfortunately
            // make use of a register to call a game function in question.
            // Here we find an unused register and delegate it to calling the function.

            // Default value | nonvolatile register
            X64ReloadedFunctionAttribute.Register callRegister = reloadedFunction.ReturnRegister;

            // Use return register if it's not a parameter (safe).
            if (!reloadedFunction.SourceRegisters.Contains(callRegister))
            {
                return(callRegister);
            }

            // Use R11 (volatile) if it's not a parameter.
            if (!reloadedFunction.SourceRegisters.Contains(X64ReloadedFunctionAttribute.Register.r11))
            {
                return(X64ReloadedFunctionAttribute.Register.r11);
            }

            // Use R10 (volatile) if it's not a parameter.
            if (!reloadedFunction.SourceRegisters.Contains(X64ReloadedFunctionAttribute.Register.r10))
            {
                return(X64ReloadedFunctionAttribute.Register.r10);
            }

            // Otherwise brute force!
            foreach (X64ReloadedFunctionAttribute.Register foo in Enum.GetValues(
                         typeof(X64ReloadedFunctionAttribute.Register)))
            {
                // Don't use a parameter register.
                if (reloadedFunction.SourceRegisters.Contains(foo))
                {
                    continue;
                }

                return(foo);
            }

            return(callRegister);
        }