Search code examples
windowsendianness

What is the byte/bit order in this Microsoft document?


This is the documentation for the Windows .lnk shortcut format:

https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-shllink/16cb4ca1-9339-4d0c-a68d-bf1d6cc0f943

The ShellLinkHeader structure is described like this:

screenshot

This is a file:

screenshot

Looking at HeaderSize, the bytes are 4c 00 00 00 and it's supposed to mean 76 decimal. This is a little-endian integer, no surprise here.

Next is the LinkCLSID with the bytes 01 14 02 00 00 00 00 00 c0 00 00 00, representing the value "00021401-0000-0000-C000-000000000046". This answer seems to explain why the byte order changes because the last 8 bytes are a byte array while the others are little-endian numbers.

My question is about the LinkFlags part.

The LinkFlags part is described like this:

screenshot

And the bytes in my file are 9b 00 08 00, or in binary:

9    b    0    0    0    8    0    0
1001 1011 0000 0000 0000 1000 0000 0000
 ^

By comparing different files I found out that the bit marked with ^ is bit 6/G in the documentation (marked in red).

How to interpret this? The bytes are in the same order as in the documentation but each byte has its bits reversed?


Solution

  • The issue here springs from the fact the shown list of bits in these specs is not meant to fit a number underneath it at all. It is meant to fit a list of bits underneath it, and that list goes from the lowest bit to the highest bit, which is the complete inverse of how we read numbers from left to right.

    The list clearly shows bits numbered from 0 to 31, though, meaning this is indeed one 32-bit value, and not four bytes. Specifically, this means the original read bytes need to be interpreted as a single 32-bit integer before doing anything else. Like with all other values, this means it needs to be read as little-endian number, with its bytes reversed.

    So your 9b 00 08 00 becomes 0008009b, or, in binary, 0000 0000 0000 1000 0000 0000 1001 1011.

    But, as I said, that list in the specs shows the bits from lowest to highest. So to fit them under that, reverse the binary version:

    0           1            2           3
    0123 4567 8901 2345 6789 0123 4567 8901
    ABCD EFGH IJKL MNOP QRST UVWX YZ@_ ____
    ---------------------------------------
    1101 1001 0000 0000 0001 0000 0000 0000
           ^
    

    So bit 6, indicated in the specs as 'G', is 0.

    This whole thing makes a lot more sense if you invert the specs, though, and list the bits logically, from highest to lowest:

     3           2            1           0
    1098 7654 3210 9876 5432 1098 7654 3210
    ____ _@ZY XWVU TSRQ PONM LKJI HGFE DCBA
    ---------------------------------------
    0000 0000 0000 1000 0000 0000 1001 1011
                                   ^
       0    0    0    8    0    0    9    b
    

    This makes the alphabetic references look a lot less intuitive, but it does perfectly fit the numeric versions underneath. The bit matches your findings (third bit on what you have as value '9'), and you can also clearly see that the highest 5 bits are unused.