前言
在做sqli-labs的less-32及后几关时接触到了宽字节注入,就学习了以上四种编码方式并且进行了辨析,通过这篇博客以记录下来。
从ascii开始
我们都知道计算机只能识别0和1的二进制语言,因此当我们想要表示字母或者数字时需要一个规则进行转换,因此我们有了ascii字符集。但是ascii只用了7bits来表示字符,后来经过补充用8bits,这对英文来说足够了,可是世界上还有千千万万个其他文字,1个字节显然是不够的,因此,宽字符就出现了。
Unicode就起到了补充作用,事实上,Unicode对计算机全球化发展起到了巨大作用。因为各个国家之间都推出了各自的编码标准,这些标准没有一个统一值,例如gbk就是中国标准,只在中国使用,而Unicode把全球所有语言统一到了一个编码里。
Unicode与UTF-8&16
Unicode(UCS-2)编码遵循着中英文及其符号全部占用2个字节,如果是一个英文字母,其二进制表达为(以s为例):00000000 01110011
而一个汉字的二进制表达式为(以“日”字为例):01100101 11100101
在Unicode字符集中,一个字符对应的一个十六进制,我们可以发现英文的二进制码前9位全部都是0,占据两个字节实在是一种浪费,这时候UTF就派上用场了。
- 首先是UTF-8,对于英文字母这类单字节字符,UTF-8会将字节第一位设置为0,此时这个第一个0相当于代替了9个0,因此英文字符这类的字符只占用一个字节,与ascii码值完全相同。
- 而对于多个字节的字符,就要转换为多字节的UTF-8,而中文在UTF-8中属于三字节。UTF-8对于n个字节的编码方式为,第一个字节的前n位用1表示,第n+1位用0表示,后面字节的前两位用10表示。
那么s与日的UTF-8编码就是如下所示:s:01110011
日:11100110 10010111 10100101
是的,汉字在UTF-8中占据了3个字符,这就导致了在使用纯中文时反而消耗了更多的内存,因此对于纯中文UTF-8不是很友好。这时,我们把目光聚焦在UTF-16。
UTF-16的编码中字符一般占两个字节,因此有些人会将Unicode和UTF-16的概念混作一谈,这是错误的。但其实UTF-16编码的泛用性还是没有UTF-8广,因为UTF-16存在大小端字节序问题,容错率也更低。反观UTF-8局部的字节错误(丢失、增加、改变)不会导致连锁性的错误,因为UTF-8 的字符边界很容易检测出来。而url编码就是在uft-8编码的基础上,给编码的每个字节加上百分号。
这里给出不同编码方式的文件头:
1 | EF BB BF UTF-8 |
走近gbk
在了解gbk之前,我们要先了解GB2312,而在了解GB2312之前,我们先认识下区位码。区位码是1980年中国制定的编码标准,每一个字符都有一个对应的四位编号,前两位为“区”,后两位为“位”,而中文汉字的区码为16。
GB2312编码正是基于区位码用双字节编码表示中文的,编码方式一般为0xA0+区号 0xA0+位号
。而当编码对象是英文或数字时,一般情况下直接使用ascii编码。不过这里有个有意思的情况:
1 | 0x32 |
0x32自然是代表着2,那么下面那个根据GB2312编码的结果应该也为2,这两个2有什么区别呢?有,ascii码对应的2是半角字符,而GB2312编码的2是全角字符。
而gbk,即汉字国际扩展码,在GB2312的基础上进行了拓展,涵盖了Unicode中所有的汉字,因此也可以Unicode一一对应。和前面说到的GB2312不同,有的字的编码比0xA0 0xA0还小,但是其实只补充了计算机编码表,区位码是没有更新的。微软Windows安排给GBK的code page(代码页)是CP936,所以有时候看到编码格式是CP936,其实就是GBK的意思。
同一个编码文件里,高字节最高位为0则为ascii,为1则为中文。
总结
学习这些编码的原理,对于我们继续进行的靶场练习可以提供一定的帮助,了解到计算机是如何编码我们的文字的,不过这也算不顾正业一回了吧。