摘要
Action Message Format (AMF) 是一种简洁的二进制格式,通常用于序列化ActionScript object graphs(对象图?不会翻译)。一旦序列化,AMF编码的对象图可用于会话之间持久化以及检索应用程序的公共状态,或者允许两个端通过强类型数据的交换进行通信。
AMF 0 Data Types
下方是AMF0的16种类型的marker。marker位占用一个字节长度,用于描述AMF中某种数据类型。
| marker | value | remark | |
|---|---|---|---|
| number-marker | 0x00 | ||
| boolean-marker | 0x01 | ||
| string-marker | 0x02 | ||
| object-marker | 0x03 | ||
| movieclip-marker | 0x04 | reserved, not supported | |
| null-marker | 0x05 | ||
| undefined-marker | 0x06 | ||
| reference-marker | 0x07 | ||
| ecma-array-marker | 0x08 | ||
| object-end-marker | 0x09 | ||
| strict-array-marker | 0x0A | ||
| date-marker | 0x0B | ||
| long-string-marker | 0x0C | ||
| unsupported-marker | 0x0D | ||
| recordset-marker | 0x0E | reserved, not supported | |
| xml-document-marker | 0x0F | ||
| typed-object-marker | 0x10 |
抓包分析
因为AMF0采用的是 big endian (network) byte order,所以先简单看看什么是big endian。
int val = 0x1234;
big endian:
低地址 0------->1------->2 高地址
+--------+--------+
| 0x12 | 0x34 |
+--------+--------+
little endian:
+--------+--------+
| 0x34 | 0x12 |
+--------+--------+
- Number
number-type = number-marker DOUBLE

Number
Number的marker为0x00,紫框是Number的数值,为40 08 00 00 00 00 00 00,我的电脑是little endian的所以我在内存里面看到的相应的数值是00 00 00 00 00 00 08 40。我们可以看一下rtmpdump的实现
char *AMF_EncodeNumber(char *output, char *outend, double dVal)
{
unsigned char *ci, *co;
ci = (unsigned char *)&dVal;
co = (unsigned char *)output;
co[0] = ci[7];
co[1] = ci[6];
co[2] = ci[5];
co[3] = ci[4];
co[4] = ci[3];
co[5] = ci[2];
co[6] = ci[1];
co[7] = ci[0];
}
- Boolean
boolean-type = boolean-marker U8 ; 0 is false, <> 0 is true

Boolean
Boolean的marker为0x01,紫框是Boolean的数值,为0x01,理论上只要非零就是truertmpdump的实现
char * AMF_EncodeBoolean(char *output, char *outend, int bVal)
{
*output++ = AMF_BOOLEAN;
*output++ = bVal ? 0x01 : 0x00;
return output;
}
- String
string-type = string-marker UTF-8

String
String的marker为0x02,绿框是字符串的长度,值为0x0008,紫框是String的值,为onStatus的ASCII码。rtmpdump的实现
char *AMF_EncodeString(char *output, char *outend, const AVal *bv)
{
*output++ = AMF_STRING;
output = AMF_EncodeInt16(output, outend, bv->av_len);
memcpy(output, bv->av_val, bv->av_len);
output += bv->av_len;
return output;
}
- Object
object-property = (UTF-8 value-type) | (UTF-8-empty object-end-marker)
anonymous-object-type = object-marker *(object-property)
Object类型除了可以包含其他类型之外,也可以包含Object类型。

image.png
Object是以Object-End结束的,值为0x000009。
Thanks
- rtmpdump,简直是入门引路者
最终目标是实现RTMP协议。还好前方有大量牛人实现过,感觉造轮子的时候,可以抄一下=。=
简单地实现了一下,代码地址->amf0