Wednesday, December 29, 2010

PLF File Format

A few weeks ago i bought an A.R. Drone from Parrot. This quadcopter is controlled over WLAN and uses an embedded Linux on an ARM chipset.

Altough it is possible via FTP / Telnet to modify the file system, i was intreseted in the flash file format. So I analyzed the available firmware.

I was quite successful athough there are still some unkown fields left.

Fileheader:
typedef struct sPLFFile
{
  u32 dwMagic; 
  u32 dwHdrVersion;
  u32 dwHeaderSize;
  u32 dwEntryHeaderSize;
  u32 uk_0x10;
  u32 uk_0x14;
  u32 uk_0x18;
  u32 uk_0x1C;
  u32 uk_0x20;
  u32 dwVersionMajor;
  u32 dwVersionMinor;
  u32 dwVersionBugfix;
  u32 uk_0x30;
  u32 dwFileSize;
}

The fields have the following meaning:

  • dwMagic: MagicCode of the file. Must be 0x21464C50
  • dwHdrVersion: Version of the header struct. Only seen with 0xB or 0xA
  • dwHeaderSize: Size of the file header. Must be 0x38.
  • dwEntryHeaderSize: Size of the section header. Must be 0x14.
  • uk_0x10: Currently unkown. Maybe some Type. Seen with 0x2
  • uk_0x14: Currently unkown. Maybe an EntryPoint. Seen with 0x0
  • uk_0x18: Currently unkown. Maybe the Device Type. Seen with 0x4
  • uk_0x1C: Currently unkown. Maybe the Model Number. Seen with 0x4E
  • uk_0x20: Currenlty unkown. Seen with 0x20
  • dwVersionMajor: Major version of this firmware
  • dwVersionMinor: Minor version of this firmware
  • dwVersionBugfix: Bugfix version of this firmware
  • uk_0x30: Curently unkown
  • dwFileSize: Size of the file.



After the header the sections follow. Each section starts with the following header.
typedef struct sPLFEntryTag
{
  u32 dwSectionType;
  u32 dwEntrySize;
  u32 dwCRC32;
  u32 uk_0x0C;
  u32 dwUncompressedSize;
}

The fields have the following meaning:
  • dwSectionType: Type of the section.

    0x00: unkown
    0x03: probably the bootloader
    0x07: unkown
    0x09: Filesystem action/content
    0x0b: Configuration Data (Mounting, creation of partitions)
    0x0c: Installer (contains another PLF file)
  • dwEntrySize: Size of the section (excluding header size)
  • dwCRC32: CRC-32 of the content and EntrySize
  • uk_0x0C: Currently unkown. Seems to be the address where to load the section to
  • dwUncompressedSize: If > 0, the content of this entry is compressed with gzip format. The value represents the uncompressed size of the entry.
The meaning of each section depends on dwSectionType.

0x09 - File system content
Each section represents one entry on the file system. It first starts with the null-terminated filename (variable length). After this name, the following header is placed:

typedef struct sFileEntryTag
{
  u32 dwFlags;
  u32 uk_0x04;
  u32 uk_0x08;
} sFileEntry;

  • dwFlags: Flags of the file entry. Encodes the type of the entry and the access rights.

    bit00-11: Rights of the file. Its the same as you would use for chmod. E.g. 0755 -> 0x1ED
    bit12-15: Type of the file entry:
    • 0x04: mkdir. No more data follows after the header.
    • 0x08: write. The file content follows after the header.
    • 0x0A: symlink. The target of the link follows after the header.
  • uk_0x04: Currently unkown. Seems to be either the UID or GID.
  • uk_0x08: Currently unkown. Seems to be either the UID or GID.
0x0b - Configuration data
This section contains informations about mounting, truncating and creating partitions. There is an old and a new version.

Old version (starts with "/mnt"):
32 bytes unkown. Then a u32 with some unkown_count follows. Then unkown_count*8 bytes follows. Then a u32 with the number of entries follows. Afterwards, the entries follow.

New version (does not start with "/mnt"):
typedef struct sPartitionSectionTag
{
  u32 dwTblVersion;
  u32 dwVersionMajor;
  u32 dwVersionMinor;
  u32 dwVersionBugfix;
  u32 uk_0x10;
  u32 uk_0x14;
  u32 uk_0x18;
  u32 uk_0x1C;
  u32 uk_0x20;
  u32 dwNumEntries;
} sPartitionSection;

  • dwTblVersion: Seems to be the version of this "partition table". 
  • dwVersionMajor: Major version
  • dwVersionMinor: Minor version
  • dwVersionBugfix: Bugfix version
  • uk_0x10 - uk_0x20: Unkown
  • dwNumEntries number of partition entries
For both, new and old version, the entries follow directly after the header. Each entries had the following format:

typedef struct sPartitionEntryTag
{
  u16 wDevice;
  u16 wVolumeType;
  u16 wVolume;
  u16 uk_0x06;
  u32 dwVolumeSize;
  u32 wVolumeAction;
  u8  cVolumeName[32];
  u8  cMountName[32];
} sPartitionEntry;

  • wDevice: Device number
  • wVolumeType: Volume type.
    • 0x0: RAW - no file system is available on this device
    • 0x1: STATIC - A filesystem is available but will not change (e.g. for the boot partitions)
    • 0x2: DYNAMIC - A filesystem is availalbe and can be changed 
  • wVolume: Volume number
  • uk_0x06: Unkown
  • dwVolumeSize: Size of the volume. Only to be used for wVolumeAction=2
  • wVolumeAction
    • 0x0: mount. Only for wVolumeType=2! -> mount /dev/ubi__
    • 0x1: truncate and mount -> Truncates the partition and mounts it afterwards
    • 0x2: create partition -> will call ubimkvol

... to be continued ...

Feel free to leave your comments!

2 comments:

  1. Hello.

    How could you disassemble that .plf file? I want to learn about this file type, for editing my Parrot Car Kit.

    ReplyDelete
  2. Oh This is great work!
    You are bring the chance to great improvements for the ARdrone software.
    Please continue your excellent work!
    Mike Aparicio

    ReplyDelete