The icon you see in Explorer, the version string in a file properties dialog, the error dialog text in your language, and the application manifest that asks for per-user privileges all live inside the PE file itself. None of that is loose text — it is a lookup table the operating system reads with FindResource-style APIs.
The resource directory is also the structure malware analysts, localization tools, and installers touch every day: extract an icon, swap a dialog, read the manifest that decides whether a program runs elevated. If you cannot walk this tree, half of the PE file is unreadable to you.
Data directory index 2 (the Resource Table) points at this structure. In our 64-bit sample cli-64.exe it holds RVA 0x7000 with size 0x1E0, exactly the .rsrc section.
Think of resources as a three-level filing cabinet, which is exactly how the PE/COFF specification describes it by convention:
Each level is a directory: a 16-byte header followed by 8-byte entries. An entry either points one level deeper (a subdirectory) or ends the walk (a leaf) that finally describes the raw bytes.
The model's missing piece: every level uses the same two structures, and a single high bit inside each entry decides which way it points. Learn one level and you have learned all three.
The specification chapter "The .rsrc Section" pins down every field:
| Structure | Size | Contents |
|---|---|---|
| Resource Directory Table | 16 bytes | Characteristics, Time/Date Stamp, Major/Minor Version, Number of Name Entries, Number of ID Entries |
| Directory Entry | 8 bytes | Name Offset or Integer ID (4 bytes), then Data Entry Offset or Subdirectory Offset (4 bytes) |
| Resource Data Entry | 16 bytes | Data RVA, Size, Codepage, Reserved |
Three rules from the spec control the whole walk: all Name entries precede all ID entries in every table; entries are sorted in ascending order (names by case-sensitive string, IDs by numeric value); and directory offsets are relative to the address of the resource data directory, not to the start of the file.
The high bit of the second entry field is the branch: clear means the low 31 bits address a leaf (Resource Data Entry), set means they address the next directory table. Windows preassigns the well-known Type IDs — for example RT_ICON is 3, RT_GROUP_ICON is 14, RT_VERSION is 16, RT_MANIFEST is 24 (Microsoft, "Resource Types").
The first 96 bytes of the .rsrc section in cli-64.exe (section file offset 0x3400) contain the entire walk for its one resource. The bytes are shown without the trailing ascii column:
00003400: 0000 0000 0000 0000 0000 0000 0000 0100 00003410: 1800 0000 1800 0080 0000 0000 0000 0000 00003420: 0000 0000 0000 0100 0100 0000 3000 0080 00003430: 0000 0000 0000 0000 0000 0000 0000 0100 00003440: 0904 0000 4800 0000 6070 0000 7d01 0000 00003450: 0000 0000 0000 0000 0000 0000 0000 0000
Walk-through:
0100).0100 0000 3000 0080: Name ID 1, high bit set, subdirectory at 0x30 — file 0x3430.The bytes at RVA 0x7060 (file 0x3460, because .rsrc sits at RVA 0x7000 / file 0x3400) open with an XML declaration — this binary embeds a Windows application manifest:
00003460: 3c3f 786d 6c20 7665 7273 696f 6e3d 2731
3c 3f is an opening angle bracket followed by a question mark, and 78 6d 6c spells xml. The second sample, conpty.dll, shows the same tree with more breadth: its type table counts 2 ID entries — 0x10 (RT_VERSION, 16) and 0x18 (RT_MANIFEST, 24) — with leaves of size 0x358 and 0x17D.
Any Windows executable works. On Linux or macOS, find the .rsrc file offset from the section table, then dump it (0x3400 for our sample):
$ xxd -s 0x3400 -l 96 cli-64.exe
00003400: 0000 0000 0000 0000 0000 0000 0000 0100 ................
00003410: 1800 0000 1800 0080 0000 0000 0000 0000 ................Decode by hand: read the last two bytes of the header as a little-endian count, then read each entry as two 32-bit little-endian words. Mask the second word with 0x7FFFFFFF to get the next offset, and test the top bit to learn whether it is a subdirectory or a leaf.
What to look for: the ID 0x18 should appear immediately, because almost every desktop executable ships a manifest. If you see IDs 3, 14, or 16 instead, you are looking at icons or a version block — the same tree, different Type ID.
Without looking back: in a three-level resource walk, which level does the value 0x0409 identify?
A directory entry reads 1800 0000 1800 0080. Before touching a hex editor again: where does this entry point, and relative to what?
The pattern: mask the high bit for the offset, use the high bit itself as the branch, and remember the base is the directory — not the file.
Resources are static data a program carries for the loader and the shell. The next table is the opposite: data the loader actively writes into the image while threads are being created.
Next: Thread-Local Storage — the TLS directory, its per-thread template, and the callback array.