checksumcrcpacket-snifferscrc16ndis

Checksum/CRC reverse engineering of Microsoft NDIS packet


I am trying to decode a 42-byte packet which seems to include 2-byte CRC / checksum field

This is a Microsoft NDIS packet (type IPX) which is sent in HLK (WHQL) tests

I have decoded most parts of the NDIS header but I can't seem to figure out the CRC/Checksum algorithm

Sample of a 45-byte packet (just to explain the decoded fields):

char packet_bytes[] = {
  0x02, 0xe4, 0x55, 0xee, 0x12, 0x56, 0x02, 0x93,
  0x19, 0x40, 0x89, 0x00, 0x00, 0x1f, 0xaa, 0xaa,
  0x03, 0x00, 0x00, 0x00, 0x81, 0x37, 0x4e, 0x44,
  0x49, 0x53, 0x01, 0x49, 0x03, 0x00, 0x98, 0xd4,
  0x58, 0x55, 0x25, 0xf5, 0x39, 0x00, 0x14, 0x00,
  0x00, 0x00, 0x49, 0x4a, 0x4b
};


Raw: 02e455ee1256029319408900001faaaa0300000081374e4449530149030098d4585525f5390014000000494a4b

Decoded fields:

802.2 ethernet header: (Wireshark decoding)
  02e455ee1256 : Destination
  029319408900 : Source
  001f : Length
  
Logical_link Control: (Wireshark decoding)
  aa : DSAP
  aa : SSAP
  03 : Control
  000000 : Organization
  8137 : Type (Netware IPX/SPX)
  
NDIS header: (my estimation for NDIS decoded fields)
  4e444953 : NDIS ascii String ("NDIS")
  01 : Unknown
  49 : payload counter start (first byte of payload, with increasing value afterwards)
  0300 : Payload length ( = 0003)
  98d4 : test identification number (equal on all packets of the same test)
  5855 : Assumed to be checksum
  25f53900 : Packet counter ( = 0039f525, Increases gradually per packet) 
  14000000 : Payload offset ( = 00000014), offset from start of NDIS header to start of payload
  494a4b : Payload (3 bytes of increasing counter 49,4a,4b)

To try to understand the checksum algorithm with minimal packet bytes, I've captured the minimal packets size (42 bytes)

Those packets include the headers above but without payload at all

And tried to reverse eng them using reveng CRC decoder which fail to find any known CRC algorithm

Sample 42-byte packets:

02e455ee1256029319408900001caaaa0300000081374e444953016b000098d495262502000014000000
02e455ee1256029319408900001caaaa0300000081374e44495301a2000098d481ef3802000014000000
02e455ee1256029319408900001caaaa0300000081374e4449530152000098d47f3f3b02000014000000
02e455ee1256029319408900001caaaa0300000081374e44495301d0000098d476c14302000014000000
02e455ee1256029319408900001caaaa0300000081374e44495301f7000098d4539a6602000014000000
02e455ee1256029319408900001caaaa0300000081374e44495301b6000098d444db7502000014000000
02e455ee1256029319408900001caaaa0300000081374e44495301a6000098d431eb8802000014000000
02e455ee1256029319408900001caaaa0300000081374e444953016a000098d40627b402000014000000

Reverse eng the CRC:

reveng.exe -w 16 -s 02e455ee1256029319408900001caaaa0300000081374e444953016b000098d495262502000014000000 02e455ee1256029319408900001caaaa0300000081374e44495301a2000098d481ef3802000014000000 02e455ee1256029319408900001caaaa0300000081374e4449530152000098d47f3f3b02000014000000 02e455ee1256029319408900001caaaa0300000081374e44495301d0000098d476c14302000014000000 02e455ee1256029319408900001caaaa0300000081374e44495301f7000098d4539a6602000014000000 02e455ee1256029319408900001caaaa0300000081374e44495301b6000098d444db7502000014000000 02e455ee1256029319408900001caaaa0300000081374e44495301a6000098d431eb8802000014000000 02e455ee1256029319408900001caaaa0300000081374e444953016a000098d40627b402000014000000
reveng.exe: no models found

Tried reverse eng only the NDIS header part:

4e444953016b000098d495262502000014000000
4e44495301a2000098d481ef3802000014000000
4e4449530152000098d47f3f3b02000014000000
4e44495301d0000098d476c14302000014000000
4e44495301f7000098d4539a6602000014000000
4e44495301b6000098d444db7502000014000000
4e44495301a6000098d431eb8802000014000000
4e444953016a000098d40627b402000014000000

reveng.exe -w 16 -s 4e444953016b000098d495262502000014000000 4e44495301a2000098d481ef3802000014000000 4e4449530152000098d47f3f3b02000014000000 4e44495301d0000098d476c14302000014000000 4e44495301f7000098d4539a6602000014000000 4e44495301b6000098d444db7502000014000000 4e44495301a6000098d431eb8802000014000000 4e444953016a000098d40627b402000014000000
reveng.exe: no models found

Any help would be appreciated.


Solution

  • This seems to be the Internet Checksum, described in RFC 1071, calculated over the NDIS header part of the packet.

    In short, you need to add up all of the header contents (except the 16-bit checksum field itself) as 16-bit values, then add the carries (if any) to the least significant 16 bits of the result (thus forming the one's complement sum), and finally, calculate one's complement of this one's complement sum by inverting all bits.

    For the example packet you listed, the manual calculation steps would be the following.

    1. Given the whole packet:
    02e455ee1256029319408900001faaaa0300000081374e4449530149030098d4585525f5390014000000494a4b
    
    1. Extract the NDIS header part only, without the payload:
    4e4449530149030098d4585525f5390014000000
    
    1. Split into 16-bit values:
    4e44
    4953
    0149
    0300
    98d4
    5855
    25f5
    3900
    1400
    0000
    
    1. Substitute the checksum field with zeroes:
    4e44
    4953
    0149
    0300
    98d4
    0000
    25f5
    3900
    1400
    0000
    
    1. Add all those 16-bit values together:
    1A7A9
    
    1. Here, the 16 least significant bits are A7A9 and the arithmetic carry is 1. So, add these together (as 16-bit words), to form the so-called one's complement sum:
      0001
    + A7A9
    = A7AA
    
    1. Now, invert all bits (apply the bitwise NOT operation), to get the one's complement:
    ~ A7AA
    = 5855
    
    1. Place this checksum back into the place (which we temporarily zeroed out):
    4e44
    4953
    0149
    0300
    98d4
    5855
    25f5
    3900
    1400
    0000
    

    If you only want to check the checksum, do the following.

    1. First, take the original NDIS header (as 16-bit values):
    4e44
    4953
    0149
    0300
    98d4
    5855
    25f5
    3900
    1400
    0000
    
    1. Then sum all of this up:
    1FFFE
    
    1. Again, add the carry to the 16-bit LSB part:
      0001
    + FFFE
    = FFFF
    

    If all the bits of the result are 1 (i.e., if the result is FFFF), the check is successful.