0

I am successfully parcing '.pcap' files using SharpPcap libary.

The goal is to retrieve XML data from the TCP/HTTP packets. In order to do this, I am using the code below (removed null checks to make it more readable):

Packet packet = Packet.ParsePacket(eventArguments.Packet.LinkLayerType, eventArguments.Packet.Data);
EthernetPacket ethernetPacket = ((EthernetPacket)packet);

IpPacket ipPacket = (IpPacket)packet.Extract(typeof(IpPacket));

TcpPacket tcpPacket = (TcpPacket)packet.Extract(typeof(TcpPacket));

string rawData = tcpPacket.PrintHex();

Moving, aside the hex values and the initial lines, I am able to extract the XML data from the rawData variable, along with an unexpected side-effect.

Instead of spaces, the .PrintHex() returns '.' characters:

Instead of:

<xml>Only text here</xml>

I am getting this:

<xml>Only.text.here</xml>

I am not doing any weird replacements or byte conversions. The above behavior is exactly what .PrintHex() returns.

  • Is this by any chance the expected outcome?
  • And more importantly... How can this be fixed or prevented? (having in mind that valid '.' from converted '.' cannot be distinguished)

Library versions:

  • .NET Framework: > 4.5.2

  • Pcapsharp: 4.2.0

Nkosi
  • 235,767
  • 35
  • 427
  • 472
Mario
  • 767
  • 1
  • 14
  • 42

2 Answers2

1

Try to use override of ToString() method which seems to do exactly what you expect.

Optionally if that does not work, implement public string PrintHex() from Packet on your own. If you take a look at decompiled code here is your problem :

    if ((int) bytes[index - 1] < 33 || (int) bytes[index - 1] > 126)
      str2 += ".";
    else
      str2 += Encoding.ASCII.GetString(new byte[1]
      {
        bytes[index - 1]
      });

Only characters with dec code ranging from 33 to 126 will be left unchanged, rest will be replaced with . (including space which is 32 http://www.asciitable.com/). And since BytesHighPerformance.Bytes is public you can write your own extension method rather easily along those lines.

TcpPacket tcpPacket = (TcpPacket)packet.Extract(typeof(TcpPacket));
string rawData = tcpPacket.CustomPrintHex();

public static class Extensions
{
    public static string CustomPrintHex(this TcpPacket self)
    {
        byte[] bytes = self.BytesHighPerformance.Bytes;

        // copy / paste of `PrintHex()` with your custom conversion
    }
}
just-my-name
  • 465
  • 1
  • 6
  • 15
  • Thank you. It worked for me. As a side note, ASCII codes 10 (new line) and 13 (carriage return) can be included, in order to keep the line separation within the content. – Mario Dec 09 '18 at 19:44
0

It might be helpful to others, so I am posting my final solution (which is based on the accepted answer).

Additional features:

  • Utilizing string builder for performance
  • Including new line characters

public class TcpPacketCustom: TcpPacket
{
    public static int AsciiRangeMin { get; } = 32;
    public static int AsciiRangeMax { get; } = 126;
    public static HashSet<int> AdditionalAsciiCodes { get; } = new HashSet<int> { 10, 13 }; //ascii codes of carriage and new line

    public TcpPacketCustom(ByteArraySegment byteArraySegment) : base(byteArraySegment) { }

    public new string PrintHex()
    {
        StringBuilder stringBuilder = new StringBuilder();
        foreach (byte b in this.BytesHighPerformance.Bytes)
        {
            int asciiCode = (int)b;
            if ( ((asciiCode < AsciiRangeMin) || (asciiCode > AsciiRangeMax)) && !AdditionalAsciiCodes.Contains(asciiCode) )
            {
                stringBuilder.Append(".");
            }
            else
            {
                stringBuilder.Append(Encoding.ASCII.GetString(new byte[1] { b }));
            }
        }
        return stringBuilder.ToString();
    }

}
Mario
  • 767
  • 1
  • 14
  • 42