/// <summary> /// Get an Instruction's Details. /// </summary> /// <param name="hInstruction"> /// An instruction handle. /// </param> /// <returns> /// The instruction's details. A null reference indicates the instruction was disassembled without /// details. /// </returns> internal static NativeInstructionDetail?GetInstructionDetail(NativeInstructionHandle hInstruction) { var pInstruction = hInstruction.DangerousAddRefAndGetHandle(); try { // ... // // First, we calculate the memory address of the <c>NativeInstruction.Details</c> field, which is // always relative to the memory address of its defining <c>NativeInstruction</c> structure. This is // NOT the actual memory address of the instruction's details. var instructionDetailOffset = Marshal.OffsetOf(typeof(NativeInstruction), nameof(NativeInstruction.Details)); var pInstructionDetail = (IntPtr)((long)pInstruction + (long)instructionDetailOffset); // ... // // Second, we read the value of the <c>NativeInstruction.Details</c> field, which IS the actual memory // address of the instruction's details. If the value is not equal to <c>IntPtr.Zero</c>, that indicates // the instruction was disassembled with details. var ppInstructionDetail = Marshal.ReadIntPtr(pInstructionDetail); NativeInstructionDetail?instructionDetail = null; if (ppInstructionDetail != IntPtr.Zero) { instructionDetail = MarshalExtension.PtrToStructure <NativeInstructionDetail>(ppInstructionDetail); } return(instructionDetail); } finally { hInstruction.DangerousRelease(); } }
/// <summary> /// Create an Instruction.. /// </summary> /// <param name="hDisassembler"> /// A disassembler handle. /// </param> /// <returns> /// An instruction handle. /// </returns> /// <exception cref="System.ObjectDisposedException"> /// Thrown if the disassembler handle is disposed. /// </exception> internal static NativeInstructionHandle CreateInstruction(NativeDisassemblerHandle hDisassembler) { // ... // // Throws an exception if the operation fails. var pInstruction = NativeCapstoneImport.CreateInstruction(hDisassembler); var hInstruction = new NativeInstructionHandle(pInstruction); return(hInstruction); }
/// <summary> /// Build an Instruction. /// </summary> /// <param name="disassembler"> /// A disassembler. /// </param> /// <param name="hInstruction"> /// An instruction handle. /// </param> internal virtual void Build(CapstoneDisassembler disassembler, NativeInstructionHandle hInstruction) { // ... // // Throws an exception if the operation fails. var nativeInstruction = NativeCapstone.GetInstruction(hInstruction); this.Address = nativeInstruction.Address; this.DisassembleArchitecture = disassembler.DisassembleArchitecture; this.DisassembleMode = this.CreateDisassembleMode(disassembler.NativeDisassembleMode); this.Id = this.CreateId(nativeInstruction.Id); this.IsSkippedData = disassembler.EnableSkipDataMode && !(nativeInstruction.Id > 0); this.Mnemonic = !CapstoneDisassembler.IsDietModeEnabled ? nativeInstruction.Mnemonic : null; this.Operand = !CapstoneDisassembler.IsDietModeEnabled ? nativeInstruction.Operand : null; // ... // // ... SetBytes(this, ref nativeInstruction); SetDetails(this, disassembler, hInstruction, ref nativeInstruction); // <summary> // Set Instruction's Machine Bytes. // </summary> void SetBytes(InstructionBuilder <TDetail, TDisassembleMode, TGroup, TGroupId, TInstruction, TId, TRegister, TRegisterId> @this, ref NativeInstruction cNativeInstruction) { @this.Bytes = new byte[0]; if (cNativeInstruction.Id >= 0) { @this.Bytes = new byte[cNativeInstruction.Size]; for (var cI = 0; cI < @this.Bytes.Length; cI++) { @this.Bytes[cI] = cNativeInstruction.Bytes[cI]; } } } // <summary> // Set Instruction's Details. // </summary> void SetDetails(InstructionBuilder <TDetail, TDisassembleMode, TGroup, TGroupId, TInstruction, TId, TRegister, TRegisterId> @this, CapstoneDisassembler cDisassembler, NativeInstructionHandle cHInstruction, ref NativeInstruction cNativeInstruction) { var cHasDetails = cNativeInstruction.Details != IntPtr.Zero; var cIsInstructionDetailsEnabled = cDisassembler.EnableInstructionDetails; @this.Details = null; if (cHasDetails && cIsInstructionDetailsEnabled && cNativeInstruction.Id > 0) { @this.Details = @this.CreateDetails(cDisassembler, cHInstruction); } } }
/// <summary> /// Get an Instruction. /// </summary> /// <param name="hInstruction"> /// An instruction handle. /// </param> /// <returns> /// An instruction. /// </returns> internal static NativeInstruction GetInstruction(NativeInstructionHandle hInstruction) { var pInstruction = hInstruction.DangerousAddRefAndGetHandle(); try { // ... // // Throws an exception if the operation fails. var instruction = MarshalExtension.PtrToStructure <NativeInstruction>(pInstruction); return(instruction); } finally { hInstruction.DangerousRelease(); } }
/// <summary> /// Get an Instruction's Details. /// </summary> /// <typeparam name="TInstructionDetail"> /// The type of the instruction's details. /// </typeparam> /// <param name="hInstruction"> /// An instruction handle. /// </param> /// <returns> /// The instruction's details. A null reference indicates the instruction was disassembled without /// details. /// </returns> internal static TInstructionDetail?GetInstructionDetail <TInstructionDetail>(NativeInstructionHandle hInstruction) where TInstructionDetail : struct { var pInstruction = hInstruction.DangerousAddRefAndGetHandle(); try { // ... // // First, we calculate the memory address of the <c>NativeInstruction.Details</c> field, which is // always relative to the memory address of its defining <c>NativeInstruction</c> structure. This is // NOT the actual memory address of the instruction's details. var instructionDetailOffset = Marshal.OffsetOf(typeof(NativeInstruction), nameof(NativeInstruction.Details)); var pInstructionDetail = (IntPtr)((long)pInstruction + (long)instructionDetailOffset); // ... // // Second, we read the value of the <c>NativeInstruction.Details</c> field, which IS the actual memory // address of the instruction's details. If the value is not equal to <c>IntPtr.Zero</c>, that indicates // the instruction was disassembled with details. var ppInstructionDetail = Marshal.ReadIntPtr(pInstructionDetail); TInstructionDetail?instructionDetail = null; if (ppInstructionDetail != IntPtr.Zero) { // ... // // Fourth, we calculate the memory address of the instruction's architecture specific details, // which is always relative to the memory address of the instruction's details. var pArchInstructionDetail = ppInstructionDetail + NativeCapstone.MagicInstructionArchitectureDetailsFieldOffset; instructionDetail = (TInstructionDetail)Marshal.PtrToStructure(pArchInstructionDetail, typeof(TInstructionDetail)); } return(instructionDetail); } finally { hInstruction.DangerousRelease(); } }
/// <summary> /// Create Instruction's Details. /// </summary> /// <param name="disassembler"> /// A disassembler. /// </param> /// <param name="hInstruction"> /// An instruction handle. /// </param> /// <returns> /// The instruction's details. /// </returns> private protected abstract TDetail CreateDetails(CapstoneDisassembler disassembler, NativeInstructionHandle hInstruction);
internal static extern bool Iterate(NativeDisassemblerHandle hDisassembler, ref IntPtr pCode, ref IntPtr codeSize, ref long address, NativeInstructionHandle hInstruction);
internal static extern NativeCapstoneResultCode GetAccessedRegisters(NativeDisassemblerHandle hDisassembler, NativeInstructionHandle hInstruction, short[] readRegisters, ref byte readRegistersCount, short[] writtenRegisters, ref byte writtenRegistersCount);
/// <summary> /// Disassemble Binary Code Iteratively. /// </summary> /// <param name="hDisassembler"> /// A disassembler handle. /// </param> /// <param name="binaryCode"> /// A buffer indicating the binary code to disassemble. /// </param> /// <param name="binaryCodeOffset"> /// The index of the instruction to disassemble in the binary code buffer . If the instruction is /// disassembled successfully, this value will be updated to reflect the index of the next instruction to /// disassemble in the binary code buffer. If the updated value is less than the length of the binary code /// buffer, you can safely invoke this method with the updated value to disassemble the next instruction. /// </param> /// <param name="address"> /// The address of the instruction. If the instruction is disassembled successfully, this value will be /// updated to reflect the address of the next instruction to disassemble in the binary code buffer. /// </param> /// <param name="hInstruction"> /// An instruction handle. /// </param> /// <returns> /// A boolean true if an instruction was disassembled successfully. A boolean false otherwise. /// </returns> /// <exception cref="System.ObjectDisposedException"> /// Thrown if the disassembler handle is disposed, or if the instruction handle is disposed. /// </exception> internal static bool Iterate(NativeDisassemblerHandle hDisassembler, byte[] binaryCode, ref int binaryCodeOffset, ref long address, NativeInstructionHandle hInstruction) { var hBinaryCode = GCHandle.Alloc(binaryCode, GCHandleType.Pinned); try { // ... // // First, we increment the pointer to the binary code buffer to the point to the address of the // instruction we want to disassemble. var pBinaryCode = hBinaryCode.AddrOfPinnedObject() + binaryCodeOffset; // ... // // Second, we calculate the size of the binary code buffer by decrementing the offset we incremented // by in the previous step. var binaryCodeSize = (IntPtr)binaryCode.Length - binaryCodeOffset; // ... // // Third, we save the address of the binary code buffer we will disassemble, so that we can later // compute a new offset, and disassemble the binary code. If an instruction was disassembled // successfully, the pointer to the binary code, the binary code size, and the starting address will // be updated by the Capstone API to reflect the address of the next instruction to disassemble in the // binary code buffer. // // Throws an exception if the operation fails. var initialPBinaryCode = pBinaryCode; var isDisassembled = NativeCapstoneImport.Iterate(hDisassembler, ref pBinaryCode, ref binaryCodeSize, ref address, hInstruction); if (isDisassembled) { // ... // // Fourth, we compute a new offset to indicate to the caller the next instruction to disassemble // in the binary code buffer. binaryCodeOffset += (int)((long)pBinaryCode - (long)initialPBinaryCode); } return(isDisassembled); } finally { if (hBinaryCode.IsAllocated) { hBinaryCode.Free(); } } }
/// <summary> /// Get an Instruction's Accessed Registers. /// </summary> /// <param name="hDisassembler"> /// A disassembler handle. /// </param> /// <param name="hInstruction"> /// An instruction handle. /// </param> /// <returns> /// A 2-tuple, where the first item is an array of the instruction's read registers and the second item is /// an array of the instruction's written registers. /// </returns> /// <exception cref="Capstone.Net.CapstoneException"> /// Thrown if the instruction's accessed registers could not be retrieved. /// </exception> /// <exception cref="System.ArgumentException"> /// Thrown if the disassembler handle is invalid. /// </exception> /// <exception cref="System.InvalidOperationException"> /// Thrown if the instruction was disassembled when Instruction Details Mode was disabled, or if the /// instruction was disassembled when Skip Data Mode was enabled. /// </exception> /// <exception cref="System.NotSupportedException"> /// Thrown if Diet Mode is enabled, or if the disassembler's hardware architecture does not support the /// operation. /// </exception> /// <exception cref="System.ObjectDisposedException"> /// Thrown if the disassembler handle is disposed, or if the instruction handle is disposed. /// </exception> internal static Tuple <short[], short[]> GetAccessedRegisters(NativeDisassemblerHandle hDisassembler, NativeInstructionHandle hInstruction) { // ... // // Throws an exception if the operation fails. var readRegisters = new short[64]; byte readRegistersCount = 0; var writtenRegisters = new short[64]; byte writtenRegistersCount = 0; var resultCode = NativeCapstoneImport.GetAccessedRegisters(hDisassembler, hInstruction, readRegisters, ref readRegistersCount, writtenRegisters, ref writtenRegistersCount); if (resultCode != NativeCapstoneResultCode.Ok) { if ((int)resultCode == -1) { // ... // // For some reason, the Capstone API will return a <c>-1</c>, instead of a defined error code, if // the disassembler handle is invalid. var detailMessage = $"A disassembler handle ({nameof(hDisassembler)}) is invalid."; throw new ArgumentException(detailMessage, nameof(hDisassembler)); } else if (resultCode == NativeCapstoneResultCode.UnsupportedDisassembleArchitecture) { const string detailMessage = "A disassembler's hardware architecture is not supported."; throw new NotSupportedException(detailMessage); } else if (resultCode == NativeCapstoneResultCode.UnSupportedDietModeOperation) { const string detailMessage = "An operation is not supported when diet mode is enabled."; throw new NotSupportedException(detailMessage); } else if (resultCode == NativeCapstoneResultCode.UnsupportedInstructionDetail) { const string detailMessage = "An operation is not supported when instruction details are disabled."; throw new InvalidOperationException(detailMessage); } else if (resultCode == NativeCapstoneResultCode.UnsupportedSkipDataModeOperation) { const string detailMessage = "An operation is not supported when skip-data mode is enabled."; throw new InvalidOperationException(detailMessage); } else { const string detailMessage = "An instruction's accessed registers could not be retrieved."; throw new CapstoneException(detailMessage); } } var newReadRegisters = new short[readRegistersCount]; var newWrittenRegisters = new short[writtenRegistersCount]; Array.Copy(readRegisters, newReadRegisters, newReadRegisters.Length); Array.Copy(writtenRegisters, newWrittenRegisters, newWrittenRegisters.Length); var tuple = Tuple.Create(newReadRegisters, newWrittenRegisters); return(tuple); }
/// <summary> /// Build an Instruction Detail. /// </summary> /// <param name="disassembler"> /// A disassembler. /// </param> /// <param name="hInstruction"> /// An instruction handle. /// </param> internal virtual void Build(CapstoneDisassembler disassembler, NativeInstructionHandle hInstruction) { // ... // // Throws an exception if the operation fails. var nativeInstructionDetail = NativeCapstone.GetInstructionDetail(hInstruction).GetValueOrDefault(); this.DisassembleArchitecture = disassembler.DisassembleArchitecture; this.DisassembleMode = this.CreateDisassembleMode(disassembler.NativeDisassembleMode); // ... // // ... SetAccessedRegisters(this, disassembler, hInstruction); SetGroups(this, disassembler, ref nativeInstructionDetail); SetImplicitlyReadRegisters(this, disassembler, ref nativeInstructionDetail); SetImplicitlyWrittenRegisters(this, disassembler, ref nativeInstructionDetail); // <summary> // Set Accessed Registers. // </summary> void SetAccessedRegisters(InstructionDetailBuilder <TDetail, TDisassembleMode, TGroup, TGroupId, TInstruction, TInstructionId, TRegister, TRegisterId> @this, CapstoneDisassembler cDisassembler, NativeInstructionHandle cHInstruction) { @this.AllReadRegisters = new TRegister[0]; @this.AllWrittenRegisters = new TRegister[0]; if (!CapstoneDisassembler.IsDietModeEnabled) { var isArchSupported = cDisassembler.DisassembleArchitecture != DisassembleArchitecture.M68K; isArchSupported = isArchSupported && cDisassembler.DisassembleArchitecture != DisassembleArchitecture.Mips; isArchSupported = isArchSupported && cDisassembler.DisassembleArchitecture != DisassembleArchitecture.PowerPc; isArchSupported = isArchSupported && cDisassembler.DisassembleArchitecture != DisassembleArchitecture.XCore; if (isArchSupported) { // ... // // Throws an exception if the operation fails. var cAccessedRegisters = NativeCapstone.GetAccessedRegisters(cDisassembler.Handle, cHInstruction); @this.AllReadRegisters = new TRegister[cAccessedRegisters.Item1.Length]; for (var cI = 0; cI < @this.AllReadRegisters.Length; cI++) { var cExplicitlyReadRegister = cAccessedRegisters.Item1[cI]; @this.AllReadRegisters[cI] = @this.CreateRegister(cDisassembler, cExplicitlyReadRegister); } @this.AllWrittenRegisters = new TRegister[cAccessedRegisters.Item2.Length]; for (var cI = 0; cI < @this.AllWrittenRegisters.Length; cI++) { var cExplicitlyWrittenRegister = cAccessedRegisters.Item2[cI]; @this.AllWrittenRegisters[cI] = @this.CreateRegister(cDisassembler, cExplicitlyWrittenRegister); } } } } // <summary> // Set Instruction's Groups. // </summary> void SetGroups(InstructionDetailBuilder <TDetail, TDisassembleMode, TGroup, TGroupId, TInstruction, TInstructionId, TRegister, TRegisterId> @this, CapstoneDisassembler cDisassembler, ref NativeInstructionDetail cNativeInstructionDetail) { @this.Groups = new TGroup[cNativeInstructionDetail.GroupCount]; if (!CapstoneDisassembler.IsDietModeEnabled) { for (var cI = 0; cI < @this.Groups.Length; cI++) { var cGroup = cNativeInstructionDetail.Groups[cI]; @this.Groups[cI] = @this.CreateInstructionGroup(cDisassembler, cGroup); } } } // <summary> // Set Implicitly Read Registers. // </summary> void SetImplicitlyReadRegisters(InstructionDetailBuilder <TDetail, TDisassembleMode, TGroup, TGroupId, TInstruction, TInstructionId, TRegister, TRegisterId> @this, CapstoneDisassembler cDisassembler, ref NativeInstructionDetail cNativeInstructionDetail) { @this.ImplicitlyReadRegisters = new TRegister[cNativeInstructionDetail.ImplicitlyReadRegisterCount]; if (!CapstoneDisassembler.IsDietModeEnabled) { for (var cI = 0; cI < @this.ImplicitlyReadRegisters.Length; cI++) { var cImplicitlyReadRegister = cNativeInstructionDetail.ImplicitlyReadRegisters[cI]; @this.ImplicitlyReadRegisters[cI] = @this.CreateRegister(cDisassembler, cImplicitlyReadRegister); } } } // <summary> // Set Implicitly Written Registers. // </summary> void SetImplicitlyWrittenRegisters(InstructionDetailBuilder <TDetail, TDisassembleMode, TGroup, TGroupId, TInstruction, TInstructionId, TRegister, TRegisterId> @this, CapstoneDisassembler cDisassembler, ref NativeInstructionDetail cNativeInstructionDetail) { @this.ImplicitlyWrittenRegisters = new TRegister[cNativeInstructionDetail.ImplicitlyWrittenRegisterCount]; if (!CapstoneDisassembler.IsDietModeEnabled) { for (var cI = 0; cI < @this.ImplicitlyWrittenRegisters.Length; cI++) { var cImplicitlyWrittenRegister = cNativeInstructionDetail.ImplicitlyWrittenRegisters[cI]; @this.ImplicitlyWrittenRegisters[cI] = @this.CreateRegister(cDisassembler, cImplicitlyWrittenRegister); } } } }