Plist 二进制格式

1 Plist 存储格式

Plist 文件有3种存储格式:

  • xml
  • JSON
  • 二进制

使用plutil -convert <fmt>命令可以在这3种格式之间相互转换。

<fmt>分别对应上面3种存储格式:

  • xml1

  • json

  • binary1

同时如果输出到控制台,<fmt>还可以选择是按照OC还是Swift的方式进行输出:

bash 复制代码
// 按照 OC 输出
MacBook-Pro:~ user$ plutil -convert objc -o - xxxx.plist
/// Generated from xxxx.plist
__attribute__((visibility("hidden")))
NSDictionary * const xxxx = @{
    @"BuildVersion" : @"50",
    @"CFBundleShortVersionString" : @"4.13",
    @"CFBundleVersion" : @"3146.1.2",
    @"ProjectName" : @"Notes",
    @"SourceVersion" : @"3146001002000000",
};

// 按照 Swift 输出
MacBook-Pro:~ user$ plutil -convert swift -o - xxxx.plist
/// Generated from xxxx.plist
let xxxx = [
    "BuildVersion" : "50",
    "CFBundleShortVersionString" : "4.13",
    "CFBundleVersion" : "3146.1.2",
    "ProjectName" : "Notes",
    "SourceVersion" : "3146001002000000",
]

上面命令中的-o -表示要输出到控制台。

2 Plist 二进制格式

Plist二进制格式描述在苹果CF代码库中的CFBinaryPList.c中。

Plist二进制格式整体如下:

从图上可以看到,HeaderTrailer的大小是固定的。

ObjectsOffset-Table部分是可变的。

下面给出了一个二进制Plist的内容,相关部分已经用不同颜色进行了区分:

将二进制Plist打印为xml输出到控制台的内容为:

bash 复制代码
MacBook-Pro:~ user$ plutil -convert xml1 -o - xxxx.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>BuildVersion</key>
	<string>50</string>
	<key>CFBundleShortVersionString</key>
	<string>4.13</string>
	<key>CFBundleVersion</key>
	<string>3146.1.2</string>
	<key>ProjectName</key>
	<string>Notes</string>
	<key>SourceVersion</key>
	<string>3146001002000000</string>
</dict>
</plist>

可以将xml内容和二进制内容对照着看。

2.1 Header

Header总共有8字节,定义如下:

c 复制代码
// ForFoundationOnly.h
typedef struct {
    uint8_t	_magic[6];
    uint8_t	_version[2];
} CFBinaryPlistHeader;

2.1.1 magic

magic固定为plist

2.1.2 version

plist常见的version00

同时还有1516

版本1516都没有文档说明。

2.2 Trailer

Trailer固定位于二进制Plist的尾部,总共32字节。

Trailer的定义如下:

c 复制代码
// ForFoundationOnly.h
typedef struct {
    uint8_t	_unused[5];
    uint8_t _sortVersion;
    uint8_t	_offsetIntSize;
    uint8_t	_objectRefSize;
    uint64_t _numObjects;
    uint64_t _topObject;
    uint64_t _offsetTableOffset;
} CFBinaryPlistTrailer;

2.2.1 Unused

Trailer开始的头5字节没有使用,始终是0

2.2.2 SortVersion

SortVersion表是Plist中的Key是否排序,占用1字节。

0表示未排序。

2.2.3 OffsetIntSize

OffsetIntSize表示Offset-Table中每一项占用的字节数。

在上面例子中可以看到,OffsetIntSize1,表示Offset-Table中每项只占用1字节。

2.2.4 ObjectRefSize

ObjectRefSize表示DictArray中引用的对象索引占用的字节数。

在上面例子中ObjectRefSize1,表示DictArray中引用对象的索引占用1字节。

Objects区域的第1个字节d5为例。

d5的高4bit代表数据类型,d代表Dict

d5的低4bitDict场景代表key-value对的个数,也就是这个Dict5key-value对。

d5后面0x01-0x051个字节代表keyOffset-Table中的索引。

0x06-0x0a1个字节代表valueOffset-Table中的索引。

如果ObjectRefSize2,那么这些索引就会占用2个字节。

2.2.5 Num-Objects

Num-Objects代表二进制Plist中的对象个数。

在上面例子中,有一个Dict,这个Dict5key-value对,因此总共有11个对象。

2.2.6 Top-Object

Top-Object表示根对象偏移量,一般都为0

在上面例子中,根对象就是plist节点。

2.2.7 Offset-Table Offset

Offset-Table Offset表示Offset-Table的偏移量。

在上面例子中,Offset-Table位于0x93处。

2.2.8 Offset-Table

Offset-Table中的每一项存储对象在Plist文件中的偏移量。

Offset-Table的项从0开始计数。

上面例子中Offset-Table的第0项为0x08

Plist二进制偏移0x08处的值是d5

d5代表了数据类型。

d54bit代表这是一个Dict

d54bit代表这个Dict5key-value对。

2.2.9 Objects

Objects区域就是二进制Plist的数据区。

3 Plist 二进制中的数据类型

常见的Plist二进制中的数据类型如下:

  • 0x00

0x00代表null

  • 0x08

0x08代表布尔值false

  • 0x09

0x09代表布尔值true

  • 0x1n

0x1n表示是int类型。

0x1n中的n可以取0~7,表示这个int占用2^n个字节,这些字节是大端在前排列。

比如0x11 0x20 0x30,那么n=1,表示这个int占用2个字节,为0x2030

  • 0x2n

0x2n表示是real类型。

0x2n中的n可以取值0~7,表示这个real类型占用2^n个字节,这些字节是大端在前排列。

  • 0x5n

0x5n表示ASCII字符串。

0x5nn取值0-f,表示这个ASCII字符串占用的字节数。

ASCII字符串的内容接在0x5n的后面。

但是如果n=f,那么后面的1个字节表示一个int类型,定义了这个ASCII字符串占用的字节数。

比如有一个字节序列0x5f 10 0f

0x5f表示这是一个ASCII字符串。

10按照上面int的定义,它后面的2^0=1个字节定义了这个整数,也就是0xf

那么,整个ASCII字符串就占用0xf个字节。

  • an

an表示是Array类型。

ann取值0-f,表示这个Array中元素的个数。

Array中每个元素在Offset-Table中的索引直接接在an后面。

如果n=f,那么就和0x5n中的一样。

  • dn

dn表示是Dict类型。

dnn取值0-f,表示这个Dictkey-value对个数。

Dict后面先跟keyOffset-Table中的索引,接着跟着valueOffset-Table中的索引。

如果n=f,那么就和0x5n中的一样

更多详细的类型参看CFBinaryPList.c

相关推荐
汉克老师16 天前
GESP2024年12月认证C++三级( 第一部分选择题(1-8))
c++·字符串·二进制·八进制·补码·gesp三级·gesp3级
汉克老师20 天前
GESP2025年6月认证C++三级( 第一部分选择题(1-8))
c++·二进制·原码·补码·gesp三级·gesp3级·八进制、
The_Uniform_C@t22 个月前
PWN | 对CTF WIKI的复现+再学习 (第八期)
网络·学习·网络安全·二进制
zfj3213 个月前
小数和整数10进制转2进制算法
算法·二进制·进制转换·十进制
楠木s6 个月前
ctfshow pwn44
linux·服务器·网络·安全·网络攻击模型·二进制
笔沫拾光6 个月前
二进制世界如何表达现实世界的文字、图像和视频
计算机·二进制
深思慎考6 个月前
Linux二进制查看工具——hexdump
linux·c++·二进制·文件查看·hexdump
程序猿编码8 个月前
二进制签名查找器(Aho-Corasick 自动机):设计思路与实现原理(C/C++代码实现)
c语言·c++·网络安全·二进制·逆向工程·ac自动机
yi.Ist9 个月前
关于二进制的规律
算法·二进制·bitset