Skip to content

Instantly share code, notes, and snippets.

@Const-me
Last active March 19, 2016 16:42
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Const-me/c69cce18dd6bf1c81f89 to your computer and use it in GitHub Desktop.
Save Const-me/c69cce18dd6bf1c81f89 to your computer and use it in GitHub Desktop.
using Gee.External.Capstone;
using Gee.External.Capstone.X86;
using System;
using System.Collections.Generic;
using System.Linq;
namespace InstructionsCheck
{
/// <summary>This class implements a way to disassemble real-life modules with Capstone.</summary>
/// <remarks>Real-life x86 and amd64 code contains inline data.
/// And real-life data can't be disassembled, it causes Capstone to stop disassembling and fail.
/// This static class implements some heuristics to resume disassembly after that happens.</remarks>
static class DisasmEx
{
/// <summary>return a portion of the byte array.</summary>
static IEnumerable<byte> take( this byte[] arr, int offset, int c )
{
int end = Math.Min( arr.Length, offset + c );
for( int i = offset; i < end; i++ )
yield return arr[ i ];
}
/// <summary>True if the code from the offset is equal to the marker.</summary>
static bool isMarkerAt( this byte[] code, byte[] marker, int offset )
{
return code.take( offset, marker.Length ).SequenceEqual( marker );
}
/// <summary>Create byte array from hex string</summary>
public static byte[] parseBytes( string hex )
{
hex = hex.Trim();
// http://stackoverflow.com/a/321404/126995
return Enumerable.Range( 0, hex.Length )
.Where( x => x % 2 == 0 )
.Select( x => Convert.ToByte( hex.Substring( x, 2 ), 16 ) )
.ToArray();
}
/// <summary>Return possible x86 NOP commands, and also int3 command.</summary>
static IEnumerable<string> allNOPs()
{
yield return "CC"; // int 3: not nop, but we still skip it.
// http://stackoverflow.com/q/25545470/126995
yield return "90 ";
yield return "6690 ";
yield return "0f1f00 ";
yield return "0f1f4000 ";
// AMD
yield return "0f1f440000 ";
yield return "660f1f440000 ";
yield return "0f1f8000000000 ";
yield return "0f1f840000000000 ";
yield return "660f1f840000000000 ";
yield return "66660f1f840000000000 ";
yield return "6666660f1f840000000000 ";
// Intel
yield return "0f1f440000 ";
yield return "660f1f440000 ";
yield return "0f1f8000000000 ";
yield return "0f1f840000000000 ";
yield return "660f1f840000000000 ";
yield return "0f1f440000 ";
yield return "660f1f440000 ";
yield return "0f1f8000000000 ";
yield return "0f1f840000000000 ";
yield return "660f1f840000000000 ";
yield return "662e0f1f840000000000 ";
yield return "0f1f440000660f1f440000 ";
yield return "660f1f440000660f1f440000 ";
yield return "660f1f4400000f1f8000000000 ";
yield return "0f1f80000000000f1f8000000000 ";
yield return "0f1f80000000000f1f840000000000 ";
yield return "66662e0f1f840000000000 ";
yield return "6666662e0f1f840000000000 ";
yield return "666666662e0f1f840000000000 ";
yield return "66666666662e0f1f840000000000 ";
yield return "6666666666662e0f1f840000000000 ";
}
const int minStopLength = 5;
static IEnumerable<byte[]> createStopMarkers()
{
byte[] int3 = Enumerable.Repeat( (byte)0xCC, minStopLength ).ToArray();
return allNOPs()
.Distinct()
.Select( parseBytes )
.Where( n => n.Length >= minStopLength )
.Concat( Enumerable.Repeat( int3, 1 ) );
}
static IEnumerable<byte[]> createNOPs()
{
return allNOPs().Distinct()
.Select( parseBytes )
.OrderByDescending( an => an.Length );
}
static readonly byte[][] stopMarkers = createStopMarkers().ToArray();
static readonly byte[][] nops = createNOPs().ToArray();
static int skipNOPs( byte[] code, int offset )
{
while( true )
{
bool found = false;
foreach( byte[] nop in nops )
{
if( code.isMarkerAt( nop, offset ) )
{
offset += nop.Length;
found = true;
break;
}
}
if( !found )
return offset;
}
}
static int searchNextCode( DisassembleMode mode, byte[] code, int offset )
{
while( offset < code.Length )
{
foreach( byte[] marker in stopMarkers )
{
if( code.isMarkerAt( marker, offset ) )
{
offset += marker.Length;
return skipNOPs( code, offset );
}
}
offset++;
}
return -1;
}
/// <summary>Same as CapstoneDisassembler.DisassembleStream but resumes after invalid instructions.</summary>
public static IEnumerable<Instruction<X86Instruction, X86Register, X86InstructionGroup, X86InstructionDetail>>
disassembleStreamEx( this CapstoneDisassembler<X86Instruction, X86Register, X86InstructionGroup, X86InstructionDetail> disassembler,
byte[] code, int offset, long startingAddress )
{
while( true )
{
foreach( var i in disassembler.DisassembleStream( code, offset, startingAddress ) )
{
yield return i;
offset += i.Bytes.Length;
}
int o1 = offset;
offset = searchNextCode( disassembler.Mode, code, offset );
if( offset < 0 )
yield break;
if( offset < o1 )
throw new ApplicationException();
Console.WriteLine( "; Skipped addresses {0:X}-{1:X}", startingAddress + o1, startingAddress + offset );
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment