Skip to content

Instantly share code, notes, and snippets.

@rikka0w0
Last active April 9, 2025 22:38
Show Gist options
  • Save rikka0w0/1643f3726f0bbb0c823f626d277ae2e3 to your computer and use it in GitHub Desktop.
Save rikka0w0/1643f3726f0bbb0c823f626d277ae2e3 to your computer and use it in GitHub Desktop.
Binary format of the Win32 Ribbon resource file

Introduction

The UICC.exe produces a binary description file from the source XAML, this binary is embedded in the generated RC resource file. The format of the binary file is not documented. I will try to reverse-engineer its binary format.

Definitions:

  1. Byte, 8 bits
  2. WORD, 16 bits, little-endian
  3. DWORD, 32 bits, little-endian

File Structure

  1. Header
  2. An Unknown String Section
  3. The Application.Commands Section
  4. The String Section
  5. The Unnamed Section
  6. The Pointer Section

The Header

  1. 0x0000: Starts with 00 12 00 00 00 00 00 01 00 53 43 42 69 6E (14 bytes, last 5 bytes in ASCII is SCBIN), all binaries seem to share this same header.
  2. 0x000e: DWORD, size of the binary file

An Unknown String Section

Starting at 0x12, this seems to be a string section, with unknown purpose.

  1. BYTE, 0x02, stands for the type?
  2. DWORD, length of this section, in bytes.
  3. BYTE, 0x01, unknown
  4. BYTE, the number of strings.
    Each string has the following format: 1 byte of fixed 0x01, 1 WORD of the length of the string and the string itself in ASCII, no '\0' termination.
    These strings can always be found: Small MajorItems StandardItems

The Application.Commands Section

Almost identical to the XAML Application.Commands tags. The length of the section header is 5 bytes. (Fixed)

  1. BYTE, 0x0F, stands for the type?
  2. DWORD, number of tags within this section

Tag Format

Each tag consists of multiple property -value pairs. The type is always 1 byte, however, the length of the data payload can vary. Up to now, the length can be 4 or 6, depending on the type byte.

  1. DWORD: ID, the higher WORD of this DWORD should always be 0, same rule applies to other DWORD IDs.
  2. Byte: Number of property-value pairs
  3. Byte: Tag type 1
  4. Variable-Length: Tag value 1
  5. Byte: Tag type 2
  6. Variable-Length: Tag value 2
  7. ....

Property Types:

static const struct ac_prop_data_item {
    enum ub_ac_property_type type;  // 1 byte
    const int len;                  // length of the data
    const char* name;               // Friendly name
} ac_prop_data[] = {
    {0x01, 4, "Command.LabelTitle"},
    {0x02, 4, "Command.LabelDescription"},
    {0x03, 6, "Command.SmallHighContrastImages"},
    {0x04, 6, "Command.LargeHighContrastImages"},
    {0x05, 6, "Command.SmallImages"},
    {0x06, 6, "Command.LargeImages"},
    {0x07, 4, "Command.Keytip"},
    {0x08, 4, "Command.TooltipTitle"},
    {0x09, 4, "Command.TooltipDescription"}
};

The first WORD of the payload points to a string or bitmap in the resource file. The second WORD is always 0 (As far as we know). The third WORD (if exists) is the DPI (0x03 to 0x06 only). The following XAML Attributes never appear in property value:

  1. Symbol: Sets the macro name of the resource in the generated .h file
  2. Id: Set the id of the resource manually, UICC.exe will generate one if not supplied.
  3. Content and Source: Their content are included in the resource file only.

The String Section

  1. BYTE, 0x10, stands for the type?
  2. DWORD: length of this String Section in bytes, including this DWORD and previous byte
  3. DWORD: number of strings within this String Section

Each string:

  1. WORD, ID
  2. WORD, 0x0000
  3. WORD, little-endian, object type
  4. WORD, 0x1000, little-endian, fixed. However, there is one exception (up to now, known): for type 0x0001, this WORD is 0x0000.
  5. WORD, length of this string
  6. WORDs, WideChar representation of the string.

Object Type

Little-endian:

  1. 0x0600 Toggle Button
  2. 0x0700 Group
  3. 0x0F00 Button
  4. 0x1300 "File" Menu
  5. 0x1800 MenuGroup
  6. 0x1A00 Tab
  7. 0x2500 Quick Access Bar (Qat)

The Unnamed Section

  1. BYTE, 0x0D
  2. WORD, 0x0003, little-endian, fixed
  3. DWORD, the absolute address of the pointer section
  4. The root tag
  5. DWORD, length of the supplementary block section
  6. supplementary block 1
  7. supplementary block 2
  8. supplementary block 3

Supplementary Block format

  1. WORD, length of this supplementary block
  2. WORD, 0x0118, little-endian, fixed
  3. BYTE, unknown
  4. WORD, number of tags.
  5. tag 1
  6. tag 2
  7. tag n

Tag format

  1. BYTE, 0x16
  2. WORD, object type
  3. WORD, 0x1000, little-endian, fixed
  4. WORD, length of this subsection, from the 0x16 byte to the end, including possible sub tags.
  5. BYTE, the sum of numbers of properties and possible sub tags
  6. Properties
  7. Sub tags header
  8. Possible sub tags1
  9. Possible sub tags2 ....

Properties

Properties seem to start with 4 bytes which represents its type and followed by the data. The length of data is variable, depending on the property type. The known properties are:

  1. 01 01 41 2B followed by a BYTE, MajorItems=1, StandardItems=2
  2. 01 01 00 03 followed by a WORD, which is the referring Id
  3. 01 01 0B 04 followed by a BYTE, purpose unknown
  4. 01 01 0B 09 followed by a BYTE, purpose unknown
  5. 3E followed by a DWORD, the DWORD points to a position within the file, purpose known. Only seen on 16 00 13 00 10.

Sub tags

A section(?) of sub tags starts with:

  1. 18 01, 2 bytes
  2. BYTE, can be 01,02,3E or more, meaning is still unknown.
  3. WORD, number of following

The Pointer Section

The first DWORD of this section is the length of this section, including the first DWORD. This section seems to store an array of pointers, each pointer points to the address of the first occurrence of its referring object. The purpose of this section is still not clear.

References

  1. https://www.codeproject.com/Articles/119319/Windows-Ribbon-Framework-in-Win32-C-Application
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment