static public void __REPLACE(params byte[] _opcodes) { _FuncPtr32 caller = new _FuncPtr32(__TOPCALLER()); //caller.WriteLine(); if (caller.Size < _opcodes.Length) //|| true) { //array cannot fit existing allocation //Console.WriteLine("test"); _FuncPtr32 rebase = new _FuncPtr32(0, _opcodes.Length); rebase.Array2Image(_opcodes); rebase.Image2Raw(); rebase.WriteLine(); //Console.WriteLine("test2"); caller.Stream2Image(); caller.Stream((byte)0x68); caller.Stream((int)rebase); caller.Stream((byte)0xC3); //Console.WriteLine("test4"); caller.Image2Raw(); caller.WriteLine(); //Console.WriteLine("test5"); } else { //array can fit caller.Array2Image(_opcodes); caller.Image2Raw(); } //Console.WriteLine("test6"); __DROPSPECIAL((int)caller); //this value is adjusted //throw new Exception("__REPLACE FAILURE"); }
//this is "magical" rejit class that allows to emit custom assembly into existing managed method //including operations that are not allowed by C# or default calling convention //like modification of stackframe, that belongs to other function call //there are absolutely no safety checks, you can crash entire runtime by single invalid opcode //also you may cause delayed crash if mess with GC or return pointers //method will be called like normal, hitting __REPLACE routine will terminate method //replace it's code with provided sequence //and RESTART method //if method can't be replaced, new method will be allocated inside unmanaged memory //relative calls like E8 and E9 will be patched automatically //everything else will be left as it is //you can use __REPLACE(0xC3) inside condition to "nullify" singlerun methods //also you may put __REPLACE(0xC3) to very end of method with same result //method will not be changed before actual call into __REPLACE //obviously, you can't use __REBASE to emic call into rebase, it will cause "problems" //static unsafe void __REJIT_ static _ReJIT() { _FuncPtr32 RETIMM = new _FuncPtr32(typeof(_ReJIT).GetMethod("__TOPCALLER")); RETIMM.Array2Image ( 0x8B, 0x45, 0x04, //mov eax,DWORD PTR [esp+0x0] 0xC3 //ret ); RETIMM.Image2Raw(); _FuncPtr32 DROPSPECIAL = new _FuncPtr32(typeof(_ReJIT).GetMethod("__DROPSPECIAL")); DROPSPECIAL.Array2Image ( 0x8B, 0x44, 0x24, 0x04, 0xC9, 0xC9, 0x50, 0xC3 ); DROPSPECIAL.Image2Raw(); }
static unsafe public void Main(string[] args) { Console.WriteLine("Entry:start"); stored_ORIGINAL = new _FuncPtr32(typeof(_yaCIL).GetMethod("ORIGINAL")); stored_ORIGINAL.Rebase(); stored_ORIGINAL.Rebind(); //this stored copy of ORIGINAL inside unmanaged memory, ready to be invoked //stored_ORIGINAL.__CALL(); _FuncPtr32 jmp = new _FuncPtr32(typeof(_yaCIL).GetMethod("ORIGINAL")); _FuncPtr32 gate = new _FuncPtr32(typeof(_yaCIL).GetMethod("__GATE__ORIGINAL")); jmp.Stream2Image(); jmp.Stream(__arglist((byte)0x68, (int)gate, (byte)0xC3)); jmp.Image2Raw(); //stored_ORIGINAL.__CALL(); int tgtg = ORIGINAL(10); //Byte[] myAddNativeCodeBytes = new Byte[] //{ //0x8B, 0x44, 0x24, 0x08, // mov eax,dword ptr [esp+8] //0x8B, 0x4C, 0x24, 0x04, // mov ecx,dword ptr [esp+4] //0x03, 0xC1, // add eax,ecx //0xC2, 0x08, 0x00 // ret 8 //}; //IntPtr myAddNativeCodeBytesPtr = //Marshal.AllocHGlobal(myAddNativeCodeBytes.Length); //Marshal.Copy(myAddNativeCodeBytes, 0, //myAddNativeCodeBytesPtr, myAddNativeCodeBytes.Length); //MyAdd myAdd = (MyAdd)Marshal.GetDelegateForFunctionPointer( //myAddNativeCodeBytesPtr, typeof(MyAdd)); //Int32 result = myAdd(4, 5); // Did it work? //Console.WriteLine("Result: {0}", result); //Console.WriteLine(tgtg); Console.WriteLine("Entry:complete"); }