Пример #1
0
        /// <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();
            }
        }
Пример #2
0
        /// <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);
        }
Пример #3
0
        /// <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);
                }
            }
        }
Пример #4
0
        /// <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();
            }
        }
Пример #5
0
        /// <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();
            }
        }
Пример #6
0
 /// <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);
Пример #7
0
 internal static extern bool Iterate(NativeDisassemblerHandle hDisassembler, ref IntPtr pCode, ref IntPtr codeSize, ref long address, NativeInstructionHandle hInstruction);
Пример #8
0
 internal static extern NativeCapstoneResultCode GetAccessedRegisters(NativeDisassemblerHandle hDisassembler, NativeInstructionHandle hInstruction, short[] readRegisters, ref byte readRegistersCount, short[] writtenRegisters, ref byte writtenRegistersCount);
Пример #9
0
        /// <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();
                }
            }
        }
Пример #10
0
        /// <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);
        }
Пример #11
0
        /// <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);
                    }
                }
            }
        }