4

我最近一直在尝试学习 python,但遇到了一些我很难理解它是如何工作的东西。首先,它是一个列表的设计。

有问题的列表来自这篇关于简单模糊测试工具的安全文章:http: //blog.securestate.com/post/2009/10/06/How-a-simple-python-fuzzer-brought-down-SMBv2- in-2-seconds.aspx

有问题的实际列表是:

#Negotiate Protocol Request
packet = [chr(int(a, 16)) for a in """
00 00 00 90
ff 53 4d 42 72 00 00 00 00 18 53 c8 00 00 00 00
00 00 00 00 00 00 00 00 ff ff ff fe 00 00 00 00
00 6d 00 02 50 43 20 4e 45 54 57 4f 52 4b 20 50
52 4f 47 52 41 4d 20 31 2e 30 00 02 4c 41 4e 4d
41 4e 31 2e 30 00 02 57 69 6e 64 6f 77 73 20 66
6f 72 20 57 6f 72 6b 67 72 6f 75 70 73 20 33 2e
31 61 00 02 4c 4d 31 2e 32 58 30 30 32 00 02 4c
41 4e 4d 41 4e 32 2e 31 00 02 4e 54 20 4c 4d 20
30 2e 31 32 00 02 53 4d 42 20 32 2e 30 30 32 00
""".split()]

他使用以下几行从中提取了一个字节(我认为?):

what = packet[:]
where = choice(range(len(packet)))
which = chr(choice(range(256)))
what[where] = which

我从未见过以这种方式设计的列表,而且似乎无法理解它是如何选择它所做的任何事情的。最让我困惑的是packet = [chr(int(a, 16)) for a in """,他将所有这些东西都放在了一个评论区中......然后确实如此.split()。0_o

我知道这是一个模糊的问题,但如果有人可以向我解释这一点,或者向我指出一些解释这种列表构建风格的文档的方向,我会非常高兴。这看起来是一种非常有效的存储/提取大量字节的方法。

4

5 回答 5

10

"""
00 00 00 90
ff 53 4d 42 72 00 00 00 00 18 53 c8 00 00 00 00
00 00 00 00 00 00 00 00 ff ff ff fe 00 00 00 00
00 6d 00 02 50 43 20 4e 45 54 57 4f 52 4b 20 50
52 4f 47 52 41 4d 20 31 2e 30 00 02 4c 41 4e 4d
41 4e 31 2e 30 00 02 57 69 6e 64 6f 77 73 20 66
6f 72 20 57 6f 72 6b 67 72 6f 75 70 73 20 33 2e
31 61 00 02 4c 4d 31 2e 32 58 30 30 32 00 02 4c
41 4e 4d 41 4e 32 2e 31 00 02 4e 54 20 4c 4d 20
30 2e 31 32 00 02 53 4d 42 20 32 2e 30 30 32 00
"""

只是多行字符串

"""
00 00 00 90
ff 53 4d 42 72 00 00 00 00 18 53 c8 00 00 00 00
""".split()

使用上述字符串的空格生成拆分:

['00', '00', '00', '90', 'ff', '53', '4d', '42', '72', '00', '00', '00', '00', '18', '53', 'c8', '00', '00', '00', '00']

还有这个:

[chr(int(a, 16)) for a in ['00', '00', '00', '90', 'ff', '53', '4d', '42', '72', '00', '00', '00', '00', '18', '53', 'c8', '00', '00', '00', '00']]

是一个列表推导,它遍历形成的列表并转换适用chr(int(a,16))于每个的所有值a

int(a,16)将包含十六进制字符串表示形式的字符串转换为int.

chr将此整数转换为 char。

结果是:

>>> [chr(int(a, 16)) for a in ['00', '00', '00', '90', 'ff', '53', '4d', '42', '72', '00', '00', '00', '00', '18', '53', 'c8', '00', '00', '00', '00']]
['\x00', '\x00', '\x00', '\x90', '\xff', 'S', 'M', 'B', 'r', '\x00', '\x00', '\x00', '\x00', '\x18', 'S', '\xc8', '\x00', '\x00', '\x00', '\x00']
于 2012-05-14T19:44:42.107 回答
2

   """
content
"""

格式是在 python 中定义多行字符串文字的简单方法。这不是评论区。

[chr(int(a, 16)) for a in "00 00 00...".split()]是一个列表理解。大字符串被分割成一个数组(由空格分割),并且对于数组中的每个项目,它将它转换为一个十六进制数(int(a,16)意味着将字符串 a 转换为 int,字符串 a 以 16 为基数),然后返回该 ascii char ( chr(...)) 由该整数表示。

packet[:]返回list的浅表副本packet

choice(range(len(packet)))返回一个在数据包长度范围内的随机数。

chr(choice(range(256)))在 0,255 范围内选择一个随机数并将其解释为 ascii 字符,然后最后一条语句将该 ascii 字符插入随机选择的位置。

于 2012-05-14T19:44:01.140 回答
2

让我们分解它,并简化它以提高可读性:

    bytes = """
            00 00 00 90
            ff 53 4d 42 72 00 00 00 00 18 53 c8 00 00 00 00
            00 00 00 00 00 00 00 00 ff ff ff fe 00 00 00 00
            00 6d 00 02 50 43 20 4e 45 54 57 4f 52 4b 20 50
            52 4f 47 52 41 4d 20 31 2e 30 00 02 4c 41 4e 4d
            41 4e 31 2e 30 00 02 57 69 6e 64 6f 77 73 20 66
            6f 72 20 57 6f 72 6b 67 72 6f 75 70 73 20 33 2e
            31 61 00 02 4c 4d 31 2e 32 58 30 30 32 00 02 4c
            41 4e 4d 41 4e 32 2e 31 00 02 4e 54 20 4c 4d 20
            30 2e 31 32 00 02 53 4d 42 20 32 2e 30 30 32 00
            """
    packet = [chr(int(a, 16)) for a in bytes.split()]

bytes是一个字符串,"""通常用于 Python 文档字符串,但您可以在代码中使用它们来创建非常长的字符串(但它们有点糟糕,因为您最终会在代码中添加额外的空格。

bytes.split()将在空白处拆分,并返回以空格分隔的字符串各个部分的列表。

print bytes.split()

['00', '00', '00', '90', 'ff', '53', '4d', '42', '72', 
 '00', '00', '00', '00', '18', '53', 'c8', '00', '00' ... ] # and more

那么这个:

packet = [chr(int(a, 16)) for a in bytes.split()]

这是一个列表理解:

  • 拆分bytes并获取上述列表
  • 对于列表中的每个元素(a此处),对其执行int(a,16),这将通过进行 base-16 到十进制转换(即FF255)来获得其整数值。
  • 然后chr对该值执行操作,这将为您返回该字节的 ASCII 值。

packetASCII 格式的字节列表也是如此。

print packet
['\x00', '\x00', '\x00', '\x90', '\xff', 'S', 'M', 'B', 'r', '\x00', '\x00', '\x00',
 '\x00', '\x18', 'S', '\xc8', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 
 '\x00', '\x00', '\x00', '\x00', '\x00', '\xff', '\xff', '\xff', '\xfe', '\x00', 
 '\x00', '\x00', '\x00', '\x00', 'm', '\x00', '\x02', 'P', 'C', ' ', 'N', 'E', 'T', 
 'W', 'O', 'R', 'K', ' ', 'P', 'R', 'O', 'G', 'R', 'A', 'M', ' ', '1', '.', '0', 
 '\x00', '\x02', 'L', 'A', 'N', 'M', 'A', 'N', '1', '.', '0', '\x00', '\x02', 'W', 'i', 
 'n', 'd', 'o', 'w', 's', ' ', 'f', 'o', 'r', ' ', 'W', 'o', 'r', 'k', 'g', 'r', 'o', 
 ... more ]
于 2012-05-14T19:49:42.403 回答
1

您在这里遇到了几个不同的概念。慢慢往回走,你就会明白的。

"""00 00 00 90 ff 53 4d 42 72 00 00 00 00 18 53 c8 00 00 00 00""" 东西只是一个大字符串。它上面的 .split 将其分解为空格上的数组,所以此时你有类似 ['00', '00', '00', '90' ....]

该行的其余部分是一个列表理解——它是这样做的一种奇特方式:

new_list = []
for a in that_list_we_split_above:
    new_list.append( chr( int(a, 16) ) )

int 函数将字符串转换为基数为 16 的 int - http://docs.python.org/library/functions.html#int

然后 chr 函数使用该数字获取 ascii 字符

所以在所有废话的最后你有一个列表“数据包”

定义 where 的行获取该列表的长度,创建一个新列表,其中包含从 0 到长度的每个数字(即,每个可能的索引),并随机选择其中一个。

选择 0 到 256 之间的随机 int 并为其获取 ascii 字符的行

最后一行将包列表中“where”索引处的项目替换为其中定义的随机 ascii 字符

tl;博士:去寻找不同的代码来学习 - 这既令人困惑又没有灵感

于 2012-05-14T19:47:52.607 回答
0

有问题的代码示例似乎将原始数据包中的随机选择的字节替换为另一个随机字节(我相信这是模糊测试背后的想法之一。)

packet = [chr(int(a, 16)) for a in """
 00 00 00 90 .... """.split()]

这是“在空格上拆分字符串,将子字符串读取为从十六进制整数解码的字符(int 的第二个参数是基数)。

what = packet[:]

packet用于“将数组复制到what”的 Python 习语。

where = choice(range(len(packet)))

在数据包中选择一个随机索引。

which = chr(choice(range(256)))

制作一个随机字符。

what[where] = which 

将其替换为先前选择的索引。

于 2012-05-14T19:48:37.487 回答