.trx file format is widely used for distribution of firmware updates for Broadcom devices. The most well-known are ASUS routers.
Fundamentally, it includes a footer which acts as a safeguard against installing a firmware package on a wrong hardware model or version, and a header which list numerous partitions packaged inside a single .trx file.
trx files not necessarily contain all these headers.
This page hosts a formal specification of Broadcom devices .trx firmware packaging using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.
digraph {
rankdir=LR;
node [shape=plaintext];
subgraph cluster__broadcom_trx {
label="BroadcomTrx";
graph[style=dotted];
broadcom_trx__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
</TABLE>>];
broadcom_trx__inst__header [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
<TR><TD PORT="header_pos">0</TD><TD PORT="header_size">...</TD><TD>Header</TD><TD PORT="header_type">header</TD></TR>
</TABLE>>];
broadcom_trx__inst__tail [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
<TR><TD PORT="tail_pos">_io.size - 64</TD><TD PORT="tail_size">64</TD><TD>Tail</TD><TD PORT="tail_type">tail</TD></TR>
</TABLE>>];
subgraph cluster__header {
label="BroadcomTrx::Header";
graph[style=dotted];
header__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
<TR><TD PORT="magic_pos">0</TD><TD PORT="magic_size">4</TD><TD>48 44 52 30</TD><TD PORT="magic_type">magic</TD></TR>
<TR><TD PORT="len_pos">4</TD><TD PORT="len_size">4</TD><TD>u4le</TD><TD PORT="len_type">len</TD></TR>
<TR><TD PORT="crc32_pos">8</TD><TD PORT="crc32_size">4</TD><TD>u4le</TD><TD PORT="crc32_type">crc32</TD></TR>
<TR><TD PORT="version_pos">12</TD><TD PORT="version_size">2</TD><TD>u2le</TD><TD PORT="version_type">version</TD></TR>
<TR><TD PORT="flags_pos">14</TD><TD PORT="flags_size">2</TD><TD>Flags</TD><TD PORT="flags_type">flags</TD></TR>
<TR><TD PORT="partitions_pos">16</TD><TD PORT="partitions_size">4</TD><TD>Partition</TD><TD PORT="partitions_type">partitions</TD></TR>
<TR><TD COLSPAN="4" PORT="partitions__repeat">repeat until ((i >= 4) || (!(_.is_present))) </TD></TR>
</TABLE>>];
subgraph cluster__flags {
label="BroadcomTrx::Header::Flags";
graph[style=dotted];
flags__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
<TR><TD PORT="flags_pos">0</TD><TD PORT="flags_size">1b</TD><TD>b1le→bool</TD><TD PORT="flags_type">flags</TD></TR>
<TR><TD COLSPAN="4" PORT="flags__repeat">repeat 16 times</TD></TR>
</TABLE>>];
}
subgraph cluster__partition {
label="BroadcomTrx::Header::Partition";
graph[style=dotted];
partition__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
<TR><TD PORT="ofs_body_pos">0</TD><TD PORT="ofs_body_size">4</TD><TD>u4le</TD><TD PORT="ofs_body_type">ofs_body</TD></TR>
</TABLE>>];
partition__inst__body [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
<TR><TD PORT="body_pos">ofs_body</TD><TD PORT="body_size">len_body</TD><TD></TD><TD PORT="body_type">body</TD></TR>
<TR><TD COLSPAN="4" PORT="body__if">if is_present</TD></TR>
</TABLE>>];
partition__inst__is_last [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD BGCOLOR="#E0FFE0">id</TD><TD BGCOLOR="#E0FFE0">value</TD></TR>
<TR><TD>is_last</TD><TD> ((idx == _parent.partitions.length - 1) || (!(_parent.partitions[idx + 1].is_present))) </TD></TR>
</TABLE>>];
partition__inst__is_present [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD BGCOLOR="#E0FFE0">id</TD><TD BGCOLOR="#E0FFE0">value</TD></TR>
<TR><TD>is_present</TD><TD>ofs_body != 0</TD></TR>
</TABLE>>];
partition__inst__len_body [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD BGCOLOR="#E0FFE0">id</TD><TD BGCOLOR="#E0FFE0">value</TD></TR>
<TR><TD>len_body</TD><TD>(is_last ? _root._io.size - ofs_body : _parent.partitions[idx + 1].ofs_body)</TD></TR>
</TABLE>>];
}
}
subgraph cluster__revision {
label="BroadcomTrx::Revision";
graph[style=dotted];
revision__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
<TR><TD PORT="major_pos">0</TD><TD PORT="major_size">1</TD><TD>u1</TD><TD PORT="major_type">major</TD></TR>
<TR><TD PORT="minor_pos">1</TD><TD PORT="minor_size">1</TD><TD>u1</TD><TD PORT="minor_type">minor</TD></TR>
</TABLE>>];
}
subgraph cluster__tail {
label="BroadcomTrx::Tail";
graph[style=dotted];
tail__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
<TR><TD PORT="version_pos">0</TD><TD PORT="version_size">4</TD><TD>Version</TD><TD PORT="version_type">version</TD></TR>
<TR><TD PORT="product_id_pos">4</TD><TD PORT="product_id_size">12</TD><TD>str(UTF-8)</TD><TD PORT="product_id_type">product_id</TD></TR>
<TR><TD PORT="comp_hw_pos">16</TD><TD PORT="comp_hw_size">4</TD><TD>HwCompInfo</TD><TD PORT="comp_hw_type">comp_hw</TD></TR>
<TR><TD COLSPAN="4" PORT="comp_hw__repeat">repeat 4 times</TD></TR>
<TR><TD PORT="reserved_pos">32</TD><TD PORT="reserved_size">32</TD><TD></TD><TD PORT="reserved_type">reserved</TD></TR>
</TABLE>>];
subgraph cluster__hw_comp_info {
label="BroadcomTrx::Tail::HwCompInfo";
graph[style=dotted];
hw_comp_info__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
<TR><TD PORT="min_pos">0</TD><TD PORT="min_size">2</TD><TD>Revision</TD><TD PORT="min_type">min</TD></TR>
<TR><TD PORT="max_pos">2</TD><TD PORT="max_size">2</TD><TD>Revision</TD><TD PORT="max_type">max</TD></TR>
</TABLE>>];
}
}
subgraph cluster__version {
label="BroadcomTrx::Version";
graph[style=dotted];
version__seq [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD BGCOLOR="#E0FFE0">pos</TD><TD BGCOLOR="#E0FFE0">size</TD><TD BGCOLOR="#E0FFE0">type</TD><TD BGCOLOR="#E0FFE0">id</TD></TR>
<TR><TD PORT="major_pos">0</TD><TD PORT="major_size">1</TD><TD>u1</TD><TD PORT="major_type">major</TD></TR>
<TR><TD PORT="minor_pos">1</TD><TD PORT="minor_size">1</TD><TD>u1</TD><TD PORT="minor_type">minor</TD></TR>
<TR><TD PORT="patch_pos">2</TD><TD PORT="patch_size">1</TD><TD>u1</TD><TD PORT="patch_type">patch</TD></TR>
<TR><TD PORT="tweak_pos">3</TD><TD PORT="tweak_size">1</TD><TD>u1</TD><TD PORT="tweak_type">tweak</TD></TR>
</TABLE>>];
}
}
broadcom_trx__inst__header:header_type -> header__seq [style=bold];
broadcom_trx__inst__tail:tail_type -> tail__seq [style=bold];
header__seq:flags_type -> flags__seq [style=bold];
header__seq:partitions_type -> partition__seq [style=bold];
partition__inst__is_present:is_present_type -> header__seq:partitions__repeat [color="#404040"];
partition__seq:ofs_body_type -> partition__inst__body:body_pos [color="#404040"];
partition__inst__len_body:len_body_type -> partition__inst__body:body_size [color="#404040"];
partition__inst__is_present:is_present_type -> partition__inst__body:body__if [color="#404040"];
partition__params:idx_type -> partition__inst__is_last [color="#404040"];
header__seq:partitions_type -> partition__inst__is_last [color="#404040"];
partition__inst__is_present:is_present_type -> partition__inst__is_last [color="#404040"];
partition__seq:ofs_body_type -> partition__inst__is_present [color="#404040"];
partition__inst__is_last:is_last_type -> partition__inst__len_body [color="#404040"];
partition__seq:ofs_body_type -> partition__inst__len_body [color="#404040"];
tail__seq:version_type -> version__seq [style=bold];
tail__seq:comp_hw_type -> hw_comp_info__seq [style=bold];
hw_comp_info__seq:min_type -> revision__seq [style=bold];
hw_comp_info__seq:max_type -> revision__seq [style=bold];
}