1

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.

Amit
  • 165
  • 1
  • 9
  • Those two bytes do not appear to be a CRC-16 of anything that precedes them. – Mark Adler May 13 '22 at 00:00
  • When I'm passing those packets to the receiver side, in case I don't pass the "Checksum" field with the packet I get a test error due to corrupted packet - which lead me to believe the receiver knows about corruption using this field. – Amit May 13 '22 at 04:06
  • I don't doubt that. They do not appear to be a CRC-16. I recommend searching for documentation on what checksum algorithm is used. – Mark Adler May 13 '22 at 04:22
  • As this is a Microsoft proprietary header, I didn't find any formal checksum algorithm documentation (unlike for example known UDP checksum algorithm) – Amit May 13 '22 at 04:42
  • By the way, if you wipe out any portion of a checked packet, which may or may not be the check value itself, you will get the same error that the packet is corrupted. – Mark Adler May 13 '22 at 05:41
  • Agree, as only when combining all fields (with some unknown algorithm), we will get non corrupted packet, but as I parsed by now hundreds of IPX packets of all sizes and shapes, I'm pretty sure all other fields have different meaning, and this is the only suspected CRC/Checksum field. (I have also an unknown 8 bit field but its mostly static (0x1) ) – Amit May 13 '22 at 07:05

1 Answers1

1

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.

heap underrun
  • 1,846
  • 1
  • 18
  • 22