端口扫描工具
初学python尝试做的一个端口扫描工具 ,下面直接上教程
需要使用到的python库
import threading
import tkinter as tk
from socket import *
实际上 这里只需导入Threading以及Socket库就可以了
但是个人原因 就写了一个简单的可视化界面,所以引用了Tkinter库
导入库的作用
引用库的作用:
Threading: 导入Threading库最核心的功能就是调用Thread类。
每个Threading对象代表一个线程,在每个线程中,
我们可以让程序处理所分配的不同任务,这就是最基本多线程编程。Threading对象
最重要的就是target参数,下文使用时会详细说明。
有关Threading的相关使用可以自行百度。
Socket:Socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,
对于文件用【打开】【读写】【关闭】模式来操作。
socket(套接字)是应用层与TCP/IP协议族通信的中间软件抽象层,
它是一组接口,将复杂的TCP/IP协议族隐藏在接口后面,
让socket去组织数据以符合指定的协议。
socket就是该模式的一个实现,
socket即是一种特殊的文件,一些socket函数就是对其进行的操作
(读/写IO、打开、关闭)。同样,下文使用具体介绍相关参数。
Scoket相关内容连接:http://t.zoukankan.com/Forever77-p-10966483.html
Tkinter:pytho常用的图形化库啦,这个网上有很多资料,这里就不过多说了。
全局使用的参数
lock = threading.Lock() # 确保 多个线程在共享资源的时候不会出现脏数据
threads = [] # 线程池
out22 = ''
Socket部分
def portscanner(host, port): //这里定义了一个函数名 参数是ip以及端口
global out22 //设置了一个全局变量 是字符串形式的 用来在可视化界面输出
try: //这里使用python中的异常处理 结合Socket使用
s = socket(AF_INET, SOCK_STREAM) // 创建基于TCP面向网络的的工作流程
s.connect((host, port)) //连接到host地址port端口的套接字 连接不上就返回error错误
lock.acquire() //调用Threading的方法 此方法用于获取锁,阻塞或非阻塞。
out22 += str(port) + " open\n" //连接上就将端口写入该字符串 提示信息是端口open
lock.release() //这里是释放锁 以便下一个线程获取锁开始执行
s.close() //关闭流程
except:
pass
//这里的作用是 当S.connect返回的时错误的时候 表示目标端口并没有开放,不执行直接跳过
Threading部分
//因为代码是在主要方法里面 这里单拿出解释 后面会放完整代码
for port in ports: //使用for循环读入所有的端口范围
t = threading.Thread(target=portscanner, args=(ip, port))
//创建线程 方法是Socke部分 传入的参数是ip地址以及端口
threads.append(t) //将线程追加到线程池
t.start() //这里开始线程
for t in threads: //for循环多线程
t.join() //执行线程
Tkinter部分
root = tk.Tk() //导入库设置了别名tk 这里是定义root为Tk方法的别名
root.title('XSCAN小工具') //设置可视化界面的标题 当然你可以改成你自己的
screenWidth = root.winfo_screenwidth() //获取屏幕分辨率 宽度
screenHeight = root.winfo_screenheight() //获取屏幕分辨率 高度
x = int((screenWidth - 300) / 2)
y = int((screenHeight - 400) / 2) //屏幕高宽取半 获取中心位置
root.geometry(f'300x400+{x}+{y}') //设置可视化界面的大小 设置坐标为居中
root.anchor('center') //模块居中 跟随窗口变化
in1 = tk.Label(root, text='请输入你要扫描的ip', font=('华文行楷', 20, 'bold'), fg='red', anchor='center')
in1.grid(row=1, column=0, sticky='N')
en1 = tk.Entry(root, width=20)
en1.grid(row=3, column=0, sticky='N')
in2 = tk.Label(root, text='输入端口\n默认全扫描', font=('华文行楷', 15, 'bold'), fg='red', anchor='center')
in2.grid(row=5, column=0, sticky='N')
en2 = tk.Entry(root, width=20)
en2.grid(row=7, column=0, sticky='N')
//以上是设置的提示模块以及输入模块 具体可百度
AnNiu = tk.Button(root, text='提交', fg='blue', bd=2, width=10, command=main)
AnNiu.grid(row=10, column=0, sticky='N')
//设置了一个提交按钮 提交后 将输入模块的值传给主方法
out3 = tk.Text(root, width=20, height=15)
//输出界面 这里定义一个空内容 用于读取成功扫描的端口
out3.grid(row=15, column=0, columnspan=7, sticky='N', )
root.mainloop() //执行界面 本人第一次接触的就是grid布局 喜欢用pack的也可以自行参考修改
主方法部分
def main():
global out2, out22, out3 //设置三个全局变量 用来接收和输出在可视化界面的数据
out22='' //每次设置为空 避免可视化界面不刷新输出数据
out3.configure(state="normal") //状态设置为正常 可删除修改添加 便于更新输出界面数据
out3.delete(0.0,'end') //从开始删除数据 即清空上一次操作可视化界面输出的数据
ip = en1.get() //get获取变量本身的值 这里是可视化界面传过来的要扫描的目标地址
putport = en2.get() //get获取变量本身的值 这里是可视化界面传过来的要扫描的目标端口
if putport == '': //判断是否有指定端口和端口范围 没有指定就默认全扫描
ports = range(65535) //默认端口扫描范围为全部端口
else: //有输入端口的情况
getport = putport.split(',') //因为传入端口是字符串 多端口用逗号间隔 这里分割放进列表
ports = [] //定义一个空的列表 作用是 提取传入端口中如果有指定范围
for port in getport: //for循环端口 查找是否有指定端口范围 ps:端口范围例子:1-10
if port.find('-') != -1: //匹配到为1 没匹配到为-1
port = range(int(port.split('-')[0]), int(port.split('-')[-1]+1))
//匹配到后 将范围开始和结束提取放进range中 因为结尾会少一个 所以结束的值要加1
for num in port:
//因为直接列表中添加range 输出会不生效 且报错 所以逐个添加进新列表
ports.append(num) //将指定范围所有端口添加新列表
else:
ports.append(int(port)) //如果没有匹配 强转为int类型 放进列表
ports.sort() //将得到的列表排序
for port in ports: //这里是之前所提到的Threading部分 可自行去上文查看
t = threading.Thread(target=portscanner, args=(ip, port))
threads.append(t)
t.start()
for t in threads:
t.join() //线程结束之前 不会执行下面的语句 下面语句所使用的数据在Socket部分
out3.insert('end', out22) //将成功的字符串添加进输出界面
out3.configure(state="disabled") //输出界面状态改为不可用 即禁止修改
完整代码
import threading
import tkinter as tk
from socket import *
lock = threading.Lock() # 确保 多个线程在共享资源的时候不会出现脏数据
threads = [] # 线程池
out22 = ''
def portscanner(host, port):
global out22
try:
s = socket(AF_INET, SOCK_STREAM)
s.connect((host, port))
lock.acquire()
openNum += 1
out22 += str(port) + " open\n"
lock.release()
s.close()
except:
pass
def main():
global out22, out3
out22=''
out3.configure(state="normal")
out3.delete(0.0,'end')
ip = en1.get()
putport = en2.get()
if putport == '':
ports = range(65535)
else:
getport = putport.split(',')
ports = []
for port in getport:
if port.find('-') != -1:
port = range(int(port.split('-')[0]), int(port.split('-')[-1]))
for num in port:
ports.append(num)
else:
ports.append(int(port))
for port in ports:
t = threading.Thread(target=portscanner, args=(ip, port))
threads.append(t)
t.start()
for t in threads:
t.join()
out3.insert('end', out22)
out3.configure(state="disabled")
if __name__ == '__main__':
root = tk.Tk()
root.title('XSCAN小工具')
screenWidth = root.winfo_screenwidth()
screenHeight = root.winfo_screenheight()
x = int((screenWidth - 300) / 2)
y = int((screenHeight - 400) / 2)
root.geometry(f'300x400+{x}+{y}')
root.anchor('center')
in1 = tk.Label(root, text='请输入你要扫描的ip', font=('华文行楷', 20, 'bold'), fg='red', anchor='center')
in1.grid(row=1, column=0, sticky='N')
en1 = tk.Entry(root, width=20)
en1.grid(row=3, column=0, sticky='N')
in2 = tk.Label(root, text='输入端口\n默认全扫描', font=('华文行楷', 15, 'bold'), fg='red', anchor='center')
in2.grid(row=5, column=0, sticky='N')
en2 = tk.Entry(root, width=20)
en2.grid(row=7, column=0, sticky='N')
AnNiu = tk.Button(root, text='提交', fg='blue', bd=2, width=10, command=main)
AnNiu.grid(row=10, column=0, sticky='N')
out3 = tk.Text(root, width=20, height=15)
out3.grid(row=15, column=0, columnspan=7, sticky='N', )
root.mainloop()
结尾
因为本人是网络安全专业的,对于开发也是粗略的学习了一些,
该代码还存在许多bug 以及功能不够全面等等问题。
欢迎大家指出不足的部分和给予宝贵的意见以及建议!!