从 netstat -ano 到自研安全工具:PortSentinel 实战开发手记

别再下那些来路不明的绿色版了,我用 Python 手搓了一个端口扫描与安全监控工具。


0x00 引子:新机初启,百“孔”难安

故事发生在 2026 年 8 月 4 日的清晨。

新配的台式机到了,Windows 10 系统清爽得像一张白纸。作为一个手痒难耐的安全爱好者,我习惯性地敲下了那条刻在 Windows 管理员 DNA 里的命令:

netstat -ano

屏幕瞬间滚出密密麻麻的列表。一个刚装好、连额外软件都没装的系统,居然挂着二十多个监听端口:

TCP    0.0.0.0:135           0.0.0.0:0              LISTENING       1348
TCP    0.0.0.0:445           0.0.0.0:0              LISTENING       4
TCP    0.0.0.0:3389          0.0.0.0:0              LISTENING       1504

…………

…………

…………

135(RPC)——冲击波蠕虫的老巢;445(SMB)——WannaCry 勒索病毒就是从这杀进来的;3389(RDP)——BlueKeep 漏洞能让攻击者不认证就执行任意代码。新机器像没锁门的仓库,门外就是整个互联网。

怎么办?

  • Nmap?参数比我头发还多,查手册翻到手抽筋。

  • TCPView?Sysinternals 出品虽好,但闭源、无风险评级、无漏洞库。

  • CurrPorts?缺日志、缺知识库、缺本地化中文。

  • 去网上下个绿色版?谁知道是哪年的版本?有没有被植入后门?

一个念头冒了出来:与其用别人的刀,不如自己铸一把。

不就是端口扫描加连接监控嘛——Windows 底层 API 摆在那里,Python 的 ctypes 能调,PyQt5 能做界面,我决定自己写一个。

这个项目的名字就是 PortSentinel ,目前v0.08版本已开源在 GitHub(github.com/donoot/PortSentinel)。


0x01 顶层设计:三层架构与核心模块

动工之前先画蓝图。我需要一个清晰的分层结构,让代码可维护、可测试、可替换。

架构总览

我采用了经典的三层架构:

层级模块技术选型
GUI 层主窗口、工作线程、右键菜单PyQt5(信号槽驱动)
核心业务层端口扫描器、连接管理器、OS 指纹、漏洞库、日志系统Python 纯逻辑封装
系统接口层Windows API 调用、Socket、进程管理ctypes + iphlpapi.dll + psutil

依赖方向自上而下:GUI 层依赖业务层,业务层依赖系统接口层。即使将来把 PyQt5 换成 PySide6,核心业务层可以纹丝不动。

模块清单

  • PortScanner:多线程 TCP Connect 扫描器,支持协作式取消

  • ConnectionManager:通过 iphlpapi.dll 枚举/关闭 TCP/UDP 连接

  • PortDatabase:107+ 端口的 JSON 知识库,四级风险分类

  • OSFingerprint:基于开放端口组合的加权评分 OS 推断

  • VulnerabilityDatabase:20+ CVE 漏洞库(永恒之蓝、BlueKeep、SMBGhost 等)

  • AppLogger:结构化日志,格式 netinfo_YYYYMMDD_HHMMSS_主机名.log

  • MainWindow:双标签页 GUI(扫描结果 + 活动连接),19 项右键功能


0x02 攻坚难点一:用 ctypes 驯服 Windows IP Helper API

为什么不用 subprocessnetstat?因为解析文本脆弱得跟玻璃一样——换个 Windows 版本,输出格式一变,程序就崩了。

底层硬桥硬马,才够稳健。

IP Helper API 三件套

Windows 的 iphlpapi.dll 提供了三个关键函数:

  1. GetExtendedTcpTable:获取 TCP 连接表(含进程 PID)

  2. GetExtendedUdpTable:获取 UDP 连接表

  3. SetTcpEntry:强制关闭 TCP 连接(需管理员权限)

两次调用法(避坑指南)

变长结构体是第一个大坑。连接数量动态变化,不知道缓冲区该开多大。解决方法是两次调用

iphlpapi = ctypes.WinDLL('iphlpapi.dll')
AF_INET = 2
TCP_TABLE_OWNER_PID_ALL = 5
​
# 第一次调用:传空指针,获取所需缓冲区大小
size = ctypes.wintypes.DWORD(0)
iphlpapi.GetExtendedTcpTable(
    None, ctypes.byref(size), False,
    AF_INET, TCP_TABLE_OWNER_PID_ALL, 0
)
​
# 第二次调用:按大小分配缓冲区,真正取数据
buf = (ctypes.c_byte * size.value)()
iphlpapi.GetExtendedTcpTable(
    buf, ctypes.byref(size), False,
    AF_INET, TCP_TABLE_OWNER_PID_ALL, 0
)

指针算术破解零长度数组

C 结构体里的柔性数组(table[0])在 ctypes 里没法直接声明。我用指针偏移的方式绕过:

table = ctypes.cast(buf, ctypes.POINTER(MIB_TCPTABLE_OWNER_PID)).contents
num = table.dwNumEntries
row_ptr = ctypes.pointer(table.table[0])  # 拿首行地址当基址
​
for i in range(num):
    row = row_ptr[i]  # 指针算术,按 sizeof(row) 步进
    local_ip = socket.inet_ntoa(struct.pack('<I', row.dwLocalAddr))
    local_port = socket.ntohs(row.dwLocalPort & 0xFFFF)
    # ...

字节序的那点事儿

Windows API 里 IP 地址是主机字节序的 DWORD,端口号却是网络字节序存于低 16 位。转换函数如下:

def _dw_to_ip(dw_addr):
    return socket.inet_ntoa(struct.pack('<I', dw_addr))
​
def _dw_to_port(dw_port):
    return socket.ntohs(dw_port & 0xFFFF)
​
def _port_to_dw(port):
    return socket.htons(port)  # 用于 SetTcpEntry

跑起来的那一刻,屏幕上刷出了和 netstat -ano 一模一样的数据——但这次,数据是我从底层 API 里亲手“捞”出来的。


0x03 攻坚难点二:PyQt5 多线程与 UI 安全更新

有了数据,还得有个漂亮的“窗口”让用户看。

信号槽是跨线程通信的命脉

Qt 强制要求所有 UI 控件操作必须在主线程执行,否则随时段错误。所以我把耗时任务扔进QThread 子类,通过 pyqtSignal 把结果安全“发射”回主线程:



class ScanWorker(QThread):
    result_found = pyqtSignal(dict)           # 发现一个开放端口
    progress_updated = pyqtSignal(int, int)   # 进度更新
    scan_finished = pyqtSignal(list)          # 扫描完成
    scan_error = pyqtSignal(str)              # 出错啦
​
# 工作线程里
def run(self):
    for port in ports:
        if self.scanner.is_open(port):
            self.result_found.emit({"port": port, ...})
​
# 主线程里
worker.result_found.connect(self._on_scan_result)

信号跨线程传递时默认采用队列模式(QueuedConnection),绝对线程安全。

表格排序的小技巧

端口号存入 QTableWidgetItem 时用 setData(Qt.DisplayRole, int)

port_item = QTableWidgetItem()
port_item.setData(Qt.DisplayRole, result["port"])  # 存整数

这样点击表头排序时是按数值大小排,而不是按字符串排——否则 “9” 会排在 “80” 后面,那画面太美我不敢看。


0x04 攻坚难点三:I/O 密集型任务的并发与协作取消

端口扫描是典型的 I/O 密集型任务socket.connect_ex 大部分时间在等待响应或超时。

ThreadPoolExecutor 批量提交

with ThreadPoolExecutor(max_workers=self.threads) as executor:
    future_to_port = {
        executor.submit(self.scan_port, port): port
        for port in range(self.start_port, self.end_port + 1)
    }
    
    for future in as_completed(future_to_port):
        if self._cancelled:   # 协作式取消检查
            break
        port = future_to_port[future]
        is_open = future.result()
        if is_open:
            # 回调通知 UI

Python 的 GIL 在 I/O 阻塞时会释放,所以多线程对扫描吞吐量的提升是实打实的。

协作式取消:不杀线程,只停脚步

用户点了“取消”怎么办?暴力杀线程会留下各种不干净的状态。我采用协作式取消

def cancel(self):
    self._cancelled = True  # 设置标志

# 在 as_completed 循环中每个 Future 完成时检查
for future in as_completed(future_to_port):
    if self._cancelled:
        break
    # ...

不强行中断正在执行的 connect_ex,只是不再处理新的结果。干净、安全、优雅。

实测吞吐量

在 300 线程、0.5 秒超时下,对本机 1–65535 全端口扫描:

  • 耗时:109.83 秒

  • 吞吐量:约 597 端口/秒

线程数耗时(秒)吞吐量(端口/秒)
100≈ 180≈ 364
300109.83≈ 597
500≈ 95≈ 690
1000≈ 90≈ 728

从 500 到 1000 收益递减,说明本机扫描瓶颈已从并发度转向系统 socket 处理能力。


0x05 知识工程:端口风险库与 OS 指纹算法

扫出端口只是第一步,让用户看懂才是本事。

端口知识库(107+ 条目)

JSON 格式,结构清晰:

{
  "445": {
    "service": "SMB",
    "protocol": "tcp",
    "risk": "danger",
    "description": "Windows文件共享",
    "hazard": "勒索病毒(WannaCry)主要传播通道,永恒之蓝(MS17-010)利用此端口"
  },
  "22": {
    "service": "SSH",
    "protocol": "tcp",
    "risk": "safe",
    "description": "安全Shell远程登录",
    "hazard": "若使用弱密码或旧版本,可能被暴力破解"
  }
}

四级风险分类 + 对应颜色:

等级标签颜色示例
safe正常#27ae6022/SSH, 443/HTTPS
warning警告#f39c1221/FTP, 25/SMTP
danger危险#e74c3c445/SMB, 3389/RDP
unknown未知#95a5a649152+ 动态端口

OS 指纹识别:加权评分算法

不同操作系统的典型端口组合不同:

  • Windows:135, 139, 445, 3389

  • Linux:22, 80, 443

  • macOS:22, 548, 445

评分规则:

  • 端口匹配:+10 分/个

  • 服务名匹配:+15 分/个

  • 置信度 = 最高分 / (开放端口数 × 15) × 100,上限 100%

def _is_windows(self, open_ports):
    return any(p in open_ports for p in [135, 139, 445, 3389, 1433, 5985, 5986])

# 若检测到 Windows 典型端口,置信度下限直接拉到 70%

实测扫到 [135, 139, 445, 3389] 时,准确识别为 Windows 10

漏洞匹配库(20+ CVE)

内置三组漏洞:

  • Windows 组:永恒之蓝(CVE-2017-0144)、SMBGhost(CVE-2020-0796)、BlueKeep(CVE-2019-0708)

  • Linux 组:SSH、MySQL、Redis 相关

  • 通用组:FTP、Telnet、SNMP

匹配逻辑:端口 → 服务类型 → 漏洞条目 → 结合 OS 类型过滤。对 445 + 3389 的 Windows 主机,一次性命中 4 个 Critical 级漏洞。


0x06 实战验收:109 秒扫描 6.5 万端口

测试环境

项目配置
操作系统Windows 10 19045
CPUIntel i7-10700K(8 核 16 线程)
内存31.72 GB
Python3.11.3
PyQt55.15.11

全端口扫描结果

2026-08-04 20:22:07 [INFO] 【开始端口扫描】 目标: 127.0.0.1  范围: 1-65535
2026-08-04 20:22:08 [INFO]   [发现] 135/tcp MS-RPC 危险
2026-08-04 20:22:08 [INFO]   [发现] 445/tcp SMB 危险
2026-08-04 20:22:12 [INFO]   [发现] 3389/tcp RDP 危险
...
2026-08-04 20:23:57 [INFO] 【扫描完成】 耗时: 109.83秒  开放端口: 24个
2026-08-04 20:23:57 [WARNING]   ⚠ 检测到 3 个高危端口!

活动连接监控

程序启动后自动拉取本机连接表,100 条连接稳定解析:

TCP 192.168.6.125:56146 -> 27.222.17.33:443 [ESTABLISHED] PID:14632 (Trae CN.exe)
TCP 192.168.6.125:57956 -> 52.242.103.142:443 [ESTABLISHED] PID:11304 (msedge.exe)
UDP 192.168.6.125:137 -> *:0 [UDP] PID:4 (System)

PID 到进程名的映射准确无误——PID 4 是 “System”,PID 11304 是 “msedge.exe (11304)”,与任务管理器完全一致。

右键菜单功能矩阵

两个表格共集成了 19 项右键功能

菜单项适用场景
复制端口 / 复制完整信息端口扫描结果
查找该端口的服务项(本机)定位占用进程
通过防火墙关闭/打开该端口本机快速封禁
查看已知漏洞 / 在线搜索 CVE安全评估
全网络检索 / 大模型分析知识扩展
关闭该连接(TCP)紧急断连(需管理员)
结束进程 / 查看进程详情异常进程处置
WHOIS / IP 归属地查询溯源分析

0x07 踩坑记:那些年我掉进去的坑

  1. ctypes.Structure 的字节对齐 Windows API 结构体默认 #pragma pack(8),ctypes 默认是 4 字节对齐。我用 _pack_ = 1_pack_ = 8 强制匹配,否则偏移量全错。

  2. UDP 连接的 remote_addr 解析 UDP 是无连接的,dwRemoteAddr 可能为 0x00000000dwRemotePort 为 0。inet_ntoa 不能处理全零地址,得特判。

  3. SetTcpEntry 返回 ERROR_ACCESS_DENIED 非管理员权限下关闭连接必失败。我在 UI 上明确提示“请以管理员身份运行”,并把错误码映射成中文提示。

  4. 进程名缓存过期 ConnectionManager 启动时用 psutil 一次性缓存所有进程名。但扫描过程中新进程启动不会刷新。我的对策是:缓存命中直接返回,未命中时单次查询并补充入缓存——“预取 + 懒加载”策略。

  5. 已知端口扫描的端口列表来源 如果 port_database.json 加载失败,get_all_known_ports() 返回空列表。我在初始化时加了 fallback 空数据库,并打印警告。


0x08 项目开源与后续展望

PortSentinel v0.08 已完整开源,采用 GPL v3 协议。项目地址:

👉 github.com/donoot/PortSentinel

如果你也想自己动手改一版,或者发现 bug 想提 issue,非常欢迎。

未来迭代方向

  1. SYN 半开扫描:接入 WinPcap/Npcap,提升扫描速率

  2. Banner 抓取 + TTL 探测:OS 指纹精度再升一档

  3. AI 威胁分析:把端口 + CVE 摘要喂给大语言模型,输出自然语言加固方案

  4. 云端漏洞库同步:对接 NVD,每周自动拉取最新 CVE

  5. 实时连接推送:基于 ETW(Event Tracing for Windows)监控连接变化


写在最后

从那个发现满屏开放端口的早晨,到 PortSentinel 跑通全端口扫描,前后不过数日。

回顾这段经历,最大的感触是:Windows 底层 API 没那么可怕。 iphlpapi.dll 就在那里,ctypes 就是那座桥。两次调用、指针算术、字节序转换——搞懂了,你就拥有了和 netstat 一样的能力,还多出了强制关闭连接的超能力。

PyQt5 + QThread + 信号槽 的组合,是桌面 GUI 应用开发的黄金搭档。工作线程干重活,信号把结果安全送回主线程——UI 不卡,数据不错。

最重要的是,知识库让工具有了“灵魂”。107+ 端口的风险分级、20+ CVE 的漏洞匹配——这些让一个冷冰冰的扫描器变成了能给出安全建议的顾问

门就在那里,推开它。


项目标签#Python #PyQt5 #网络安全 #端口扫描 #Windows API #ctypes #开源

作者:donoot 日期:2026-08-04 版本:PortSentinel v0.08

打开链接下载源码: https://pan.quark.cn/s/05da658a2377 在信息技术领域中,输入法作为操作系统的一个核心构成部分,赋予了用户利用键盘输入多语种文字的能力。"ime-日语输入法安装必须文件"这一资源是一套为日语输入法部署而设计、包含全部必要元素的集成包,对于那些需要在个人计算机上执行日语文字输入的操作者而言具有不可替代的作用。接下来将深入剖析其中所包含的核心概念。 IME(Input Method Editor,输入法编辑器)是操作系统内的一种软件支持服务,其功能在于为非拉丁字符环境提供文字输入方案,例如中文、日文、韩文等文字系统。在日本地区,IME通常被用来将罗马字(罗马拼音)形式的输入转换为平假名、片假名乃至汉字。此压缩文件内含的日语IME文件夹即为执行这一转换功能的关键要素。 kbdjpn.dll被视为一个关键的系统性文件,其意指“Japanese Keyboard Layout”(日语键盘布局)。该动态链接库文件负责设定日语键盘的排列方式及快捷操作组合,使用户能够借助常规的QWERTY键盘输入日语文字。倘若缺少这一文件,即便已经安装了日语输入法,依然无法正常显示及输入日语字符。 另外,imjp81k.dll同样是一个重要的系统性构成,它属于日语IME的范畴,全称为“Input Method Japanese for Windows 8.1 and later, Katakana mode”(适用于Windows 8.1及更新版本的日语输入法,片假名模式)。该文件支持日语的片假名输入,是处理日语输入的核心组成部分。在安装或升级日语输入法的过程中,保证imjp81k.dll的准确性与完整性显得尤为关键。 压缩包所含的"Window...
内容概要:本文究了基于DPWMA调制与正负序分离的ANPC三电平并网逆变器前馈控制策略,旨在解决传统三电平逆变器在谐波抑制、电网不平衡适应性及动态响应方面的技术瓶颈。通过构建融合双极性倍频脉宽调制(DPWMA)、正负序分离锁相控制与电网电压前馈的一体化控制体系,全面优化逆变器的输出波形质量、相位同步精度与抗扰能力。文章深入分析了ANPC三电平拓扑的结构优势,如开关损耗均衡、中点电位可控性强和电压利用率高等特点,并设计了包含信号采集、核心控制与调制驱动三层架构的完整控制系统。通过Simulink仿真平台对稳态运行、电网不平衡及动态扰动等多种工况进行验证,结果表明该策略显著降低了总谐波畸变率,提升了锁相精度与系统动态稳定性,有效增强了逆变器在复杂电网环境下的适应能力和运行可靠性。; 适合人群:具备电力电子、自动控制及新能源并网相关基础知识,从事新能源发电、微电网、电力系统仿真等领域的科人员与工程技术人员,特别适合究生及以上层次的究者。; 使用场景及目标:①用于提升大功率并网逆变器在电网电压不平衡、谐波干扰和动态扰动等复杂工况下的运行性能;②为高电能质量要求的应用场景提供先进控制解决方案;③支持科仿真、论文复现与实际工程项目中的高性能并网控制系统设计与优化。; 阅读建议:建议结合提供的Simulink仿真模型进行实践操作,重点理解DPWMA调制机制、正负序分离锁相算法与电网电压前馈控制之间的协同作用,按照文档结构系统学习,并与传统控制策略进行对比分析,以深入掌握改进策略的技术优势与实现细节。
代码下载链接: https://pan.quark.cn/s/d9794888cbc0 ### G代码经典解释程序知识点详解 #### 一、引言 随着数控技术的持续进步,尤其是开放式数控系统的广泛应用,软件层面的设计在数控领域占据了核心地位。G代码作为数控机床编程的基础语言,在自动化生产流程中发挥着不可或缺的作用。本文的核心内容是关于一个基于Linux平台、采用C语言开发的G代码解释程序的设计思路及其具体实现。 #### 二、G代码解释器概述 **1. 设计背景** - 当前数控技术发展的主要方向是开放式数控系统,这类系统具备出色的可扩展能力、良好的移植性、高度的互换性以及优异的互操作性等优势。 - 计算机硬件技术的快速发展使得在PC平台上构建数控系统成为可能,进而推动了全软件式数控系统的普及。 **2. G代码解释器的重要性** - G代码解释器在全软件式数控系统中是至关重要的组成部分,其主要职责是将G代码转化为数控系统能够识别的数据格式。 - 为了提升数控系统的开放程度,G代码解释器的设计必须兼顾开放性和灵活性。 #### 三、G代码解释器设计与实现 **1. 总体结构设计** - G代码解释器主要由两个核心部分构成:G代码关键字函数表(GKFT)和G代码分组(GG)。 - GKFT用于解析G代码中的关键字,它是解释器的核心骨架;而GG则是语法检查的基础框架。 **2. G代码关键字函数表(GKFT)** - GKFT是一种专门用于存储G代码关键字及其关联处理函数的数据结构。 - 解释器通过查询GKFT,能够根据特定的G代码关键字调用相应的处理函数,从而完成对G代码的有效解析。 - 此种设计方法不仅简化了解释器的构建过程,同时也增强了其可扩展性,因为新增功能...
已经博主授权,源码转载自 https://pan.quark.cn/s/458849d2eac8 Microblaze代表由Xilinx公司发的一款软核处理器,其核心特性在于使用户能够针对FPGA(Field Programmable Gate Array)平台进行嵌入式系统的个性化构建。此“Xinlin中Microblaze的培训教程”致力于辅助学习人员深入理解和熟练掌握Microblaze在Xilinx开发环境中的实际应用。 一、Microblaze基础 Microblaze作为一款可配置的32位RISC处理器,具备高度适应性,允许在设计中根据具体需求对性能、功耗及面积进行灵活调整。Microblaze支持多种指令集架构(ISA),涵盖Xtensa-like和Classic两种模式,并且与包括UART、SPI、I2C在内的多种外设接口标准保持兼容。 二、Xilinx ISE与Vivado工具 Xilinx ISE(Integrated Software Environment)是一个用于FPGA系统设计、实现和调试的集成开发平台,而Vivado则是一款功能更为先进且全面的工具套件。在本次教程中,学员将学会如何在上述工具中配置和执行Microblaze处理器,以及如何开发相关的硬件描述语言(HDL)代码。 三、Microblaze硬件设计 在Xinlin提供的教程里,学员将学习如何在Xilinx FPGA中部署Microblaze处理器。这涉及到选择合适的处理器配置参数,如时钟频率、缓存容量和外设接口设置。此外,学员还将接触到创建和连接内存模块、中断控制器以及其他必需硬件组件的方法。 四、软件开发 Microblaze的软件开发通常涉及嵌入式编程,采用C或C++语言来...
内容概要:本文围绕并网与离网模式下的风光互补制氢合成氨系统,开展容量配置与运行调度的联合优化分析,并提供了完整的Python代码实现。究构建了综合考虑风能、太阳能发电特性、电解水制氢、合成氨工艺及储能环节的系统模型,重点解决了在不同运行模式(并网/离网)下,如何通过优化算法确定各单元的最佳容量配置,并在此基础上实现系统经济高效的运行调度。文中详细阐述了数学模型的建立过程,包括以最小化综合成本为目标的目标函数,以及涵盖功率平衡、设备容量、物料守恒等多方面的约束条件体系,并利用Python编程语言调用专业优化求解器进行仿真求解,最终获得系统的最优容量配置方案与精细化的调度策略。; 适合人群:具备一定Python编程基础和优化理论知识,从事新能源系统规划、综合能源系统、氢能或化工过程优化等相关领域的究生、科人员及工程技术人员。; 使用场景及目标:①学习如何对复杂的“电--氨”多能转换与存储系统进行一体化建模与仿真;②掌握使用Python实现能源系统容量优化与运行调度联合求解的具体方法与技术路线;③为相关领域的科项目、学位论文撰写或实际工程设计提供可复现的代码参考和系统性的解决方案借鉴。; 阅读建议:在阅读时应重点关注模型构建的逻辑框架与严谨的数学表达,并结合所提供的Python代码逐行理解其具体实现方式,建议读者务必自行复现代码以加深对优化算法求解过程和系统运行机制的理解,同时可尝试修改模型参数或拓展系统结构以适应不同的究需求和应用场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值