如何知道一个文件是什么类型的文件
1. 如何知道一个文件是什么类型的文件文件有各种各样的类型, 比如有普通的文本文件(*.txt), doc文件, ppt文件, exe文件, dll文件, so文件, iso文件, mp3文件, mp4文件,jpg文件, pdf文件等等.但是, 你有没有想过这个问题:任何一个文件, 它实质上就是一片0和1组成的数据. 工具(比如linux中的file工具)是怎么判断出文件是什么类型的文件呢?例如,
1. 如何知道一个文件是什么类型的文件
文件有各种各样的类型, 比如有普通的文本文件(*.txt), doc文件, ppt文件, exe文件, dll文件, so文件, iso文件, mp3文件, mp4文件, jpg文件, pdf文件等等.
但是, 你有没有想过这个问题:
任何一个文件, 它实质上就是一片0和1组成的数据. 工具(比如linux中的file工具)是怎么判断出文件是什么类型的文件呢?
例如, 有一个1foo.o的ELF文件, 用file命令可以得出它是ELF Relocatable文件.
[mg@vm201226 elf]$ gcc -g -O0 -c 1foo.c -o 1foo.o
[mg@vm201226 elf]$ file 1foo.o
1foo.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), with debug_info, not stripped
命令file 1foo.o
中, file工具怎么知道1foo.o是ELF文件呢? 它为什么不判定1foo.o是txt文件, 或者是doc文件, 或者是mp4文件呢?
这里, 就提供了一个1foo.o文件, 其他什么也没有了, 这说明了什么呢?
这说明文件类型信息肯定是存在于文件1foo.o本身之中. 也就是说, 一个文件, 它自己就携带了描述它自身是什么文件类型的信息.
2. 文件的魔数决定了文件的类型
在文件的规范/约定/协议中, 规定文件开头的几个字节, 可以用来作为Format Indicator(格式指示), 并将这几个用来指示文件类型的字节数据称为Magic Number(魔数).
不同类型的文件, 魔数不同. 每种类型的文件, 魔数都唯一的.
当给定一个文件, 读取文件最开始的一些字节, 判断这些字节是什么内容, 从而可以得知文件时什么类型的文件.
常见的文件的魔数, 见List of file signatures.
这里列举一些常见的文件魔数.
魔数 | 文件扩展名 | 描述 |
---|---|---|
ED AB EE DB | rpm | RedHat Package Manager (RPM) package |
53 50 30 31 | bin | Amazon Kindle Update Package |
42 5A 68 | bz2 | Compressed file using Bzip2 algorithm |
CA FE BA BE | class | Java class file, Mach-O Fat Binary |
25 50 44 46 2D | PDF document | |
43 44 30 30 31 | iso | ISO9660 CD/DVD image file |
6B 6F 6C 79 | dmg | Apple Disk Image file |
66 74 79 70 69 73 6F 6D | mp4 | ISO Base Media file (MPEG-4) |
7F 45 4C 46 | Executable and Linkable Format | |
89 50 4E 47 0D 0A 1A 0A | png | Image encoded in the Portable Network Graphics format |
所以, 给我们一个文件, 我们只需读取文件最开始的很小一部分, 然后将读出的内容跟协议规范中文件魔数一一做对比, 当匹配上某个魔数时, 就说明该文件就是那个类型.
下面以解析一个ELF文件为例
3. 解析ELF文件
首先, 用工具倒出文件的内容, 不需要倒出太多.
# xxd工具, 可以用来倒出二进制文件的内容, -g 4是表示4个octet(8bit为一个octet)为一个组
[mg@vm201226 elf]$ xxd -g 4 1foo.o
00000000: 7f454c46 02010100 00000000 00000000 .ELF............
00000010: 01003e00 01000000 00000000 00000000 ..>.............
00000020: 00000000 00000000 98130000 00000000 ................
00000030: 00000000 40000000 00004000 15001400 ....@.....@.....
00000040: 554889e5 be000000 00bf0000 0000b800 UH..............
00000050: 000000e8 00000000 b8000000 005dc355 .............].U
00000060: 4889e58b 15000000 008b0500 00000001 H...............
00000070: c28b0500 00000001 d089c6bf 00000000 ................
00000080: b8000000 00e80000 0000b800 0000005d ...............]
...
...
可以看到, 开始的4个字节是 7f 45 4c 46
这既是ELF文件的魔数, 因此可以断定1foo.o是一个ELF文件.
当然ELF文件可以进一步细分为很多种, 比如可执行文件, core文件, ko文件, .o文件, .so文件. 进一步确认出是哪一种ELF文件, 就不是本篇文章所讨论的范围了.
4. 总结 (TLV模型)
一个文件本身就携带了描述它自身是什么文件类型的信息. 这个信息叫魔数, 存在于文件最开始处的几个字节中. 不同类型的文件, 魔数也不相同. 因此读取文件开头部分的一些字节, 就可以鉴别出文件是什么类型.
为什么文件开头要存放标识文件类型的魔数信息呢? 这是因为 "解析"本身就是一种 "TLV"模型的不断运用
.
"解析"本身就是一种 "TLV"模型的不断运用. 解析实际上就是将一片数据怎么切割成许多小的数据块, 然后分析出每个数据块是什么含义.
TLV模型, 即 “类型(Type) – 长度(Length) – 值(Value)” 模型.
T是指Type(类型), L是指Length(长度), V是指Value(值). Type信息一定是放在最前面的, 因为读取了Type, 就知道把这片数据强转成什么类型的结构体来接收. 知道了Length, 就知道一片的数据如何切割, 如何下刀. 从首地址开始, 到多长的范围是属于当前数据块的, 从多少开始是属于下一个数据块的. 然后V, 即数据块中存的内容. 只有知道了T和L, 才可能读出V, 否则没法解析出V.
前面数据的V记录着后面数据的T和L.
因此读取第一个数据的V, 可以知道第二个数据是什么数据, 它是什么类型, 占据多长的范围. 进而可以用什么类型的数据结构来强转和接收, 因此可以读出第二个数据的V. 第二个数据的V记录的是后面第三个数据的T和L, 进而解析出第三个数据, … 以次类推, 可以解析出所有数据.
不管是解析文件, 还是解析报文, 还是解析什么东西, 统统都是运用TLV模型.
更多推荐
所有评论(0)