python黑客学习之IP包嗅探

1、附上源码

import socket
import os
import struct
from ctypes import *

# 本地监听
host   = "127.0.0.1"

#IP头定义
class IP(Structure):

    _fields_ = [
        ("ihl",           c_ubyte, 4),
        ("version",       c_ubyte, 4),
        ("tos",           c_ubyte),
        ("len",           c_ushort),
        ("id",            c_ushort),
        ("offset",        c_ushort),
        ("ttl",           c_ubyte),
        ("protocol_num",  c_ubyte),
        ("sum",           c_ushort),
        ("src",           c_ulong),
        ("dst",           c_ulong)
    ]

    def __new__(self, socket_buffer=None):
        return self.from_buffer_copy(socket_buffer)    

    def __init__(self, socket_buffer=None):

        # 协议字段与协议名称对应
        self.protocol_map = {1:"ICMP", 6:"TCP", 17:"UDP"}

        # human readable IP addresses
        self.src_address = socket.inet_ntoa(struct.pack("<L",self.src))
        self.dst_address = socket.inet_ntoa(struct.pack("<L",self.dst))

        # human readable protocol
        try:
            self.protocol = self.protocol_map[self.protocol_num]
        except:
            self.protocol = str(self.protocol_num)

# Windows下嗅探所有数据包,Linux下嗅探ICMP数据包
if os.name == "nt":
    socket_protocol = socket.IPPROTO_IP 
else:
    socket_protocol = socket.IPPROTO_ICMP
    
sniffer = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket_protocol)

sniffer.bind((host, 0))

# we want the IP headers included in the capture
sniffer.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)

# Windows下要打开混杂模式
if os.name == "nt":
    sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)

try:
    while True:
    
        # 读取数据包
        raw_buffer = sniffer.recvfrom(65565)[0]
    
        # 读取前20字节
        ip_header = IP(raw_buffer[0:20])

        #输出协议和双方通信的IP地址    
        print "Protocol: %s %s -> %s" % (ip_header.protocol, ip_header.src_address, ip_header.dst_address)
        
except KeyboardInterrupt:

    if os.name == "nt":
        sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)

2、源码解读

ctype库

python的底层大部分都是C/C++实现,python赋予了黑客类似于c语言一样的底层操作能力,且不失动态语言的便捷;

python访问C/C++的方式很多(ctypes,pybind11,cffi,swig),但ctypes是最方便的;

ctype库提供了和C语言兼容的数据类型和函数来加载dll文件,因此在调用时不需对源文件做任何的修改。

用ctype库加载dll文件

import platform
from ctypes import *

if platform.system() == 'Windows':
    libc = cdll.LoadLibrary('msvcrt.dll')
elif platform.system() == 'Linux':
    libc = cdll.LoadLibrary('libc.so.6')

libc.printf('%s\n', 'here!')        
libc.printf('%S\n', u'there!')      

struct模块

可以按照指定格式将Python数据和字节流进行转换;可以处理c语言中的结构体。

structpack函数把任意数据类型变成bytes:

pack(fmt,v1,v2…)

按照给定的格式(fmt),把数据转换成字符串(字节流),并将该字符串返回.

struct.pack("<L",self.src)

<表示字节顺序是little-endian,即低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
L表示4字节无符号长整型

fmt格式——对齐方式

fmt格式——格式符

IP结构

Socket模块中一些IP转换函数

socket.ntohl(x)         // 类似于C语言的ntohl(x)

把32位正整数从网络序转换成主机字节序。

socket.ntohs(x)        // 类似于C语言的ntohs(x)

把16位正整数从网络序转换成主机字节序。

socket.htonl(x)         // 类似于C语言的htonl(x)

把32位正整数从主机字节序转换成网络序。

socket.htons(x)        // 类似于C语言的htons(x)

把16位正整数从主机字节序转换成网络序。

socket.inet_aton(ip_string)  // 依赖于inet_aton的C实现

转换IPV4地址字符串(192.168.10.8)成为32位打包的二进制格式(长度为4个字节的二进制字符串),它不支持IPV6。inet_pton()支持IPV4/IPV6地址格式。

socket.inet_ntoa(packed_ip)

转换32位打包的IPV4地址为IP地址的标准点号分隔字符串表示。

socket.inet_pton(address_family,ip_string)

转换IP地址字符串为打包二进制格式。地址家族为AF_INET和AF_INET6,它们分别表示IPV4和IPV6。

socket.inet_ntop(address_family,packed_ip)

转换一个打包IP地址为标准字符串表达式,例如:“5aef:2b::8”或“127.0.0.1”。
以上来自于https://blog.csdn.net/fan_hai_ping/article/details/8435140

猜你喜欢

转载自blog.csdn.net/xlsj228/article/details/91489633