关于hexdec()、pack()等函数的研究分析

来源:互联网 发布:淘宝热搜关键词 编辑:程序博客网 时间:2024/04/26 20:58

http://chenwei.me/p/57.html

先看一段简单的代码

    <?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 一个填充空的字节串

再看英文翻译
 

aNUL-padded stringaNUL-padded string

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

待续


原创粉丝点击