使用 Python 解压缩数据包的 gzip 有效载荷
Decompressing a gzipped payload of a packet with Python
我目前正在开发一个程序,该程序采用 .pcap 文件并使用 scapy 包通过 ip 分离出所有数据包。我想解压缩使用 gzip 包压缩的有效负载。我可以判断有效载荷是否被 gzip 压缩,因为它包含
Content-Encoding: gzip
我正在尝试使用
fileStream = StringIO.StringIO(payload)
gzipper = gzip.GzipFile(fileobj=fileStream)
data = gzipper.read()
解压缩负载,其中
payload = str(pkt[TCP].payload)
当我尝试执行此操作时出现错误
IOError: Not a gzipped file
当我打印第一个有效载荷时,我得到
HTTP/1.1 200 OK
Cache-Control: private, max-age=0
Content-Type: text/html; charset=utf-8
P3P: CP="NON UNI COM NAV STA LOC CURa DEVa PSAa PSDa OUR IND"
Vary: Accept-Encoding
Content-Encoding: gzip
Date: Sat, 30 Mar 2013 19:23:33 GMT
Content-Length: 15534
Connection: keep-alive
Set-Cookie: _FS=NU=1; domain=.bing.com; path=/
Set-Cookie: _SS=SID=F2652FD33DC443498CE043186458C3FC&C=20.0; domain=.bing.com; path=/
Set-Cookie: MUID=2961778241736E4F314E732240626EBE; expires=Mon, 30-Mar-2015 19:23:33 GMT; domain=.bing.com; path=/
Set-Cookie: MUIDB=2961778241736E4F314E732240626EBE; expires=Mon, 30-Mar-2015 19:23:33 GMT; path=/
Set-Cookie: OrigMUID=2961778241736E4F314E732240626EBE%2c532012b954b64747ae9b83e7ede66522; expires=Mon, 30-Mar-2015 19:23:33 GMT; domain=.bing.com; path=/
Set-Cookie: SRCHD=D=2758763&MS=2758763&AF=NOFORM; expires=Mon, 30-Mar-2015 19:23:33 GMT; domain=.bing.com; path=/
Set-Cookie: SRCHUID=V=2&GUID=02F43275DC7F435BB3DF3FD32E181F4D; expires=Mon, 30-Mar-2015 19:23:33 GMT; path=/
Set-Cookie: SRCHUSR=AUTOREDIR=0&GEOVAR=&DOB=20130330; expires=Mon, 30-Mar-2015 19:23:33 GMT; domain=.bing.com; path=/
?}k{?H????+0?#!?,_???$?:?7vf?w?Hb???ƊG???9???/9U?$;3{9g?ycAӗ???????W{?o?~?FZ?e ]>??<??n?????????????d?t??a?3?
?2?p??eBI?e??????ܒ?P??-?Q?-L?????ǼR?³?ׯ??%'
?2Kf?7???c?Y?I?1+c??,ae]?????<{?=ƞ,?^?J?ď???y??6O?_?z????_?ޞ~?_?????Bo%]???_?????W=?
有关其他信息,这是一个被隔离的数据包,因为它包含内容编码:项目提供的示例 .pcap 文件中的 gzip。
为了解码 gzip 压缩的 HTTP 响应,您只需要解码响应 body,而不是 headers.
您的 payload
是整个 TCP 负载,即整个 HTTP 消息,包括 headers 和 body。
HTTP 消息(请求和响应)是 RFC 822 消息(与 E-Mail 消息 (RFC 2822) 所基于的通用消息格式相同)。
822 消息的结构非常简单:
- 零个或多个 header 行(由
:
分隔的键/值对),由 CRLF 终止
- 一个空行(CRLF(回车return,换行,所以
'\r\n'
)
- 留言body
您现在可以自己解析此消息以隔离 body。但我更愿意推荐您使用 Python 已经为您提供的工具。 httplib
module (Python 2.x) includes the HTTPMessage
class 被 httplib
内部用来解析 HTTP 响应。它并不意味着可以直接使用,但在这种情况下我可能仍会使用它 - 它会为您处理一些 HTTP 特定的细节。
以下是如何使用它来将 body 与 header 分开:
>>> from httplib import HTTPMessage
>>>
>>> f = open('gzipped_response.payload')
>>>
>>> # Or, if you already have the payload in memory as a string:
... # f = StringIO.StringIO(payload)
...
>>> status_line = f.readline()
>>> msg = HTTPMessage(f, 0)
>>> body = msg.fp.read()
HTTPMessage
class 的工作方式与 rfc822.Message
类似:
首先,您需要阅读(或丢弃)状态行 (HTTP/1.1 200 OK
),因为那不是 RFC822 消息的一部分,也不是 header。
然后用打开文件的句柄实例化 HTTPMessage
,并将 seekable
参数设置为 0
。文件指针存储为msg.fp
- 在实例化时调用
msg.readheaders()
,读取所有 header 行,直到遇到空行 (CRLF)。
- 此时,
msg.fp
已经前进到 header 结束和 body 开始的位置。因此,您可以调用 msg.fp.read()
来阅读消息的其余部分 - body.
在那之后,您解压 gzipped body 的代码就可以工作了:
>>> body_stream = StringIO.StringIO(body)
>>> gzipper = gzip.GzipFile(fileobj=body_stream)
>>> data = gzipper.read()
>>>
>>> print data[:25]
<!DOCTYPE html>
<html>
我目前正在开发一个程序,该程序采用 .pcap 文件并使用 scapy 包通过 ip 分离出所有数据包。我想解压缩使用 gzip 包压缩的有效负载。我可以判断有效载荷是否被 gzip 压缩,因为它包含
Content-Encoding: gzip
我正在尝试使用
fileStream = StringIO.StringIO(payload)
gzipper = gzip.GzipFile(fileobj=fileStream)
data = gzipper.read()
解压缩负载,其中
payload = str(pkt[TCP].payload)
当我尝试执行此操作时出现错误
IOError: Not a gzipped file
当我打印第一个有效载荷时,我得到
HTTP/1.1 200 OK
Cache-Control: private, max-age=0
Content-Type: text/html; charset=utf-8
P3P: CP="NON UNI COM NAV STA LOC CURa DEVa PSAa PSDa OUR IND"
Vary: Accept-Encoding
Content-Encoding: gzip
Date: Sat, 30 Mar 2013 19:23:33 GMT
Content-Length: 15534
Connection: keep-alive
Set-Cookie: _FS=NU=1; domain=.bing.com; path=/
Set-Cookie: _SS=SID=F2652FD33DC443498CE043186458C3FC&C=20.0; domain=.bing.com; path=/
Set-Cookie: MUID=2961778241736E4F314E732240626EBE; expires=Mon, 30-Mar-2015 19:23:33 GMT; domain=.bing.com; path=/
Set-Cookie: MUIDB=2961778241736E4F314E732240626EBE; expires=Mon, 30-Mar-2015 19:23:33 GMT; path=/
Set-Cookie: OrigMUID=2961778241736E4F314E732240626EBE%2c532012b954b64747ae9b83e7ede66522; expires=Mon, 30-Mar-2015 19:23:33 GMT; domain=.bing.com; path=/
Set-Cookie: SRCHD=D=2758763&MS=2758763&AF=NOFORM; expires=Mon, 30-Mar-2015 19:23:33 GMT; domain=.bing.com; path=/
Set-Cookie: SRCHUID=V=2&GUID=02F43275DC7F435BB3DF3FD32E181F4D; expires=Mon, 30-Mar-2015 19:23:33 GMT; path=/
Set-Cookie: SRCHUSR=AUTOREDIR=0&GEOVAR=&DOB=20130330; expires=Mon, 30-Mar-2015 19:23:33 GMT; domain=.bing.com; path=/
?}k{?H????+0?#!?,_???$?:?7vf?w?Hb???ƊG???9???/9U?$;3{9g?ycAӗ???????W{?o?~?FZ?e ]>??<??n?????????????d?t??a?3?
?2?p??eBI?e??????ܒ?P??-?Q?-L?????ǼR?³?ׯ??%'
?2Kf?7???c?Y?I?1+c??,ae]?????<{?=ƞ,?^?J?ď???y??6O?_?z????_?ޞ~?_?????Bo%]???_?????W=?
有关其他信息,这是一个被隔离的数据包,因为它包含内容编码:项目提供的示例 .pcap 文件中的 gzip。
为了解码 gzip 压缩的 HTTP 响应,您只需要解码响应 body,而不是 headers.
您的 payload
是整个 TCP 负载,即整个 HTTP 消息,包括 headers 和 body。
HTTP 消息(请求和响应)是 RFC 822 消息(与 E-Mail 消息 (RFC 2822) 所基于的通用消息格式相同)。
822 消息的结构非常简单:
- 零个或多个 header 行(由
:
分隔的键/值对),由 CRLF 终止
- 一个空行(CRLF(回车return,换行,所以
'\r\n'
) - 留言body
您现在可以自己解析此消息以隔离 body。但我更愿意推荐您使用 Python 已经为您提供的工具。 httplib
module (Python 2.x) includes the HTTPMessage
class 被 httplib
内部用来解析 HTTP 响应。它并不意味着可以直接使用,但在这种情况下我可能仍会使用它 - 它会为您处理一些 HTTP 特定的细节。
以下是如何使用它来将 body 与 header 分开:
>>> from httplib import HTTPMessage
>>>
>>> f = open('gzipped_response.payload')
>>>
>>> # Or, if you already have the payload in memory as a string:
... # f = StringIO.StringIO(payload)
...
>>> status_line = f.readline()
>>> msg = HTTPMessage(f, 0)
>>> body = msg.fp.read()
HTTPMessage
class 的工作方式与 rfc822.Message
类似:
首先,您需要阅读(或丢弃)状态行 (
HTTP/1.1 200 OK
),因为那不是 RFC822 消息的一部分,也不是 header。然后用打开文件的句柄实例化
HTTPMessage
,并将seekable
参数设置为0
。文件指针存储为msg.fp
- 在实例化时调用
msg.readheaders()
,读取所有 header 行,直到遇到空行 (CRLF)。 - 此时,
msg.fp
已经前进到 header 结束和 body 开始的位置。因此,您可以调用msg.fp.read()
来阅读消息的其余部分 - body.
在那之后,您解压 gzipped body 的代码就可以工作了:
>>> body_stream = StringIO.StringIO(body)
>>> gzipper = gzip.GzipFile(fileobj=body_stream)
>>> data = gzipper.read()
>>>
>>> print data[:25]
<!DOCTYPE html>
<html>