计算机存储字节方式以及存储计算
由一道CTF题目引入今天的主题。
[ACTF新生赛2020]crypto-des
本题给了一个压缩包,需要我们解密码才能打开。
1 | 72143238992041641000000.000000, |
这是我们需要解的密码,提示为
1 | To solve the key, Maybe you know some interesting data format about C language? |
我们引入数据转字节的方式。因为我们输入的数据,在内存中是存放在对应地址,每个地址代表一个字节空间。
比如int a = 5;
就是代表a所在的地址空间,以及向下,一共连续4个地址,都会存放5这个数,其实a就像数组名,代表了数组首地址。
为什么是连续4个地址,因为int型变量占4个字节。
比如我们输入字节
1 | b'abc' |
计算机会如何存储这个字节呢?既然已经是字节了,就是找到对应的数目,直接存储到计算机中。它会将其转换为字节型数据,先取ascii值,分别为97, 98, 99
, 然后将其看成256进制数,对应计算出
1 | 97*(256^2) + 98*(256) + 99 |
这种顺序的运算,我们称为大端序,因为得到256进制数,一个256进制数可以写成8位二进制数。所以上面就是3个字节,24位二进制数。
会把从最大位的字节数,也就是97对应的8位二进制数,存到最小的地址,然后把最小的8位,即99,放到最高位地址。即为大端序。
同理,小端序也就知道了。
注:网络传输中,采用大端序。
上述运算的处理结果就是平时我们可能会看到的
1 | bytes_to_long()函数或者libnum.s2n()或者binascii.unhexlify()等。 |
我们如何处理这个题目的数据,采用python的struct库
在python中,如果要把一个普通数转换为字节,
1 | 10240099 n = |
我们可以分析一下与运算,就是分别取出每个8位的数字,也就是取出每个字节的数字,对于16进制来说,两个16进制字符代表一个字节。所以取出高8位用
1 | b1 = (n & 0xff000000) >> 24 |
但是我们可以直接用struct库
1 | import struct |
>
表示字节顺序是big-endian,也就是网络序,I
表示4字节无符号整数。
unpack
把bytes
变成相应的数据类型
1 | '>IH', b'\xf0\xf0\xf0\xf0\x80\x80') struct.unpack( |
根据>IH
的说明,后面的bytes
依次变为I
:4字节无符号整数和H
:2字节无符号整数。
所以,尽管Python不适合编写底层操作字节流的代码,但在对性能要求不高的地方,利用struct
就方便多了。
1 | from libnum import* |
就可以得出两种端序下的结果。