Deserialization: Operates on a single serialized variable and converts it back to the value of PHP (Zval).
PHP serialization mode
When serializing, PHP stores the corresponding variables in the corresponding key values.
To serialize a class, deal with the code main file: Ext/standard/var.c, as follows.
Php_var_serialize_class () function:
static void Php_var_serialize_class (Smart_str *buf, Zval *struc, Zval *retval_ptr, HashTable *var_hash tsrmls_dc)/* * {{* /{... incomplete_class = Php_var_serialize_class_name (buf, Struc tsrmls_cc); ....
Php_var_serialize_class_name () function:
Static inline Zend_bool php_var_serialize_class_name (smart_str *buf, Zval *struc tsrmls_dc)/* * {{*/{Php_class_attribut ES; Php_set_class_attributes (STRUC); Smart_str_appendl (buf, "O:", 2); Smart_str_append_long (buf, (int) name_len); Smart_str_appendl (buf, ": \" ", 2); Smart_str_appendl (buf, class_name, Name_len); Smart_str_appendl (buf, "\": ", 2); Php_cleanup_class_attributes (); return incomplete_class; }
To serialize a class, PHP first serializes the class name. Format is
O: Class name Length: "Class name": Value: {} <?php class Test {public Function Show_one () {echo $this->one;} public Function Show_two () {Ech o "123"; } }
Example: If a class with a class name called Test does not have any variables defined, the result after serialization is as follows:
O:4: "Test": 0:{}
As we can see, the methods in this class do not appear in the serialized string, and the beginning of "serializing an object will save all variables of the object, but not the method of saving the object, only the name of the class will be saved." ”。
The more special serialization is the serialization of the Reference (&) in the array and the two assignments of the object itself after instantiation.
Here we use PHP Internal the example in book.
Example 1:
<?php/** * User:lonelyrain * DATE:16/9/14 * Time: PM 12:53 */$a = ["foo"]; $a [1] =& $a [0]; $s = serialize ($a); Print $s;
The serialization result of the above code is
A:2:{i:0;s:3: "foo"; i:1; R:2;}
The r:2 here; Part means "point to second value". What is the second value? The entire array represents the first value, (s:3: "foo") represents the second value.
<?php/** * User:lonelyrain * DATE:16/9/14 * Time: PM 12:53 * * $o = new StdClass; $o->foo = $o; $s = serialize ($o); Print $s;
The serialization result of the above code is
O:8: "StdClass": 1:{s:3: "foo"; r:1;}
The following are the types and key tables for the Zval
List of serialized key names: two assignments in Array (&): R; Object two times assignment: R; Null:n; True:b:1; false:b:0; LONG:I; Double:d; STRING:S/S; CLASS:C; array:a; Object:o;
Different attributes of a variable have different formats
Public:key; Protected: \0*\0key; Private: \0key\0;
To observe through an example:
<?php/** * User:lonelyrain * DATE:16/9/14 * Time: PM 12:53 */class Test {public $public = 1; protected $protected = 2; Private $private = 3; } $a = new Test (); $s = serialize ($a); Var_dump ($s);
Results:
"O:4:" Test ": 3:{s:6:" Public ", I:1;s:12:" *protected "; i:2;s:13:" Testprivate "; i:3;}"
Let's take a look at the relevant knowledge of deserialization. You should notice that the string corresponds to two keys, s and S.
There are some differences between serialize () and unserialize () processing. PHP source Serialize () is not related to the serialization is marked with S, but in the unserialize of the S key related processing, the following I put the relevant part of the code for readers reference.
Case ' S ': Goto yy10; ... yy10:yych = * (Yymarker = ++yycursor); if (Yych = = ': ') goto yy39; Goto Yy3; ... yy39:yych = *++yycursor; if (Yych = = ' + ') goto yy40; if (Yych <= '/') goto YY18; if (Yych <= ' 9 ') goto yy41; Goto Yy18; Case ' s ': Goto yy9; ... yy9:yych = * (Yymarker = ++yycursor); if (Yych = = ': ') goto yy46; Goto Yy3; ... yy46:yych = *++yycursor; if (Yych = = ' + ') goto yy47; if (Yych <= '/') goto YY18; if (Yych <= ' 9 ') goto yy48; Goto Yy18; ... ...
If you continue to look at the next code, you will find that s and S will find that two keys are handled exactly the same way.
If everyone looked at Phpcodz 10, which wrote A:1:{s:8: "Ryatsyne" To:8: "Ryatsyne": 0:{}} This can break
static public Function Safeunserialize ($serialized) {//Unserialize would return false for object declared with small CA P O//as well as if there are any WS between O And:if (is_string ($serialized) && Strpos ($serialized, "/") = = = False) {if (Strpos ($serialized, ' O: ') = = = = False) {//The easy case, nothing to worry on/let Unserialize D o The job return @unserialize ($serialized); } else if (! Preg_match ('/(^|;| {|}) o:[+\-0-9]+: "/', $serialized)") {//In case we do have the A string with o:in it,//It is not a true serialized Obje CT return @unserialize ($serialized); }} return false; }
This payload is invalidated in php5.6.23, see the following code
Yy48: ++yycursor; if ((Yylimit-yycursor) < 2) Yyfill (2); Yych = *yycursor; if (Yych <= '/') goto YY18; if (Yych <= ' 9 ') goto yy48; if (Yych >= '; ') goto yy18; Yych = *++yycursor; if (yych! = ' "') goto Yy18; ++yycursor; {size_t len, maxlen; char *str; len = parse_uiv (start + 2); maxlen = Max-yycursor; if (MaxLen < len) {*p = start + 2; return 0; } str = (char*) yycursor; Yycursor + = Len; if (* (yycursor)! = ' "') {*p = Yycursor; return 0; } if (* (Yycursor + 1)! = '; ') {*p = yycursor + 1; return 0;} Yycursor + = 2; *p = Yycursor; Init_pzval (*rval); Zval_stringl (*rval, str, Len, 1); return 1; }
A semicolon symbol check has been added to the code, and the tricky is invalid in this PHP version.
if (* (Yycursor + 1)! = '; ') {*p = yycursor + 1; return 0;} WDDX Serialization Mode
The essence of serialization is to save the value of the program in the appropriate format, so we can not only serialize it with the Serialize function above. PHP also provides another serialization format for Web Distributed data Exchange (WDDX). WDDX is a subset of XML, so a serialized string format that conforms to WDDX is XML-compliant.
Demo Code:
<?php/** * User:lonelyrain * DATE:16/9/14 * Time: PM 12:53 */$a = ["foo"]; $a [1] =& $a [0]; echo wddx_serialize_value ($a);?>
Results:
<wddxpacket version= ' 1.0 ' >
You can see that the $ A and the values previously handled by the Wddx_serialize_value () function are preserved, except for the format that is used by the serialize () function.
WDDX serialization of related functions:
Wddx_serialize_value: The single value is continuous. Wddx_serialize_vars: The multi-value continuum. Wddx_packet_start: Start a new WDDX packet. Wddx_packet_end: End of WDDX packet. Wddx_add_vars: The WDDX packet is continuously serialized. Wddx_deserialize: The WDDX envelope is continuously solved.
This article mainly describes the format of the serialized data, the next one will write PHP serialization of an important piece of content, PHP magic method and so on.
Reference:
PHP kernel
PHP string serialization and deserialization syntax parsing inconsistent security implications
PHP serialization and deserialization series [notation for 1]--php serialization format