关于hexdec()、pack()等函数的研究分析
先看一段简单的代码
<?php function Exec_Hex($data) { $len = strlen($data); for($i=0;$i < $len;$i+=2){ $newdata.=pack("C",hexdec(substr($data,$i,2))); } return $newdata; } $c_name = Exec_Hex('7777772e74686973646f6f722e636f6d'); echo $c_name; ?>
hexdec — 十六进制转换为十进制"; pack把数据装入一个二进制字符串";
$newdata.=pack("C",hexdec(substr($data,$i,2)));
等价于:
$newdata = $newdata . pack("C",hexdec(substr($data,$i,2)));
最终输出的字符串就是www.thisdoor.com 能找到这个网址的相信你已经知道这个网址是干嘛的了,这就是一个后门提交的网址。 hexdec很好理解 pack下有很多可以说明的问题,用途也很广泛,记录一下,留着以后研究:
pack–压缩资料到位字符串之中。 语法:string pack(string format, mixed [args]…); 参数一:format参数表示资料用什么方式读取到 参数二:将要压缩的资料。
参数一 的种类 a 将字符串空白以 NULL 字符填满 A 将字符串空白以 SPACE 字符 (空格) 填满 h 十六进位字符串,低位在前 H 十六进位字符串,高位在前 c 有号字符 C 无号字符 s 有号短整数 (十六位,依计算机的位顺序) S 无号短整数 (十六位,依计算机的位顺序) n 无号短整数 (十六位, 高位在后的顺序) v 无号短整数 (十六位, 低位在后的顺序) i 有号整数 (依计算机的顺序及范围) I 无号整数 (依计算机的顺序及范围) l 有号长整数 (卅二位,依计算机的位顺序) L 无号长整数 (卅二位,依计算机的位顺序) N 无号短整数 (卅二位, 高位在后的顺序) V 无号短整数 (卅二位, 低位在后的顺序) f 单精确浮点数 (依计算机的范围) d 倍精确浮点数 (依计算机的范围) x 空位 X 倒回一位 @ 填入 NULL 字符到绝对位置
上面参数一得总结来自于网络,不知道是哪个翻译翻得,总之我个人不推荐看。下面是php手册上面的内容(全英文的,虽然我也看不懂,但是一个单词一个单词的翻译去理解,也比看上面的翻译强)
a — NUL-padded string A — SPACE-padded string h — Hex string, low nibble first H — Hex string, high nibble first c — signed char C — unsigned char s — signed short (always 16 bit, machine byte order) S — unsigned short (always 16 bit, machine byte order) n — unsigned short (always 16 bit, big endian byte order) v — unsigned short (always 16 bit, little endian byte order) i — signed integer (machine dependent size and byte order) I — unsigned integer (machine dependent size and byte order) l — signed long (always 32 bit, machine byte order) L — unsigned long (always 32 bit, machine byte order) N — unsigned long (always 32 bit, big endian byte order) V — unsigned long (always 32 bit, little endian byte order) f — float (machine dependent size and representation) d — double (machine dependent size and representation) x — NUL byte X — Back up one byte @ — NUL-fill to absolute position
====================H 和 h======================== ————————-H — h —————————— 先看中文翻译 H 十六进位字符串,高位在前 h 十六进位字符串,低位在前
再看英文 h — Hex string, low nibble first 十六进制,低位在前以半字节为单位(上面的翻译少了半字节,这个半字节很重要,nibble就是半字节的意思) H — Hex string, high nibble first 十六进制,高位在前以半字节为单位
方法:先转换为十进制,再转换为十六进制。进行pack方法的H前,必须先将字节补充完整。
H是一次是4位的读取,一个十六位进制是占4位,所以H是一次4位,H2是一次8位(即一个字节)。 echo pack("H",0×4); echo pack("H2",65); echo pack("H2",0×41); echo pack("H2",”41“); echo pack("H2H2", 0×41, 0×42); echo pack("h2h2", 0×41,0×42); ` echo pack("H3", 124); echo pack("h3",124);
输出如下 @ e e A ef Vf


//第一行:pack("H",0×4);将一个十六进制(4位)以十六进制的方式读取然后写入到字符串中。因为0×4是4位, 0×4转化为十进制为4。而一个字节是8位,所以会自动补充位一个字节8位的长度,后面4位补充为0000(记住!但凡要进行pack方法的H前,必须先将字节补充完整)。所以十进制为40(为什么要转化为十进制去在读取,我也不知道,可能pack方法开发者就是这么写的),十进制40以H十六进制的方式读取,就是0×40,转换成ascii码就为@。
//第二行:pack("H2",65);65是十进制(H默认是读取读取十进制,以十六进制的方式读取),所以65被H后为0×65,转化为ascii码就是e。
//第三行:pack("H2",0×41);0×41是十六进制,H2表示一次读取8位(H默认是读取读取十进制,以十六进制的方式读取),0×41转化为十进制为65,65被H后为0×65,转化为ascii码就是e。
//第四行:pack("H2",”41“);"41"为字符串,H2表示读取1个8位,但是(H默认是读取读取十进制,以十六进制的方式读取,所以字符串41就被H默认转换为十进制41),十进制41被H后为0×41,转化为ascii码就是A。
//第五行:pack("H2H2", 0×41, 0×42);0×41和0×42一共是十六位,H2H2表示读取两个8位,转化为十进制为65和66,65被H后就是0×65,66被H就是0×66,转化为ascii码就是分别是ef。
//第六行:pack("h2h2", 0×41,0×42);0×41和0×42是两个八位,h十六进位字符串,低位在前。h和H是几乎是一样的只是一个前后排序的问题。H是高位在前,h是低位在前。0×41和0×42转化为十进制65和66,。这里读取后跟H不一样,h是低位在前,H是高位在前。这里来做一个比较,如下:
读取前十六进制 0×41 0×42 读取前十进制 65 66 H读取后十六进制 0×65 0×66 h读取后十六进制 0×56 0×66 H读取后二进制 01100101 01100110 高位在前 以一次H读取对象为基础,4位为单位,进行高低互换 h读取后二进制 01010110 01100110 低位在前 以一次h读取对象为基础,4位为单位,进行高低互换
h按16进制读取后分别为二进制01010110和01100110转化为十六进制56和66,转化为ascii码为Vf。
//第七行:pack("H3", 124);因为要首先要将字节补充完整,因此补充完整后为1240。1240是十进制(H默认是读取读取十进制,以十六进制的方式读取),所以1240被H以后打到的是0×1240,转换为2进制的话就为0001 0010 0100 0000,转换为16进制就是0×1240,而浏览器这里是以ascii码读取的,所以是8位一次的翻译,所以0×1240被分割成0×12和0×40,0×40是@,0×12在ascii表里可以看到是(device control 2) 设备控制2,这个东西在ie8中显示出来就是上下双向箭头。而在ie6,ie7浏览器上因为使用的不同的编码方式,而显示出不同的字符。
//第八行:pack("h3",124);因为h是低位在前,而且又是1个半字节(记住!但凡要进行pack方法的H前,必须先将字节补充完整),然后再,我们来对比一下h与H, 读取前十六进制 0x7C 读取前十进制 1240 H读取后十六进制 0×1240 h读取后十六进制 0×0421 H读取后二进制 0001001001000000 高位在前 以一次H读取对象为基础,4位为单位,进行高低互换 h读取后二进制 0000010000100001 低位在前 以一次h读取对象为基础,4位为单位,进行高低互换
0000 0100 0010 0001 或者 0×0421,分成0×04和0×21,在ie8中以ascii码表示出来就是如上所示
注意:
pack("H",0×41); 是不正确的,但不会报错
pack("HH",0×41); 是不正确的,会报名错,需要两个参考
pack("H*",0×41); 是正确的,为e。
=================V 和 N====v 和 n======================= ————————-V – N———————– 先看中文翻译 V 无号短整数 (卅二位, 低位在后的顺序) N 无号短整数 (卅二位, 高位在后的顺序)
再看英文 V — unsigned long (always 32 bit, little endian byte order) 无符号长整型(总是32位,低地址存放最低有效字节)(根据金山词霸的解释) N — unsigned long (always 32 bit, big endian byte order) 无符号长整形(总是32位,高地址存放最低有效字节)(根据金山词霸的解释)
下面解释 little endian 和 big endian big endian — 是指低地址存放最高有效字节 little endian — 是指低地址存放最低有效字节
比如:a = 0×05060708 0×05060708 高端<—低端
在BIG-ENDIAN的情况下存放为: 因为低端地址存放高端有效字,08是最低有效字放在高端地址 字节号 0 1 2 3 ··· ··· 低端地址 高端地址 —————————————–> 数据 05 06 07 08 ··· ···
在LITTLE-ENDIAN的情况下存放为: 因为低地址存放最低有效字节,08是最低有效字放在低端地址 字节号 0 1 2 3 ··· ··· 低端地址 高端地址 —————————————–> 数据 08 07 06 05 ··· ···
因为内存都是从低端地址读起,因为读取内存数据一般使用地址指针,读一个地址在加一个偏移量。所以这个内存little-endian 与 big-endian 决定了数据读取出来的顺序,并不是想上面那个中文翻译的那样子(什么低位在后的顺序,我是服了,翻译的真让我受不了)。
下面举几个V的例子 echo "1 ".pack("V",0x65666768696A6B);echo "<br />"; echo "2 ".pack("V",0x666768696A6B6C);echo "<br />"; echo "3 ".pack("V",0x6768696A6B6C6D);echo "<br />";
显示出来为 // kjih 01101011 01101010 01101001 01101000 // k j i h // lkji 01101100 01101011 01101010 01101001 // l k j i // mlkj 01101101 01101100 01101011 01101010 // m l k j
N的例子 echo "4 ".pack("N",0x65666768696A6B);echo "<br />"; echo "5 ".pack("N",0x666768696A6B6C);echo "<br />"; echo "6 ".pack("N",0x6768696A6B6C6D);echo "<br />";
显示出来为 // hijk 01101000 01101001 01101010 01101011 // h i j k // ijkl 01101001 01101010 01101011 01101100 // i j k l // jklm 01101010 01101011 01101100 01101101 // j k l m
——————-v – n—————- 先看中文翻译 v 无号短整数 (十六位, 低位在后的顺序) n 无号短整数 (十六位, 高位在后的顺序)
再看英文 v — unsigned short (always 16 bit, little endian byte order) 无符号短整型(总是16位,低地址存放最低有效字节)(根据金山词霸的解释) n — unsigned short (always 16 bit, big endian byte order) 无符号短整形(总是16位,高地址存放最低有效字节)(根据金山词霸的解释)
不用举例子了,这个跟V和N的区别就是16位和32位的区别。
——————-关于V – N溢出的问题————————–
================ a =================== 先看中文翻译 a 一个填充空的字节串
再看英文翻译
a NUL – padded string
下面是例子: echo pack("a",65)."<br />"; echo pack("a2",65)."<br />"; echo pack("a2",65,66)."<br />"; echo pack("a2a2",65,66)."<br />"; echo pack("a","65")."<br />"; echo pack("a2","65")."<br />"; echo pack("a",0×65)."<br />"; echo pack("a1",0×65)."<br />"; echo pack("a2",0×65)."<br />"; echo pack("a3",0×65)."<br />";
输出为: 6 65 "报错" 65 6 65 1 1 10 101
由上面例子可知,这个该死的a,是以十进制的方式读取的,不管是字符还是十六进制都是先转换为十进制读取的,a1是读取一位十进制(也不知道是多少位),a2是读取二位十进制(也不知道是多少位),a3是读取三位十进制(也不知道是多少位)。如果是十六进制,就先转换成十进制,如上面的0×65转换成101,然后用a3读取后显示出来就是101。
echo pack("cccc", 0×41, 0×42, 0×43, 0×44); // ABCD echo pack("cccc", 65, 66, 67, 68); // ABCD echo pack("c4", 0×41, 0×42, 0×43, 0×44); // ABCD echo pack("c4", 65, 66, 67, 68); // ABCD
下载地址: 自适应移动端全屏竖屏小姐姐视频播放网站源码 带会员中心全网VIP视频解析源码 |