python 抓包与解包

我使用的环境为:Windows10、python3.6、scapy 2.4.0
一、基本知识

Sniff方法定义:

sniff(filter="",iface="any", prn=function, count=N)

filter的规则使用 Berkeley Packet Filter (BPF)语法
iface用来指定要在哪个网络接口上进行抓包(通常不指定即所有网络接口)
prn指定回调函数,每当一个符合filter的报文被探测到时,就会执行回调函数,通常使用lambda表达式来写回调函数
count指定最多嗅探多少个报文(是指符合filter条件的报文,而非所有报文)


filter写法举例:

抓取源地址为 www.baidu.com 的报文:

>>> sniff(filter="ip src www.baidu.com", iface=ifs, prn=lambda x:x.summary(), count=3)

Ether / IP / TCP 14.215.177.39:https > 192.168.2.204:6593 A / Padding
Ether / IP / TCP 14.215.177.39:https > 192.168.2.204:6593 A / Padding
Ether / IP / TCP 14.215.177.39:https > 192.168.2.204:6593 A / Raw
Out[15]: 3 UDP:0 ICMP:0 Other:0>

抓取目的地址网段为192.168.2.204/24的报文,没有设置count,所以会一直输出:

>>> sniff(filter="dst net 192.168.2.204", iface=ifs, prn=lambda x:x.summary())

Ether / IP / TCP 180.97.162.191:8202 > 192.168.2.204:4963 PA / Raw
Ether / IP / TCP 180.97.162.191:8202 > 192.168.2.204:4963 PA / Raw
Ether / IP / TCP 180.97.162.191:8200 > 192.168.2.204:4967 PA / Raw / Padding
Ether / IP / TCP 180.97.162.191:8202 > 192.168.2.204:4963 PA / Raw
。。。

抓取非ICMP的报文:

>>> sniff(filter="not icmp", iface=ifs, prn=lambda x:x.summary(), count=3)

Ether / IP / TCP 192.168.2.204:4963 > 180.97.162.191:8202 A
Ether / IP / TCP 180.97.162.191:8202 > 192.168.2.204:4963 PA / Raw
Ether / IP / TCP 192.168.2.204:4962 > 180.97.162.191:8202 A
Out[9]: 3 UDP:0 ICMP:0 Other:0>



prn函数举例:
将抓取到的报文的summary打印出来:

>>> sniff(filter="", iface=ifs, prn=lambda x:x.summary(), count=3)
Ether / IP / TCP 180.97.162.191:8202 > 192.168.2.204:4963 PA / Raw
Ether / IP / TCP 192.168.2.204:4963 > 180.97.162.191:8202 A
Ether / IP / TCP 180.97.162.191:8202 > 192.168.2.204:4963 PA / Raw
3 UDP:0 ICMP:0 Other:0>




将所有IP报文的源地址打印出来:

>>> sniff(filter="", iface=ifs, prn=lambda x:x[IP].src, count=3)

180.97.162.191
192.168.2.204
14.215.177.39
3 UDP:0 ICMP:0 Other:0>


也可使用回调函数:

def packet_callback(packet):
    print packet.show()

sniff(prn=packet_callback, count=10)

二、代码示例

import os
from scapy.all import sniff,wrpcap,Raw,IP,TCP



def get_pcap(ifs,ip=None,size=100):
    ''' 获取指定 ifs(网卡), 指定数量size 的数据包;
        如果有指定ip,则这里只接收tcp,80端口,指定ip的包 '''
    filter = ""
    if ip:
        filter += "ip src %s and tcp and tcp port 80"%ip
        dpkt = sniff(iface=ifs,filter=filter,count=size)
    else:
        dpkt = sniff(iface=ifs,count=size)
    # wrpcap("pc1.pcap",dpkt) # 保存数据包到文件
    return dpkt


def get_ip_pcap(ifs,sender,size=100):
    ''' 获取指定 ifs(网卡), 指定发送方 sender(域名或ip) 的数据包
        size:(一次获取数据包的数量) '''
    if 'www.' in sender:
        v = os.popen('ping %s'%sender).read()
        ip = v.split()[8]
        print("准备接收IP为 %s 的数据包..."%ip)
    else:
        ip = sender
        print("准备接收IP为 %s 的数据包..."%ip)
    count = 0  
    while count<10:
        d = get_pcap(ifs,ip=sender,size=size)
        for i in d:
            try:
                if i[IP].src==ip: # 发送方的IP为:ip  接收方的IP:i[IP].dst==ip
                    print(i[Raw].load)
            except:
                pass
        count+=1



def main():
    ifs = 'Realtek PCIe GBE Family Controller' # 网卡
    ip = "116.4.8.127"  # ip地址,也可写域名,如:www.baidu.com
    get_ip_pcap(ifs,ip,size=1)  # 一次接收一个包

if __name__ =='__main__':
    main()

保存文件为:grab_unpack.py
然后打开网站页面,是一个动态刷新的图,效果如下:

执行:python grab_unpack.py
输出结果:
python 抓包与解包_第1张图片

其中最后面以 zx 为键的 json 数据就是我想要的数据,而这是ajax请求过来的数据,使用一般的爬虫是难以爬取到的

你可能感兴趣的:(python,python,抓包解包)