static void writeOriginalCode(NativeCodeGenerator code, byte[] origCode, IntPtr origAddr) { for (int i = 0; i < origCode.Length; i++) { byte b = origCode[i]; if (b != 0xE8 || i + 5 >= origCode.Length) { code.writeByte(b); continue; } IntPtr dest = new IntPtr(origAddr.ToInt64() + i + 5 + BitConverter.ToInt32(origCode, i + 1)); code.writeCall(dest); i += 4; } }
unsafe byte[] createOurCode(IntPtr compileMethod) { var code = new NativeCodeGenerator(); var origCode = new byte[0x60]; Marshal.Copy(compileMethod, origCode, 0, origCode.Length); // our compileMethod() func int compileMethodOffset = code.Size; code.writeByte(0xE9); code.writeDword((uint)origCode.Length); writeOriginalCode(code, origCode, compileMethod); int numPushedArgs = compileMethodIsThisCall ? 5 : 6; code.writeByte(0x51); // push ecx code.writeByte(0x50); // push eax code.writeByte(0x54); // push esp for (int i = 0; i < 5; i++) { writePushDwordPtrEspDispl(code, (sbyte)(0xC + numPushedArgs * 4)); // push dword ptr [esp+XXh] } if (!compileMethodIsThisCall) { writePushDwordPtrEspDispl(code, (sbyte)(0xC + numPushedArgs * 4)); // push dword ptr [esp+XXh] } else { code.writeByte(0x51); // push ecx } code.writeCall(ourCompileMethodInfo.ptr); code.writeByte(0x5A); // pop edx code.writeByte(0x59); // pop ecx code.writeBytes(0x84, 0xD2); // test dl, dl code.writeBytes(0x74, 0x03); // jz $+5 code.writeBytes(0xC2, (ushort)(numPushedArgs * 4)); // retn 14h/18h for (int i = 0; i < numPushedArgs; i++) { writePushDwordPtrEspDispl(code, (sbyte)(numPushedArgs * 4)); // push dword ptr [esp+XXh] } code.writeCall(origCompileMethod); code.writeBytes(0xC2, (ushort)(numPushedArgs * 4)); // retn 14h/18h // Our callMethod() code. 1st arg is the method to call. stdcall calling convention. int callMethodOffset = code.Size; code.writeByte(0x58); // pop eax (ret addr) code.writeByte(0x5A); // pop edx (method to call) if (compileMethodIsThisCall) { code.writeByte(0x59); // pop ecx (this ptr) } code.writeByte(0x50); // push eax (ret addr) code.writeBytes(0xFF, 0xE2); // jmp edx // Returns token of method int getMethodTokenOffset = code.Size; code.writeCall(returnMethodTokenInfo.ptr); code.writeBytes(0xC2, (ushort)(IntPtr.Size * 2)); // Returns name of method int getMethodNameOffset = code.Size; code.writeCall(returnNameOfMethodInfo.ptr); code.writeBytes(0xC2, (ushort)(IntPtr.Size * 3)); IntPtr baseAddr = new IntPtr((byte *)jitterTextFreeMem - code.Size); ourCompileMethodInfo.ptrInDll = new IntPtr((byte *)baseAddr + compileMethodOffset); callMethod = new IntPtr((byte *)baseAddr + callMethodOffset); returnMethodTokenInfo.ptrInDll = new IntPtr((byte *)baseAddr + getMethodTokenOffset); returnNameOfMethodInfo.ptrInDll = new IntPtr((byte *)baseAddr + getMethodNameOffset); return(code.getCode(baseAddr)); }
unsafe void createOurCode() { var code = new NativeCodeGenerator(); // our compileMethod() func int compileMethodOffset = code.Size; int numPushedArgs = compileMethodIsThisCall ? 5 : 6; code.writeByte(0x51); // push ecx code.writeByte(0x50); // push eax code.writeByte(0x54); // push esp for (int i = 0; i < 5; i++) { writePushDwordPtrEspDispl(code, (sbyte)(0xC + numPushedArgs * 4)); // push dword ptr [esp+XXh] } if (!compileMethodIsThisCall) { writePushDwordPtrEspDispl(code, (sbyte)(0xC + numPushedArgs * 4)); // push dword ptr [esp+XXh] } else { code.writeByte(0x51); // push ecx } code.writeCall(ourCompileMethodInfo.ptr); code.writeByte(0x5A); // pop edx code.writeByte(0x59); // pop ecx code.writeBytes(0x84, 0xD2); // test dl, dl code.writeBytes(0x74, 0x03); // jz $+5 code.writeBytes(0xC2, (ushort)(numPushedArgs * 4)); // retn 14h/18h for (int i = 0; i < numPushedArgs; i++) { writePushDwordPtrEspDispl(code, (sbyte)(numPushedArgs * 4)); // push dword ptr [esp+XXh] } code.writeCall(origCompileMethod); code.writeBytes(0xC2, (ushort)(numPushedArgs * 4)); // retn 14h/18h // Our callMethod() code. 1st arg is the method to call. stdcall calling convention. int callMethodOffset = code.Size; code.writeByte(0x58); // pop eax (ret addr) code.writeByte(0x5A); // pop edx (method to call) if (compileMethodIsThisCall) { code.writeByte(0x59); // pop ecx (this ptr) } code.writeByte(0x50); // push eax (ret addr) code.writeBytes(0xFF, 0xE2); // jmp edx // Returns token of method int getMethodTokenOffset = code.Size; code.writeCall(returnMethodTokenInfo.ptr); code.writeBytes(0xC2, (ushort)(IntPtr.Size * 2)); // Returns name of method int getMethodNameOffset = code.Size; code.writeCall(returnNameOfMethodInfo.ptr); code.writeBytes(0xC2, (ushort)(IntPtr.Size * 3)); ourCodeAddr = VirtualAlloc(IntPtr.Zero, new UIntPtr((ulong)code.Size), 0x00001000, PAGE_EXECUTE_READWRITE); IntPtr baseAddr = ourCodeAddr; ourCompileMethodInfo.ptrInDll = new IntPtr((byte *)baseAddr + compileMethodOffset); callMethod = new IntPtr((byte *)baseAddr + callMethodOffset); returnMethodTokenInfo.ptrInDll = new IntPtr((byte *)baseAddr + getMethodTokenOffset); returnNameOfMethodInfo.ptrInDll = new IntPtr((byte *)baseAddr + getMethodNameOffset); byte[] theCode = code.getCode(baseAddr); Marshal.Copy(theCode, 0, baseAddr, theCode.Length); }