void EncodeDeclareByte(string hexBytes) { const int bitness = 64; const ulong newRip = 0x8000000000000000; var data = HexUtils.ToByteArray(hexBytes); var instructions = new Instruction[] { Instruction.Create(Code.Nopd), Instruction.CreateDeclareByte(data), Instruction.Create(Code.Nopd), }; var expectedData = new byte[data.Length + 2]; expectedData[0] = 0x90; Array.Copy(data, 0, expectedData, 1, data.Length); expectedData[expectedData.Length - 1] = 0x90; var codeWriter = new CodeWriterImpl(); bool b = BlockEncoder.TryEncode(bitness, new InstructionBlock(codeWriter, instructions, newRip), out var errorMessage, out var result); Assert.True(b); Assert.Null(errorMessage); Assert.Equal(expectedData, codeWriter.ToArray()); Assert.Equal(newRip, result.RIP); Assert.Null(result.RelocInfos); Assert.NotNull(result.NewInstructionOffsets); Assert.True(result.NewInstructionOffsets.Length == 0); Assert.NotNull(result.ConstantOffsets); Assert.True(result.ConstantOffsets.Length == 0); }
void DefaultArgs() { const int bitness = 64; const ulong origRip = 0x123456789ABCDE00; const ulong newRip = 0x8000000000000000; var originalData = new byte[] { /*0000*/ 0xB0, 0x00, // mov al,0 /*0002*/ 0xEB, 0x09, // jmp short 123456789ABCDE0Dh /*0004*/ 0xB0, 0x01, // mov al,1 /*0006*/ 0xE9, 0x03, 0x00, 0x00, 0x00, // jmp near ptr 123456789ABCDE0Eh /*000B*/ 0xB0, 0x02, // mov al,2 }; var instructions = BlockEncoderTest.Decode(bitness, origRip, originalData, DecoderOptions.None); var codeWriter = new CodeWriterImpl(); bool b = BlockEncoder.TryEncode(bitness, new InstructionBlock(codeWriter, instructions, newRip), out var errorMessage, out var result); Assert.True(b); Assert.Null(errorMessage); Assert.Equal(newRip, result.RIP); Assert.Equal(0x28, codeWriter.ToArray().Length); Assert.Null(result.RelocInfos); Assert.NotNull(result.NewInstructionOffsets); Assert.True(result.NewInstructionOffsets.Length == 0); Assert.NotNull(result.ConstantOffsets); Assert.True(result.ConstantOffsets.Length == 0); }
void Encode_zero_blocks() { bool b; string errorMessage; BlockEncoderResult[] result; b = BlockEncoder.TryEncode(16, new InstructionBlock[0], out errorMessage, out result, BlockEncoderOptions.None); Assert.True(b); Assert.Null(errorMessage); Assert.NotNull(result); Assert.True(result.Length == 0); b = BlockEncoder.TryEncode(32, new InstructionBlock[0], out errorMessage, out result, BlockEncoderOptions.None); Assert.True(b); Assert.Null(errorMessage); Assert.NotNull(result); Assert.True(result.Length == 0); b = BlockEncoder.TryEncode(64, new InstructionBlock[0], out errorMessage, out result, BlockEncoderOptions.None); Assert.True(b); Assert.Null(errorMessage); Assert.NotNull(result); Assert.True(result.Length == 0); }
public static IntPtr RunRemoteCode(IntPtr hProc, IReadOnlyList <Instruction> instructions, bool x86) { var cw = new CodeWriterImpl(); var ib = new InstructionBlock(cw, new List <Instruction>(instructions), 0); if (!BlockEncoder.TryEncode(x86 ? 32 : 64, ib, out string?errMsg, out _)) { throw new Exception("Error during Iced encode: " + errMsg); } byte[] bytes = cw.ToArray(); var ptrStub = Native.VirtualAllocEx(hProc, IntPtr.Zero, (uint)bytes.Length, 0x1000, 0x40); Native.WriteProcessMemory(hProc, ptrStub, bytes, (uint)bytes.Length, out _); Console.WriteLine("Written to 0x" + ptrStub.ToInt64().ToString("X8")); #if DEBUG Console.WriteLine("Press ENTER to start remote thread (you have the chance to place a breakpoint now)"); Console.ReadLine(); #endif var thread = Native.CreateRemoteThread(hProc, IntPtr.Zero, 0u, ptrStub, IntPtr.Zero, 0u, IntPtr.Zero); // NOTE: could wait for thread to finish with WaitForSingleObject Debug.Assert(thread != IntPtr.Zero); return(thread); }
public bool TryPatchX64(out string errorMessage) { var function = functionProvider.GetFunction(IsDebuggerPresentConstants.DllName, IsDebuggerPresentConstants.FuncName); /* * Generate the following code: * * xor eax,eax * ret */ var instructions = new InstructionList(); instructions.Add(Instruction.Create(II.Code.Xor_r32_rm32, Register.EAX, Register.EAX)); instructions.Add(Instruction.Create(II.Code.Retnq)); var block = new InstructionBlock(new CodeWriterImpl(function), instructions, function.NewCodeAddress); if (!BlockEncoder.TryEncode(process.Bitness, block, out var encErrMsg)) { errorMessage = $"Failed to encode: {encErrMsg}"; return(false); } errorMessage = null; return(true); }
/// <summary> /// Encodes the original bytes for a new address fixing e.g. branches, calls, jumps for execution at a given address. /// </summary> /// <param name="newAddress">The new address to encode the original instructions for.</param> public byte[] EncodeForNewAddress(IntPtr newAddress) { var writer = new CodeWriterImpl(_bytes.Length * 2); var block = new InstructionBlock(writer, DecodePrologue(), (ulong)newAddress); BlockEncoder.TryEncode(_bitness, block, out _); return(writer.ToArray()); }
public Type CompileDelegateType<T>(IEnumerable<Instruction> instructions, string methodName, Attribute[] typeAttributes = null, Attribute[] methodAttributes = null) where T : IAsmDelegate { var block = new InstructionBlock(_writer, new InstructionList(instructions) { Instruction.Create(Code.Retnq) }, _writer.NextFunctionPointer); if (!BlockEncoder.TryEncode(IntPtr.Size * 8, block, out var errorMessage)) { throw new InvalidOperationException(errorMessage); } return _writer.CommitToAssembly<T>(methodName); }
void TryEncode_with_invalid_bitness_throws() { foreach (var bitness in BitnessUtils.GetInvalidBitnessValues()) { Assert.Throws <ArgumentOutOfRangeException>(() => BlockEncoder.TryEncode(bitness, new InstructionBlock(new CodeWriterImpl(), new Instruction[1], 0), out _, out _)); } foreach (var bitness in BitnessUtils.GetInvalidBitnessValues()) { Assert.Throws <ArgumentOutOfRangeException>(() => BlockEncoder.TryEncode(bitness, new[] { new InstructionBlock(new CodeWriterImpl(), new Instruction[1], 0) }, out _, out _)); } }
public T Compile<T>(IEnumerable<Instruction> instructions) where T : Delegate { var instructionList = new InstructionList(instructions) { Instruction.Create(Code.Retnq) }; var block = new InstructionBlock(_writer, instructionList, _writer.NextFunctionPointer); if (!BlockEncoder.TryEncode(IntPtr.Size * 8, block, out var errorMessage)) { throw new InvalidOperationException(errorMessage); } return _writer.CommitToPInvokeDelegate<T>(); }
void EncodeRipRelMemOp() { var instr = Instruction.Create(Code.Add_r32_rm32, Register.ECX, new MemoryOperand(Register.RIP, Register.None, 1, 0x1234_5678_9ABC_DEF1, 8, false, Register.None)); var codeWriter = new CodeWriterImpl(); bool b = BlockEncoder.TryEncode(64, new InstructionBlock(codeWriter, new[] { instr }, 0x1234_5678_ABCD_EF02), out var errorMessage, out _); Assert.True(b, $"Couldn't encode it: {errorMessage}"); var encoded = codeWriter.ToArray(); var expected = new byte[] { 0x03, 0x0D, 0xE9, 0xEF, 0xEE, 0xEE }; Assert.Equal(expected, encoded); }
/// <summary> /// Encodes the original bytes for a new address fixing e.g. branches, calls, jumps for execution at a given address. /// </summary> /// <param name="newAddress">The new address to encode the original instructions for.</param> public byte[] EncodeForNewAddress(nuint newAddress) { var writer = new CodeWriterImpl(_bytes.Length * 2); var block = new InstructionBlock(writer, DecodePrologue(), newAddress); if (!BlockEncoder.TryEncode(_bitness, block, out var error, out _)) { throw new Exception($"Reloaded Hooks: Internal Error in {nameof(Reloaded.Hooks.Internal)}/{nameof(IcedPatcher)}. " + $"Failed to re-encode code for new address. Process will probably die." + $"Error: {error}"); } return(writer.ToArray()); }
void Encode_zero_blocks() { bool b; string errorMessage; b = BlockEncoder.TryEncode(16, new InstructionBlock[0], out errorMessage, BlockEncoderOptions.None); Assert.True(b); Assert.Null(errorMessage); b = BlockEncoder.TryEncode(32, new InstructionBlock[0], out errorMessage, BlockEncoderOptions.None); Assert.True(b); Assert.Null(errorMessage); b = BlockEncoder.TryEncode(64, new InstructionBlock[0], out errorMessage, BlockEncoderOptions.None); Assert.True(b); Assert.Null(errorMessage); }
void Encode_zero_instructions() { bool b; string errorMessage; var codeWriter = new CodeWriterImpl(); b = BlockEncoder.TryEncode(16, new InstructionBlock(codeWriter, Array.Empty <Instruction>(), 0, Array.Empty <RelocInfo>(), Array.Empty <uint>(), Array.Empty <ConstantOffsets>()), out errorMessage, BlockEncoderOptions.None); Assert.True(b); Assert.Null(errorMessage); Assert.Empty(codeWriter.ToArray()); b = BlockEncoder.TryEncode(32, new InstructionBlock(codeWriter, Array.Empty <Instruction>(), 0, Array.Empty <RelocInfo>(), Array.Empty <uint>(), Array.Empty <ConstantOffsets>()), out errorMessage, BlockEncoderOptions.None); Assert.True(b); Assert.Null(errorMessage); Assert.Empty(codeWriter.ToArray()); b = BlockEncoder.TryEncode(64, new InstructionBlock(codeWriter, Array.Empty <Instruction>(), 0, Array.Empty <RelocInfo>(), Array.Empty <uint>(), Array.Empty <ConstantOffsets>()), out errorMessage, BlockEncoderOptions.None); Assert.True(b); Assert.Null(errorMessage); Assert.Empty(codeWriter.ToArray()); }
void Encode_zero_instructions() { bool b; string errorMessage; BlockEncoderResult result; var codeWriter = new CodeWriterImpl(); b = BlockEncoder.TryEncode(16, new InstructionBlock(codeWriter, Array.Empty <Instruction>(), 0), out errorMessage, out result, BlockEncoderOptions.None); Assert.True(b); Assert.Null(errorMessage); Assert.Empty(codeWriter.ToArray()); Assert.Equal(0UL, result.RIP); Assert.Null(result.RelocInfos); Assert.NotNull(result.NewInstructionOffsets); Assert.True(result.NewInstructionOffsets.Length == 0); Assert.NotNull(result.ConstantOffsets); Assert.True(result.ConstantOffsets.Length == 0); b = BlockEncoder.TryEncode(32, new InstructionBlock(codeWriter, Array.Empty <Instruction>(), 0), out errorMessage, out result, BlockEncoderOptions.None); Assert.True(b); Assert.Null(errorMessage); Assert.Empty(codeWriter.ToArray()); Assert.Equal(0UL, result.RIP); Assert.Null(result.RelocInfos); Assert.NotNull(result.NewInstructionOffsets); Assert.True(result.NewInstructionOffsets.Length == 0); Assert.NotNull(result.ConstantOffsets); Assert.True(result.ConstantOffsets.Length == 0); b = BlockEncoder.TryEncode(64, new InstructionBlock(codeWriter, Array.Empty <Instruction>(), 0), out errorMessage, out result, BlockEncoderOptions.None); Assert.True(b); Assert.Null(errorMessage); Assert.Empty(codeWriter.ToArray()); Assert.Equal(0UL, result.RIP); Assert.Null(result.RelocInfos); Assert.NotNull(result.NewInstructionOffsets); Assert.True(result.NewInstructionOffsets.Length == 0); Assert.NotNull(result.ConstantOffsets); Assert.True(result.ConstantOffsets.Length == 0); }
/// <summary> /// Patches the prologue of a function with iced and returns the new address of the prologue. /// </summary> /// <returns></returns> public IntPtr GetFunctionAddress() { if (_newPrologueAddress != IntPtr.Zero) { return(_newPrologueAddress); } var estimateLength = _bytes.Length * 2; // Super generous! Exact length not known till relocated, just ensuring the size is enough under any circumstance. var buffer = Utilities.FindOrCreateBufferInRange(estimateLength); return(buffer.ExecuteWithLock(() => { // Patch prologue var newBaseAddress = buffer.Properties.WritePointer; var writer = new CodeWriterImpl(estimateLength); var block = new InstructionBlock((CodeWriter)writer, DecodePrologue(), (ulong)newBaseAddress); BlockEncoder.TryEncode(_bitness, block, out _); var data = writer.ToArray(); _newPrologueAddress = buffer.Add(data, 1); return _newPrologueAddress; })); }
private static IntPtr AllocateStub(IntPtr hProc, string asmPath, string typeName, string methodName, string?args, IntPtr fnAddr, bool x86, bool isV4) { const string clrVersion2 = "v2.0.50727"; const string clrVersion4 = "v4.0.30319"; string clrVersion = isV4 ? clrVersion4 : clrVersion2; const string buildFlavor = "wks"; // WorkStation var clsidCLRRuntimeHost = new Guid(0x90F1A06E, 0x7712, 0x4762, 0x86, 0xB5, 0x7A, 0x5E, 0xBA, 0x6B, 0xDB, 0x02); var iidICLRRuntimeHost = new Guid(0x90F1A06C, 0x7712, 0x4762, 0x86, 0xB5, 0x7A, 0x5E, 0xBA, 0x6B, 0xDB, 0x02); IntPtr ppv = alloc(IntPtr.Size); IntPtr riid = allocBytes(iidICLRRuntimeHost.ToByteArray()); IntPtr rcslid = allocBytes(clsidCLRRuntimeHost.ToByteArray()); IntPtr pwszBuildFlavor = allocString(buildFlavor); IntPtr pwszVersion = allocString(clrVersion); IntPtr pReturnValue = alloc(4); IntPtr pwzArgument = allocString(args); IntPtr pwzMethodName = allocString(methodName); IntPtr pwzTypeName = allocString(typeName); IntPtr pwzAssemblyPath = allocString(asmPath); var instructions = new InstructionList(); if (x86) { // call CorBindtoRuntimeEx instructions.Add(Instruction.Create(Code.Pushd_imm32, ppv.ToInt32())); instructions.Add(Instruction.Create(Code.Pushd_imm32, riid.ToInt32())); instructions.Add(Instruction.Create(Code.Pushd_imm32, rcslid.ToInt32())); instructions.Add(Instruction.Create(Code.Pushd_imm8, 0)); // startupFlags instructions.Add(Instruction.Create(Code.Pushd_imm32, pwszBuildFlavor.ToInt32())); instructions.Add(Instruction.Create(Code.Pushd_imm32, pwszVersion.ToInt32())); instructions.Add(Instruction.Create(Code.Mov_r32_imm32, Register.EAX, fnAddr.ToInt32())); instructions.Add(Instruction.Create(Code.Call_rm32, Register.EAX)); // call ICLRRuntimeHost::Start instructions.Add(Instruction.Create(Code.Mov_r32_rm32, Register.EAX, new MemoryOperand(Register.None, ppv.ToInt32()))); instructions.Add(Instruction.Create(Code.Mov_r32_rm32, Register.ECX, new MemoryOperand(Register.EAX))); instructions.Add(Instruction.Create(Code.Mov_r32_rm32, Register.EDX, new MemoryOperand(Register.ECX, 0x0C))); instructions.Add(Instruction.Create(Code.Push_r32, Register.EAX)); instructions.Add(Instruction.Create(Code.Call_rm32, Register.EDX)); // call ICLRRuntimeHost::ExecuteInDefaultAppDomain instructions.Add(Instruction.Create(Code.Pushd_imm32, pReturnValue.ToInt32())); instructions.Add(Instruction.Create(Code.Pushd_imm32, pwzArgument.ToInt32())); instructions.Add(Instruction.Create(Code.Pushd_imm32, pwzMethodName.ToInt32())); instructions.Add(Instruction.Create(Code.Pushd_imm32, pwzTypeName.ToInt32())); instructions.Add(Instruction.Create(Code.Pushd_imm32, pwzAssemblyPath.ToInt32())); instructions.Add(Instruction.Create(Code.Mov_r32_rm32, Register.EAX, new MemoryOperand(Register.None, ppv.ToInt32()))); instructions.Add(Instruction.Create(Code.Mov_r32_rm32, Register.ECX, new MemoryOperand(Register.EAX))); instructions.Add(Instruction.Create(Code.Push_r32, Register.EAX)); instructions.Add(Instruction.Create(Code.Mov_r32_rm32, Register.EAX, new MemoryOperand(Register.ECX, 0x2C))); instructions.Add(Instruction.Create(Code.Call_rm32, Register.EAX)); instructions.Add(Instruction.Create(Code.Retnd)); } else { const int maxStackIndex = 3; const int stackSize = 0x20 + maxStackIndex * 8; // 0x20 bytes shadow space, because x64 MemoryOperand stackAccess(int i) => new MemoryOperand(Register.RSP, stackSize - (maxStackIndex - i) * 8); instructions.Add(Instruction.Create(Code.Sub_rm64_imm8, Register.RSP, stackSize)); // call CorBindtoRuntimeEx // calling convention: https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=vs-2019 instructions.Add(Instruction.Create(Code.Mov_r64_imm64, Register.RAX, ppv.ToInt64())); instructions.Add(Instruction.Create(Code.Mov_rm64_r64, stackAccess(1), Register.RAX)); instructions.Add(Instruction.Create(Code.Mov_r64_imm64, Register.RAX, riid.ToInt64())); instructions.Add(Instruction.Create(Code.Mov_rm64_r64, stackAccess(0), Register.RAX)); instructions.Add(Instruction.Create(Code.Mov_r64_imm64, Register.R9, rcslid.ToInt64())); instructions.Add(Instruction.Create(Code.Mov_r32_imm32, Register.R8D, 0)); // startupFlags instructions.Add(Instruction.Create(Code.Mov_r64_imm64, Register.RDX, pwszBuildFlavor.ToInt64())); instructions.Add(Instruction.Create(Code.Mov_r64_imm64, Register.RCX, pwszVersion.ToInt64())); instructions.Add(Instruction.Create(Code.Mov_r64_imm64, Register.RAX, fnAddr.ToInt64())); instructions.Add(Instruction.Create(Code.Call_rm64, Register.RAX)); // call pClrHost->Start(); instructions.Add(Instruction.Create(Code.Mov_r64_imm64, Register.RCX, ppv.ToInt64())); instructions.Add(Instruction.Create(Code.Mov_r64_rm64, Register.RCX, new MemoryOperand(Register.RCX))); instructions.Add(Instruction.Create(Code.Mov_r64_rm64, Register.RAX, new MemoryOperand(Register.RCX))); instructions.Add(Instruction.Create(Code.Mov_r64_rm64, Register.RDX, new MemoryOperand(Register.RAX, 0x18))); instructions.Add(Instruction.Create(Code.Call_rm64, Register.RDX)); // call pClrHost->ExecuteInDefaultAppDomain() instructions.Add(Instruction.Create(Code.Mov_r64_imm64, Register.RDX, pReturnValue.ToInt64())); instructions.Add(Instruction.Create(Code.Mov_rm64_r64, stackAccess(1), Register.RDX)); instructions.Add(Instruction.Create(Code.Mov_r64_imm64, Register.RDX, pwzArgument.ToInt64())); instructions.Add(Instruction.Create(Code.Mov_rm64_r64, stackAccess(0), Register.RDX)); instructions.Add(Instruction.Create(Code.Mov_r64_imm64, Register.R9, pwzMethodName.ToInt64())); instructions.Add(Instruction.Create(Code.Mov_r64_imm64, Register.R8, pwzTypeName.ToInt64())); instructions.Add(Instruction.Create(Code.Mov_r64_imm64, Register.RDX, pwzAssemblyPath.ToInt64())); instructions.Add(Instruction.Create(Code.Mov_r64_imm64, Register.RCX, ppv.ToInt64())); instructions.Add(Instruction.Create(Code.Mov_r64_rm64, Register.RCX, new MemoryOperand(Register.RCX))); instructions.Add(Instruction.Create(Code.Mov_r64_rm64, Register.RAX, new MemoryOperand(Register.RCX))); instructions.Add(Instruction.Create(Code.Mov_r64_rm64, Register.RAX, new MemoryOperand(Register.RAX, 0x58))); instructions.Add(Instruction.Create(Code.Call_rm64, Register.RAX)); instructions.Add(Instruction.Create(Code.Add_rm64_imm8, Register.RSP, stackSize)); instructions.Add(Instruction.Create(Code.Retnq)); } var cw = new CodeWriterImpl(); var ib = new InstructionBlock(cw, instructions, 0); bool success = BlockEncoder.TryEncode(x86 ? 32 : 64, ib, out string errMsg); if (!success) { throw new Exception("Error during Iced encode: " + errMsg); } byte[] bytes = cw.ToArray(); var ptrStub = alloc(bytes.Length, 0x40); // RWX writeBytes(ptrStub, bytes); return(ptrStub); IntPtr alloc(int size, int protection = 0x04) => Native.VirtualAllocEx(hProc, IntPtr.Zero, (uint)size, 0x1000, protection); void writeBytes(IntPtr address, byte[] b) => Native.WriteProcessMemory(hProc, address, b, (uint)b.Length, out _); void writeString(IntPtr address, string str) => writeBytes(address, new UnicodeEncoding().GetBytes(str)); IntPtr allocString(string?str) { if (str is null) { return(IntPtr.Zero); } IntPtr pString = alloc(str.Length * 2 + 2); writeString(pString, str); return(pString); } IntPtr allocBytes(byte[] buffer) { IntPtr pBuffer = alloc(buffer.Length); writeBytes(pBuffer, buffer); return(pBuffer); } }
void TryEncode_with_null_array_throws() => Assert.Throws <ArgumentNullException>(() => BlockEncoder.TryEncode(64, null, out _, out _));
void TryEncode_with_default_InstructionBlock_throws() { Assert.Throws <ArgumentException>(() => BlockEncoder.TryEncode(64, default(InstructionBlock), out _, out _)); Assert.Throws <ArgumentException>(() => BlockEncoder.TryEncode(64, new InstructionBlock[3], out _, out _)); }
void VerifyResultArrays(BlockEncoderOptions options) { const int bitness = 64; const ulong origRip1 = 0x123456789ABCDE00; const ulong origRip2 = 0x223456789ABCDE00; const ulong newRip1 = 0x8000000000000000; const ulong newRip2 = 0x9000000000000000; { var instructions1 = BlockEncoderTest.Decode(bitness, origRip1, new byte[] { 0xE9, 0x56, 0x78, 0xA5, 0x5A }, DecoderOptions.None); var codeWriter1 = new CodeWriterImpl(); bool b = BlockEncoder.TryEncode(bitness, new InstructionBlock(codeWriter1, instructions1, newRip1), out var errorMessage, out var result, options); Assert.True(b); Assert.Null(errorMessage); Assert.Equal(newRip1, result.RIP); if ((options & BlockEncoderOptions.ReturnRelocInfos) != 0) { Assert.NotNull(result.RelocInfos); Assert.True(result.RelocInfos.Count == 1); } else { Assert.Null(result.RelocInfos); } if ((options & BlockEncoderOptions.ReturnNewInstructionOffsets) != 0) { Assert.NotNull(result.NewInstructionOffsets); Assert.True(result.NewInstructionOffsets.Length == 1); } else { Assert.NotNull(result.NewInstructionOffsets); Assert.True(result.NewInstructionOffsets.Length == 0); } if ((options & BlockEncoderOptions.ReturnConstantOffsets) != 0) { Assert.NotNull(result.ConstantOffsets); Assert.True(result.ConstantOffsets.Length == 1); } else { Assert.NotNull(result.ConstantOffsets); Assert.True(result.ConstantOffsets.Length == 0); } } { var instructions1 = BlockEncoderTest.Decode(bitness, origRip1, new byte[] { 0xE9, 0x56, 0x78, 0xA5, 0x5A }, DecoderOptions.None); var instructions2 = BlockEncoderTest.Decode(bitness, origRip2, new byte[] { 0x90, 0xE9, 0x56, 0x78, 0xA5, 0x5A }, DecoderOptions.None); var codeWriter1 = new CodeWriterImpl(); var codeWriter2 = new CodeWriterImpl(); var block1 = new InstructionBlock(codeWriter1, instructions1, newRip1); var block2 = new InstructionBlock(codeWriter2, instructions2, newRip2); bool b = BlockEncoder.TryEncode(bitness, new[] { block1, block2 }, out var errorMessage, out var resultArray, options); Assert.True(b); Assert.Null(errorMessage); Assert.NotNull(resultArray); Assert.Equal(2, resultArray.Length); Assert.Equal(newRip1, resultArray[0].RIP); Assert.Equal(newRip2, resultArray[1].RIP); if ((options & BlockEncoderOptions.ReturnRelocInfos) != 0) { Assert.NotNull(resultArray[0].RelocInfos); Assert.NotNull(resultArray[1].RelocInfos); Assert.True(resultArray[0].RelocInfos.Count == 1); Assert.True(resultArray[1].RelocInfos.Count == 1); } else { Assert.Null(resultArray[0].RelocInfos); Assert.Null(resultArray[1].RelocInfos); } if ((options & BlockEncoderOptions.ReturnNewInstructionOffsets) != 0) { Assert.NotNull(resultArray[0].NewInstructionOffsets); Assert.NotNull(resultArray[1].NewInstructionOffsets); Assert.True(resultArray[0].NewInstructionOffsets.Length == 1); Assert.True(resultArray[1].NewInstructionOffsets.Length == 2); } else { Assert.NotNull(resultArray[0].NewInstructionOffsets); Assert.True(resultArray[0].NewInstructionOffsets.Length == 0); Assert.NotNull(resultArray[1].NewInstructionOffsets); Assert.True(resultArray[1].NewInstructionOffsets.Length == 0); } if ((options & BlockEncoderOptions.ReturnConstantOffsets) != 0) { Assert.NotNull(resultArray[0].ConstantOffsets); Assert.NotNull(resultArray[1].ConstantOffsets); Assert.True(resultArray[0].ConstantOffsets.Length == 1); Assert.True(resultArray[1].ConstantOffsets.Length == 2); } else { Assert.NotNull(resultArray[0].ConstantOffsets); Assert.True(resultArray[0].ConstantOffsets.Length == 0); Assert.NotNull(resultArray[1].ConstantOffsets); Assert.True(resultArray[1].ConstantOffsets.Length == 0); } } }
void Invalid_ConstantOffsets_Throws() { Assert.Throws <ArgumentException>(() => BlockEncoder.TryEncode(64, new InstructionBlock(new CodeWriterImpl(), new Instruction[0], 0, Array.Empty <RelocInfo>(), null, new ConstantOffsets[1]), out _, BlockEncoderOptions.None)); Assert.Throws <ArgumentException>(() => BlockEncoder.TryEncode(64, new InstructionBlock(new CodeWriterImpl(), new Instruction[1], 0, Array.Empty <RelocInfo>(), null, new ConstantOffsets[0]), out _, BlockEncoderOptions.None)); }