基于Python3的scapy解析SSL报文

        scapy对于SSL的支持个人觉得不太好,至少在构造报文方面没有HTTP或者DNS这种常见的报文有效方便,但是scapy对于SSL的解析还是可以的。下面我们以一个典型的HTTPS的报文为例,展示scapy解析SSL报文。

一:解析ClientHello报文

from scapy.all import *
from scapy.layers.tls import *load_layer("tls") 
srcpcap = rdpcap("https_standerd.pcapng")
srcpcap[3].show2()

首先我们读取报文,用rdpcap,然后取ClientHello报文,我们通过索引去获取(从0开始)。需要注意的是我们用Scapy解析SSL需要load_layer(‘tls’),不然就没法解析SSL层的字段

以下是解析的结果

###[ Ethernet ]### 
  dst       = 58:f9:87:b9:6c:92
  src       = 40:b0:76:82:0a:16
  type      = IPv4
###[ IP ]### 
     version   = 4
     ihl       = 5
     tos       = 0x0
     len       = 557
     id        = 17598
     flags     = DF
     frag      = 0
     ttl       = 64
     proto     = tcp
     chksum    = 0x0
     src       = 192.168.1.7
     dst       = 36.152.44.96
     \options   \
###[ TCP ]### 
        sport     = 54402
        dport     = https
        seq       = 1487137542
        ack       = 3503406465
        dataofs   = 5
        reserved  = 0
        flags     = PA
        window    = 1025
        chksum    = 0x14c7
        urgptr    = 0
        options   = []
###[ TLS ]### 
           type      = handshake
           version   = TLS 1.0
           len       = 512    [deciphered_len= 512]
           iv        = b''
           \msg       \
            |###[ TLS Handshake - Client Hello ]### 
            |  msgtype   = client_hello
            |  msglen    = 508
            |  version   = TLS 1.2
            |  gmt_unix_time= Wed, 11 Oct 2062 17:54:57 +0800 (2927814897)
            |  random_bytes= 81fd99aef9407de45a94a6058080ba52474f28033827cc8a149e0e92
            |  sidlen    = 32
            |  sid       = '\\x88\\x9d\u07b9\\xa4U{\\x82\x11[\x1c4\\xdaiA\\xbf.291\\xfe\\xf6*\\xd5C\\xe7\\xe19Y\\x89ٰ'
            |  cipherslen= 34
            |  ciphers   = [0xa0a, TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_AES_256_GCM_SHA384, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_3DES_EDE_CBC_SHA]
            |  complen   = 1
            |  comp      = null
            |  extlen    = 401
            |  \ext       \
            |   |###[ TLS Extension - Scapy Unknown ]### 
            |   |  type      = 19018
            |   |  len       = 0
            |   |  val       = ''
            |   |###[ TLS Extension - Server Name ]### 
            |   |  type      = server_name
            |   |  len       = 18
            |   |  servernameslen= 16
            |   |  servernames= [b'www.baidu.com']
            |   |###[ TLS Extension - Extended Master Secret ]### 
            |   |  type      = extended_master_secret
            |   |  len       = 0
            |   |###[ TLS Extension - Renegotiation Indication ]### 
            |   |  type      = renegotiation_info
            |   |  len       = 1
            |   |  reneg_conn_len= 0
            |   |  renegotiated_connection= ''
            |   |###[ TLS Extension - Supported Groups ]### 
            |   |  type      = supported_groups
            |   |  len       = 10
            |   |  groupslen = 8
            |   |  groups    = [60138, x25519, secp256r1, secp384r1]
            |   |###[ TLS Extension - Supported Point Format ]### 
            |   |  type      = ec_point_formats
            |   |  len       = 2
            |   |  ecpllen   = 1
            |   |  ecpl      = [uncompressed]
            |   |###[ TLS Extension - Session Ticket ]### 
            |   |  type      = session_ticket
            |   |  len       = 160
            |   |  ticket    = '\\xd0j\\x93\\xcf\x01\\xd4LN\\xf4\\xd1\x10y\\xfeӢ皥%m\\x94똲J\\xfa?\\xd1K\\xfb\\xe5\\xd4b3\\xcbF\x11\\xbcX*\\xd9\\xe1\\xaf\x11-;()\\xc0\x04Ъ\\xff!\x10\\x88\\xab\\xec\\xc0\x03\\xb1\ni\\xe2\\xeb\x19\\xd7\\xd7\\xe5\x19\\xd2l߈\\xf8\\xd5s\\xe3\\xd0sYU-\x7f\\xb3\\xb7X\\xc3+\\xe4\\x96e^\\xeb\\xeb\\xb59A\\xcb\x00\x1c)V\\x8an=\\xb9j\\x91\\xf1"\\xb42\\xb6\\x9cd\\xf8ȋ\\xa4\x02\\xbaL\x14\\xac\\xff\x7f\\xc0w\x0cvO7M\\xe1I\x07*"\\xcd\x17\x10\\x96q\\xd4%\x19G\\xebO\\xa8lnX\\xdc\\xf8\\x93|(\\xfa'
            |   |###[ TLS Extension - Application Layer Protocol Negotiation ]### 
            |   |  type      = alpn
            |   |  len       = 14
            |   |  protocolslen= 12
            |   |  protocols = [b'h2', b'http/1.1']
            |   |###[ TLS Extension - Certificate Status Request ]### 
            |   |  type      = status_request
            |   |  len       = 5
            |   |  stype     = ocsp
            |   |  \req       \
            |   |   |###[ OCSPStatusRequest structure ]### 
            |   |   |  respidlen = 0
            |   |   |  \respid    \
            |   |   |  reqextlen = 0
            |   |   |  reqext    = ''
            |   |###[ TLS Extension - Signature Algorithms ]### 
            |   |  type      = signature_algorithms
            |   |  len       = 20
            |   |  sig_algs_len= 18
            |   |  sig_algs  = [sha256+ecdsa, sha256+rsaepss, sha256+rsa, sha384+ecdsa, sha384+rsaepss, sha384+rsa, sha512+rsaepss, sha512+rsa, sha1+rsa]
            |   |###[ TLS Extension - Scapy Unknown ]### 
            |   |  type      = signed_certificate_timestamp
            |   |  len       = 0
            |   |  val       = ''
            |   |###[ TLS Extension - Key Share (for ClientHello) ]### 
            |   |  type      = key_share
            |   |  len       = 43
            |   |  client_shares_len= 41
            |   |  \client_shares\
            |   |   |###[ Key Share Entry ]### 
            |   |   |  group     = 60138
            |   |   |  kxlen     = 1
            |   |   |  key_exchange= 00
            |   |   |###[ Key Share Entry ]### 
            |   |   |  group     = x25519
            |   |   |  kxlen     = 32
            |   |   |  key_exchange= 914e643fa99e7c4c0a063941936df104be236e16126fc266ad03303353933e05
            |   |###[ TLS Extension - PSK Key Exchange Modes ]### 
            |   |  type      = psk_key_exchange_modes
            |   |  len       = 2
            |   |  kxmodeslen= 1
            |   |  kxmodes   = [psk_dhe_ke]
            |   |###[ TLS Extension - Supported Versions (for ClientHello) ]### 
            |   |  type      = supported_versions
            |   |  len       = 11
            |   |  versionslen= 10
            |   |  versions  = [2570, TLS 1.3, TLS 1.2, TLS 1.1, TLS 1.0]
            |   |###[ TLS Extension - Scapy Unknown ]### 
            |   |  type      = 27
            |   |  len       = 3
            |   |  val       = '\x02\x00\x02'
            |   |###[ TLS Extension - Scapy Unknown ]### 
            |   |  type      = 23130
            |   |  len       = 1
            |   |  val       = '\x00'
            |   |###[ TLS Extension - Padding ]### 
            |   |  type      = padding
            |   |  len       = 43
            |   |  padding   = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
           mac       = b''
           pad       = b''
           padlen    = None

可以看到SSL协商的字段都能解析出来。我们如果加load_layer("tls") 效果如下

Scapy能解析出来的字段,我们当然也能读取出来,比如我们想要提取Server Name字段

from scapy.all import *
from scapy.layers.tls import *load_layer("tls") 
srcpcap = rdpcap("https_standerd.pcapng")
tlsLayer = srcpcap[3][TLS]
print(tlsLayer.layers)
#print(help(tlsLayer))
#clientHelloPart = tlsLayer['TLS Handshake - Client Hello']
clientHelloPart = tlsLayer[TLSClientHello]
#serverNamePart = clientHelloPart['TLS Extension - Server Name']
serverNamePart = clientHelloPart[TLS_Ext_ServerName][ServerName]print(dir(serverNamePart))print(f"serverName={serverNamePart.servername}")
print(f"serverNameLen={serverNamePart.namelen}")

提取结果如下: 

在上面的代码中给出了两个方法去一层一层获取我们想要字段,第一种方法可以根据上述解析的层级根据字符串去获取,依此类推找到我们字段所在的层级

第二个方法就是打印出tlslayer的层级结构,根据结构的索引字段去获取

<bound method Packet.layers of <TLS  type=handshake version=TLS 1.0 len=512    [deciphered_len= 512] iv=b'' msg=[<TLSClientHello  msgtype=client_hello msglen=508 version=TLS 1.2 gmt_unix_time=Wed, 11 Oct 2062 17:54:57 +0800 (2927814897) random_bytes=81fd99aef9407de45a94a6058080ba52474f28033827cc8a149e0e92 sidlen=32 sid='\\x88\\x9d\u07b9\\xa4U{\\x82\x11[\x1c4\\xdaiA\\xbf.291\\xfe\\xf6*\\xd5C\\xe7\\xe19Y\\x89ٰ' cipherslen=34 ciphers=[0xa0a, TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_AES_256_GCM_SHA384, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_3DES_EDE_CBC_SHA] complen=1 comp=null extlen=401 ext=[<TLS_Ext_Unknown  type=19018 len=0 |>, <TLS_Ext_ServerName  type=server_name len=18 servernameslen=16 servernames=[b'www.baidu.com'] |>, <TLS_Ext_ExtendedMasterSecret  type=extended_master_secret len=0 |>, <TLS_Ext_RenegotiationInfo  type=renegotiation_info len=1 reneg_conn_len=0 |>, <TLS_Ext_SupportedGroups  type=supported_groups len=10 groupslen=8 groups=[60138, x25519, secp256r1, secp384r1] |>, <TLS_Ext_SupportedPointFormat  type=ec_point_formats len=2 ecpllen=1 ecpl=[uncompressed] |>, <TLS_Ext_SessionTicket  type=session_ticket len=160 ticket='\\xd0j\\x93\\xcf\x01\\xd4LN\\xf4\\xd1\x10y\\xfeӢ皥%m\\x94똲J\\xfa?\\xd1K\\xfb\\xe5\\xd4b3\\xcbF\x11\\xbcX*\\xd9\\xe1\\xaf\x11-;()\\xc0\x04Ъ\\xff!\x10\\x88\\xab\\xec\\xc0\x03\\xb1\ni\\xe2\\xeb\x19\\xd7\\xd7\\xe5\x19\\xd2l߈\\xf8\\xd5s\\xe3\\xd0sYU-\x7f\\xb3\\xb7X\\xc3+\\xe4\\x96e^\\xeb\\xeb\\xb59A\\xcb\x00\x1c)V\\x8an=\\xb9j\\x91\\xf1"\\xb42\\xb6\\x9cd\\xf8ȋ\\xa4\x02\\xbaL\x14\\xac\\xff\x7f\\xc0w\x0cvO7M\\xe1I\x07*"\\xcd\x17\x10\\x96q\\xd4%\x19G\\xebO\\xa8lnX\\xdc\\xf8\\x93|(\\xfa' |>, <TLS_Ext_ALPN  type=alpn len=14 protocolslen=12 protocols=[b'h2', b'http/1.1'] |>, <TLS_Ext_CSR  type=status_request len=5 stype=ocsp req=[<OCSPStatusRequest  respidlen=0 reqextlen=0 |>] |>, <TLS_Ext_SignatureAlgorithms  type=signature_algorithms len=20 sig_algs_len=18 sig_algs=[sha256+ecdsa, sha256+rsaepss, sha256+rsa, sha384+ecdsa, sha384+rsaepss, sha384+rsa, sha512+rsaepss, sha512+rsa, sha1+rsa] |>, <TLS_Ext_Unknown  type=signed_certificate_timestamp len=0 |>, <TLS_Ext_KeyShare_CH  type=key_share len=43 client_shares_len=41 client_shares=[<KeyShareEntry  group=60138 kxlen=1 key_exchange=00 |>, <KeyShareEntry  group=x25519 kxlen=32 key_exchange=914e643fa99e7c4c0a063941936df104be236e16126fc266ad03303353933e05 |>] |>, <TLS_Ext_PSKKeyExchangeModes  type=psk_key_exchange_modes len=2 kxmodeslen=1 kxmodes=[psk_dhe_ke] |>, <TLS_Ext_SupportedVersion_CH  type=supported_versions len=11 versionslen=10 versions=[2570, TLS 1.3, TLS 1.2, TLS 1.1, TLS 1.0] |>, <TLS_Ext_Unknown  type=27 len=3 val='\x02\x00\x02' |>, <TLS_Ext_Unknown  type=23130 len=1 val='\x00' |>, <TLS_Ext_Padding  type=padding len=43 padding='\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |>] |>] padlen=None |>>

当然两种方法在取字段的时候还是有细微差别的

from scapy.all import *
from scapy.layers.tls import *
#from scapy_ssl_tls.ssl_tls import *load_layer("tls") 
srcpcap = rdpcap("https_standerd.pcapng")
tlsLayer = srcpcap[3][TLS]
#print(tlsLayer.layers)
#print(help(tlsLayer))
clientHelloPart = tlsLayer['TLS Handshake - Client Hello']
#clientHelloPart = tlsLayer[TLSClientHello]
serverNamePart = clientHelloPart['TLS Extension - Server Name']
serverLayers = serverNamePart.servernames
#serverNamePart = clientHelloPart[TLS_Ext_ServerName][ServerName]print(serverLayers)print(f"serverName={serverLayers[0].servername}")
print(f"serverNameLen={serverLayers[0].namelen}")
print(f"serverNamesLen={serverNamePart.servernameslen}")
#print(f"serverNameLen={serverNamePart.name}")

要善于利用help和dir去查找我们想要的方法和函数。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/199068.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【zabbix监控三】zabbix之部署代理服务器

一、部署代理服务器 分布式监控的作用&#xff1a; 分担server的几种压力解决多机房之间的网络延时问题 1、搭建proxy主机 1.1 关闭防火墙&#xff0c;修改主机名 systemctl disbale --now firewalld setenforce 0 hostnamectl set-hostname zbx-proxy su1.2 设置zabbix下…

Docker 可视化面板 ——Portainer

Portainer 是一个非常好用的 Docker 可视化面板&#xff0c;可以让你轻松地管理你的 Docker 容器。 官网&#xff1a;Portainer: Container Management Software for Kubernetes and Docker 【Docker系列】超级好用的Docker可视化工具——Portainer_哔哩哔哩_bilibili 环境 …

服务注册发现 springcloud netflix eureka

文章目录 前言角色&#xff08;三个&#xff09; 工程说明基础运行环境工程目录说明启动顺序&#xff08;建议&#xff09;&#xff1a;运行效果注册与发现中心服务消费者&#xff1a; 代码说明服务注册中心&#xff08;Register Service&#xff09;服务提供者&#xff08;Pro…

三十二、W5100S/W5500+RP2040树莓派Pico<UPnP示例>

文章目录 1 前言2 简介2 .1 什么是UPnP&#xff1f;2.2 UPnP的优点2.3 UPnP数据交互原理2.4 UPnP应用场景 3 WIZnet以太网芯片4 UPnP示例概述以及使用4.1 流程图4.2 准备工作核心4.3 连接方式4.4 主要代码概述4.5 结果演示 5 注意事项6 相关链接 1 前言 随着智能家居、物联网等…

ESP32-BLE基础知识

一、存储模式 两种存储模式&#xff1a; 大端存储&#xff1a;低地址存高字节&#xff0c;如将0x1234存成[0x12,0x34]。小端存储&#xff1a;低地址存低字节&#xff0c;如将0x1234存成[0x34,0x12]。 一般来说&#xff0c;我们看到的一些字符串形式的数字都是大端存储形式&a…

服务器端请求伪造(SSRF)

概念 SSRF(Server-Side Request Forgery&#xff0c;服务器端请求伪造) 是一种由攻击者构造形成的由服务端发起请求的一个安全漏洞。一般情况下&#xff0c;SSRF是要攻击目标网站的内部系统。&#xff08;因为内部系统无法从外网访问&#xff0c;所以要把目标网站当做中间人来…

Flutter 中在单个屏幕上实现多个列表

今天&#xff0c;我将提供一个实际的示例&#xff0c;演示如何在单个页面上实现多个列表&#xff0c;这些列表可以水平排列、网格格式、垂直排列&#xff0c;甚至是这些常用布局的组合。 下面是要做的&#xff1a; 实现 让我们从创建一个包含产品所有属性的产品模型开始。 …

Android描边外框stroke边线、rotate旋转、circle圆形图的简洁通用方案,基于Glide与ShapeableImageView,Kotlin

Android描边外框stroke边线、rotate旋转、circle圆形图的简洁通用方案&#xff0c;基于Glide与ShapeableImageView&#xff0c;Kotlin 利用ShapeableImageView专门处理圆形和外框边线的特性&#xff0c;通过Glide加载图片装载到ShapeableImageView。注意&#xff0c;因为要描边…

⑩⑤【DB】详解MySQL存储过程:变量、游标、存储函数、循环,判断语句、参数传递..

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ MySQL存储过程 1. 介绍2. 使用3. 变量①系统变…

每天学习一点点之 Spring Web MVC 之抽象 HandlerInterceptor 实现常用功能(限流、权限等)

背景 这里介绍一下本文的背景&#xff08;废话&#xff0c;可跳过&#xff09;。上周有个我们服务的调用方反馈某个接口调用失败率很高&#xff0c;排查了一下&#xff0c;发现是因为这个接口被我之前写的一个限流器给拦截了&#xff0c;随着我们的服务接入了 Sentinel&#x…

MTK Pump Express 快速充电原理分析

1 MTK PE 1.1 原理 在讲正文之前&#xff0c;我们先看一个例子。 对于一块电池&#xff0c;我们假设它的容量是6000mAh&#xff0c;并且标称电压是3.7V&#xff0c;换算成Wh(瓦时)为单位的值是22.3Wh(6000mAh*3.7V)&#xff1b;普通的充电器输出电压电流是5V2A(10W)&#xff0c…

RK3588平台开发系列讲解(项目篇)嵌入式AI的学习步骤

文章目录 一、嵌入式AI的学习步骤1.1、入门Linux1.2、入门AI 二、瑞芯微嵌入式AI2.1、瑞芯微的嵌入式AI关键词2.2、AI模型部署流程 沉淀、分享、成长&#xff0c;让自己和他人都能有所收获&#xff01;&#x1f604; &#x1f4e2; 本篇将给大家介绍什么是嵌入式AI。 一、嵌入…

Docker与Kubernetes结合的难题与技术解决方案

文章目录 1. **版本兼容性**技术解决方案 2. **网络通信**技术解决方案 3. **存储卷的管理**技术解决方案 4. **安全性**技术解决方案 5. **监控和日志**技术解决方案 6. **扩展性与自动化**技术解决方案 7. **多集群管理**技术解决方案 结语 &#x1f388;个人主页&#xff1a…

编程刷题网站以及实用型网站推荐

1、牛客网在线编程 牛客网在线编程https://www.nowcoder.com/exam/oj?page1&tab%E8%AF%AD%E6%B3%95%E7%AF%87&topicId220 2、力扣 力扣https://leetcode.cn/problemset/all/ 3、练码 练码https://www.lintcode.com/ 4、PTA | 程序设计类实验辅助教学平台 PTA | 程…

【Java 进阶篇】Ajax 实现——原生JS方式

大家好&#xff0c;欢迎来到这篇关于原生 JavaScript 中使用 Ajax 实现的博客&#xff01;在前端开发中&#xff0c;我们经常需要与服务器进行数据交互&#xff0c;而 Ajax&#xff08;Asynchronous JavaScript and XML&#xff09;是一种用于创建异步请求的技术&#xff0c;它…

云原生专栏丨基于服务网格的企业级灰度发布技术

灰度发布&#xff08;又名金丝雀发布&#xff09;是指在黑与白之间&#xff0c;能够平滑过渡的一种发布方式。在其上可以进行A/B testing&#xff0c;即让一部分用户继续用产品特性A&#xff0c;一部分用户开始用产品特性B&#xff0c;如果用户对B没有什么反对意见&#xff0c;…

广州华锐互动VRAR:VR教学楼地震模拟体验增强学生防震减灾意识

在当今社会&#xff0c;地震作为一种自然灾害&#xff0c;给人们的生活带来了巨大的威胁。特别是在学校这样的集体场所&#xff0c;一旦发生地震&#xff0c;后果将不堪设想。因此&#xff0c;加强校园安全教育&#xff0c;提高师生的防震减灾意识和能力&#xff0c;已经成为了…

springboot中动态api如何设置

1.不需要编写controller 等mvc层&#xff0c;通过接口动态生成api。 这个问题&#xff0c;其实很好解决&#xff0c;以前编写接口&#xff0c;是要写controller&#xff0c;需要有 RestController RequestMapping("/test1") public class xxxController{ ApiOperat…

Zotero在word中插入带超链接的参考文献/交叉引用/跳转参考文献

Zotero以其丰富的插件而闻名&#xff0c;使用起来十分的带劲&#xff0c;最重要的是它是免费的、不卡顿&#xff0c;不像某专业软件。 然而Zotero在word插入参考文献时&#xff0c;无法为参考文献添加超链接&#xff0c;这是一个不得不提的遗憾。 不过&#xff0c;有大佬已经…

asp.net健身会所管理系统sqlserver

asp.net健身会所管理系统sqlserver说明文档 运行前附加数据库.mdf&#xff08;或sql生成数据库&#xff09; 主要技术&#xff1a; 基于asp.net架构和sql server数据库 功能模块&#xff1a; 首页 会员注册 教练预约 系统公告 健身课程 在线办卡 用户中心[修改个人信息 修…