我最近一直试图学习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
我知道这是一个模糊的问题,但是如果有人能够向我解释这一点,或者指向一些解释列表构建方式的文档的方向,我会特别高兴。这看起来像是一种非常有效的存储/提取大量字节的方法。
答案 0 :(得分: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']]
是list comprehension,它会浏览已形成的列表,并将应用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']
答案 1 :(得分:2)
"""
content
"""
format是在python中定义多行字符串文字的简单方法。这是不评论块。
[chr(int(a, 16)) for a in "00 00 00...".split()]
是列表理解。大字符串被拆分为一个数组(按空格分割),对于数组中的每个项目,它将其转换为十六进制数字(int(a,16)
表示将字符串a转换为int,字符串a在基数16中)然后返回由该整数表示的ascii char(chr(...)
)。
packet[:]
会返回列表packet
的{{3}}。
choice(range(len(packet)))
返回包长度范围内的随机数。
chr(choice(range(256)))
选择0,255范围内的随机数并将其解释为ascii char,然后最终语句将ascii char插入随机选择的位置。
答案 2 :(得分: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到十进制转换获得其整数值(即FF
将是255
)。chr
,这将返回该字节的ASCII值。因此packet
将是ASCII格式的字节列表。
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 ]
答案 3 :(得分: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字符所以在废话的最后你有一个列表'数据包'
定义在哪里获取该列表长度的行,创建一个新列表,其中包含从0到长度的每个数字(即,每个可能的索引),并随机选择其中一个。
在0到256之间选择一个随机int并在其中获取ascii字符的行
最后一行替换'where'索引的数据包列表中的项目,其中定义了随机的ascii字符
tl; dr:去寻找不同的代码来学习 - 这既困惑又缺乏灵感
答案 4 :(得分:0)
有问题的代码示例似乎用原始数据包中随机选择的字节替换另一个随机字节(我相信,这是模糊测试背后的一个想法。)
packet = [chr(int(a, 16)) for a in """
00 00 00 90 .... """.split()]
这是“在空格上拆分字符串,将子字符串读取为以十六进制整数解码的字符(int的第二个参数是基础)。
what = packet[:]
Python习惯用于“将packet
数组复制到what
”。
where = choice(range(len(packet)))
在数据包中选择一个随机索引。
which = chr(choice(range(256)))
制作一个随机字符。
what[where] = which
将其替换为先前选择的索引。