private static void Create(ReverseWrapper <TFunction> reverseFunctionWrapper, IntPtr functionPtr) { var attribute = FunctionAttribute.GetAttribute <TFunction>(); // Hot path: Don't create wrapper if both conventions are already compatible. var managedFuncAttribute = Misc.TryGetAttributeOrDefault <TFunction, ManagedFunctionAttribute>(); if (managedFuncAttribute != null) { if (managedFuncAttribute.Equals(attribute)) { return; } reverseFunctionWrapper.WrapperPointer = Wrapper.Create <TFunction>(functionPtr, managedFuncAttribute, attribute); return; } var funcPtrAttribute = Misc.TryGetAttributeOrDefault <TFunction, UnmanagedFunctionPointerAttribute>(); if (!attribute.IsEquivalent(funcPtrAttribute)) { reverseFunctionWrapper.WrapperPointer = Wrapper.Create <TFunction>(functionPtr, attribute.GetEquivalent(funcPtrAttribute), attribute); } }
private static void Create(ReverseWrapper <TFunction> reverseFunctionWrapper, nuint functionPtr) { var attribute = FunctionAttribute.GetAttribute <TFunction>(); // Hot path: Don't create wrapper if both conventions are already compatible. var managedFuncAttribute = Misc.TryGetAttributeOrDefault <TFunction, ManagedFunctionAttribute>(); if (managedFuncAttribute != null) { if (managedFuncAttribute.Equals(attribute)) { reverseFunctionWrapper.WrapperPointer = Utilities.CreateJump(functionPtr, false, Constants.MaxAbsJmpSize).ToSigned(); return; } reverseFunctionWrapper.WrapperPointer = Wrapper.Create <TFunction>(functionPtr, managedFuncAttribute, attribute).ToSigned(); return; } var funcPtrAttribute = Misc.TryGetAttributeOrDefault <TFunction, UnmanagedFunctionPointerAttribute>(); if (!attribute.IsEquivalent(funcPtrAttribute)) { reverseFunctionWrapper.WrapperPointer = Wrapper.Create <TFunction>(functionPtr, attribute.GetEquivalent(funcPtrAttribute), attribute).ToSigned(); } else { reverseFunctionWrapper.WrapperPointer = Utilities.CreateJump(functionPtr, false, Constants.MaxAbsJmpSize).ToSigned(); } }
/// <summary> /// Creates the <see cref="Wrapper"/> in memory allowing you to call a function /// at functionAddress as if it was a CDECL function. /// </summary> /// <param name="functionAddress">The address of the function.</param> /// <param name="fromFunction">Describes the properties of the function to wrap.</param> /// <returns>Address of the wrapper in memory you can call like a CDECL function.</returns> public static IntPtr Create <TFunction>(IntPtr functionAddress, FunctionAttribute fromFunction) { // toFunction (target) is CDECL int numberOfParameters = Utilities.GetNumberofParameters(typeof(TFunction)); int nonRegisterParameters = numberOfParameters - fromFunction.SourceRegisters.Length; List <string> assemblyCode = new List <string> { "use32" }; // Backup Stack Frame assemblyCode.Add("push ebp"); // Backup old call frame assemblyCode.Add("mov ebp, esp"); // Setup new call frame // Reserve Extra Stack Space if (fromFunction.ReservedStackSpace > 0) { assemblyCode.Add($"sub esp, {fromFunction.ReservedStackSpace}"); } // Setup Function Parameters if (numberOfParameters > 0) { assemblyCode.AddRange(AssembleFunctionParameters(numberOfParameters, fromFunction.SourceRegisters)); } // Call target function var pointerBuffer = Utilities.FindOrCreateBufferInRange(IntPtr.Size); IntPtr targetFunctionPtr = pointerBuffer.Add(ref functionAddress); assemblyCode.Add("call dword [0x" + targetFunctionPtr.ToString("X") + "]"); // Stack cleanup if necessary if (nonRegisterParameters > 0 && fromFunction.Cleanup == FunctionAttribute.StackCleanup.Caller) { assemblyCode.Add($"add esp, {nonRegisterParameters * 4}"); } // Setup return register if (fromFunction.ReturnRegister != FunctionAttribute.Register.eax) { assemblyCode.Add("mov eax, " + fromFunction.ReturnRegister); } // Unreserve Extra Stack Space if (fromFunction.ReservedStackSpace > 0) { assemblyCode.Add($"add esp, {fromFunction.ReservedStackSpace}"); } // Restore Stack Frame and Return assemblyCode.Add("pop ebp"); assemblyCode.Add("ret"); // Write function to buffer and return pointer. byte[] assembledMnemonics = Utilities.Assembler.Assemble(assemblyCode.ToArray()); var wrapperBuffer = Utilities.FindOrCreateBufferInRange(assembledMnemonics.Length); return(wrapperBuffer.Add(assembledMnemonics)); }
private static IntPtr Create(IntPtr functionAddress, FunctionAttribute fromFunction) { // CDECL is hot path, as our TFunction will already be CDECL, we marshal if it's anything else. if (fromFunction.Equals(new FunctionAttribute(CallingConventions.Cdecl))) { return(functionAddress); } // Retrieve number of parameters and setup list of ASM instructions to be compiled. int numberOfParameters = Utilities.GetNumberofParameters(typeof(TFunction)); int nonRegisterParameters = numberOfParameters - fromFunction.SourceRegisters.Length; List <string> assemblyCode = new List <string> { "use32" }; // Backup Stack Frame assemblyCode.Add("push ebp"); // Backup old call frame assemblyCode.Add("mov ebp, esp"); // Setup new call frame // Push registers for our C# method as necessary. assemblyCode.AddRange(AssembleFunctionParameters(numberOfParameters, fromFunction.SourceRegisters)); // Call target function var pointerBuffer = Utilities.FindOrCreateBufferInRange(IntPtr.Size); IntPtr targetFunctionPtr = pointerBuffer.Add(ref functionAddress); assemblyCode.Add("call dword [0x" + targetFunctionPtr.ToString("X") + "]"); // MOV EAX return register into custom calling convention's return register. if (fromFunction.ReturnRegister != FunctionAttribute.Register.eax) { assemblyCode.Add($"mov {fromFunction.ReturnRegister}, eax"); } // Restore stack pointer. if (numberOfParameters > 0) { assemblyCode.Add($"add esp, {numberOfParameters * 4}"); } // Restore Stack Frame and Return assemblyCode.Add("pop ebp"); if (fromFunction.Cleanup == FunctionAttribute.StackCleanup.Callee) { assemblyCode.Add($"ret {nonRegisterParameters * 4}"); } else { assemblyCode.Add("ret"); } byte[] assembledMnemonics = Utilities.Assembler.Assemble(assemblyCode.ToArray()); var wrapperBuffer = Utilities.FindOrCreateBufferInRange(assembledMnemonics.Length); return(wrapperBuffer.Add(assembledMnemonics)); }
private static void Create(ReverseWrapper <TFunction> reverseFunctionWrapper, IntPtr functionPtr) { var reloadedFunctionAttribute = FunctionAttribute.GetAttribute <TFunction>(); // CDECL is hot path, as our TFunction will already be CDECL, we marshal if it's anything else. if (!reloadedFunctionAttribute.Equals(new FunctionAttribute(CallingConventions.Cdecl))) { reverseFunctionWrapper.WrapperPointer = Create(functionPtr, reloadedFunctionAttribute); } }
public override bool Equals(Object obj) { FunctionAttribute functionAttribute = obj as FunctionAttribute; if (functionAttribute == null) { return(false); } return(functionAttribute.Cleanup == Cleanup && functionAttribute.ReturnRegister == ReturnRegister && functionAttribute.SourceRegisters.SequenceEqual(SourceRegisters)); }
/// <summary> /// Creates the <see cref="Wrapper"/> which allows you to call a function with a custom calling /// convention as if it were a CDECL function. /// </summary> /// <param name="functionAddress">Address of the function to reverse wrap..</param> public static TFunction Create <TFunction>(long functionAddress) { var attribute = FunctionAttribute.GetAttribute <TFunction>(); IntPtr wrapperFunctionPointer = (IntPtr)functionAddress; // Hot path: CDECL functions require no wrapping. if (!attribute.Equals(new FunctionAttribute(CallingConventions.Cdecl))) { wrapperFunctionPointer = Create <TFunction>((IntPtr)functionAddress, attribute); } return(Marshal.GetDelegateForFunctionPointer <TFunction>(wrapperFunctionPointer)); }