void Out(ref int someInt) { Input(__makeref(someInt)); } void Input(TypedReference @ref) { int val = __refvalue(@ref, int);// __refvalue(@ref, int) = 0;// someInt } void Out(int something) { Input(__arglist(something)); } void Input(__arglist) { new ArgIterator(__arglist); } delegate void ArgWarrior(RuntimeArgumentHandle argh); void Out(int something) { (new ArgWarrior(u => { } ))(__arglist(someting));// Input(new ArgWarrior(u => { } ), __arglist(someting); } void Input(ArgWarrior argh, __arglist) { argh(__arglist);// }
_methodPtrAux is the fourth field in any delegated type that will play a key role here. What is the point? The bottom line is that _methodPtrAux stores a pointer to an already jit method. By writing arbitrary unmanaged code by that pointer, this unmanaged code can be executed in this way. But this is not the point. The delegate remains usable even after replacing the _methodPtrAux value, and when you call it, control will go exactly where the value of this field indicates. Thus, having two delegates with different input parameters, I can replace the pointer from delegate a with the pointer from delegate b . Even if they have a different set of arguments, everything will work. The key point will be the fact that even if the types of the corresponding arguments are different, clr will not forget the alarm - the int will be empty in string, delegate void Encast(RuntimeArgumentHandle @ref); delegate void Uncast(object @object); static void UseWith(Encast en, __arglist) { en(__arglist); } static object m_storedRef; static void Engage(ref object @object) { Encast en = new Encast(@ref => { }); Uncast un = new Uncast(o => { m_storedRef = o;// <b>en</b>. }); typeof(Encast).GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)[3].SetValue(en, typeof(Uncast).GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)[3].GetValue(un));// en UseWith(en, __arglist(__makeref(@object))); // } static object m_locker = new object(); //... Monitor.Enter(m_locker); Monitor.Exit(m_locker); using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; namespace ThreadJiggler { class Program { delegate void Encast(RuntimeArgumentHandle @ref); delegate void Uncast(object @object); static object m_storedRef; static object m_locker = new object(); static bool m_useFlag; static void Main(string[] args) { object @v = "means \"vendetta\""; Victim1(ref @v); Console.WriteLine(@v); } static void UseWith(Encast en, __arglist) { en(__arglist); } static Thread m_someThread; static void Victim1(ref object @object) { Thread t = new Thread(() => { Monitor.Enter(m_locker); { for (; !m_useFlag; ) { Thread.Sleep(10); } Encast en = new Encast(@ref => { TypedReference tr = new ArgIterator(@ref).GetNextArg(); __refvalue( tr, object) = 0; }); Uncast un = new Uncast(o => { m_storedRef = o; }); typeof(Uncast).GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)[3].SetValue(un, typeof(Encast).GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)[3].GetValue(en)); un(m_storedRef); } Monitor.Exit(m_locker); }); t.IsBackground = false; t.Start(); { Encast en = new Encast(@ref => { }); Uncast un = new Uncast(o => { m_storedRef = o; m_useFlag = true; Monitor.Enter(m_locker); Monitor.Exit(m_locker); }); typeof(Encast).GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)[3].SetValue(en, typeof(Uncast).GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)[3].GetValue(un)); UseWith(en, __arglist(__makeref(@object))); } } } } Source: https://habr.com/ru/post/192140/
All Articles