简介这是一份面向游戏爱好者与外挂开发入门者的WPEWinsock Packet Editor封包修改完整教程以65页doc文档系统讲解网络封包编辑器的原理与实战手法。文档目录涵盖WPE 1.0、1.3C、Pro 0.7C等各版本下载安装、WPE PRO使用方法、详细教程三部分、滤镜制作四讲、独立外挂制作两讲以及封包外挂教程结构清晰、由浅入深并穿插16进制计算方法、S包查找技巧、客户端进程选择等必备基础适合零基础新手循序渐进学习。压缩包内共1个doc文件整体大小约5.49MB按章节编排便于直接阅读与对照练习。目前已有1201人学习下载。教程不仅梳理了各经典版本的操作差异还专门介绍了制作游戏外挂、修改图形音频及实现特殊效果等高级玩法同时客观分析了软件优缺点与杀毒软件误报问题帮助读者在理解封包原理的基础上安全高效地掌握这套经典工具。1. 一份65页的wpe教程重点其实不在按钮上很多人拿到一份65页的wpe教程第一反应是找“点哪个按钮能改包”。翻完会发现事情没那么简单真正讲操作的部分可能只占三分之一剩下的篇幅全在解释为什么这么改、改了之后对端会怎么处理。原因在于wpeWinsock Packet Editor不是一键修改器而是一台工作在Winsock层上的协议调试台。它能看到程序调用send/recv时传递的数据也仅限这一层所以它天生适合做协议学习、接口联调、教学实验这些需要看清应用数据的场景而不是网上传言的那种“万能拦截器”。想验证自己写的TCP/UDP协议、想理解客户端和服务端在聊什么的人这份教程对应的知识体系是值得完整过一遍的。2. wpe的原理与定位先搞懂它拦的是哪一层后面才不白忙wpe的价值和局限都来自它的工作位置。这一章把原理聊透后面操作时你才知道哪些现象是工具本身的限制哪些是你操作失误。很多教程直接跳进界面讲按钮结果新手改完包发现没用回头怪工具不行其实是对它的边界理解错了。2.1 拦截原理Winsock钩子与DLL注入的边界在哪wpe的全名是Winsock Packet Editor核心逻辑很简单它把自己的一份DLL注入到目标进程里然后替换进程中对ws2_32.dll的几个导出函数的调用。常见被挂钩的函数是send、recv、WSASend、WSARecv。只要目标进程调用了这几个函数数据在进入TCP栈之前就会被wpe截获展示在封包列表里。实现上主要分两类。一类是IAT Hook改的是进程导入地址表把send的地址换成DLL里自己的函数优点是稳定、不容易崩缺点是只对通过导入表调用ws2_32的程序有效。另一类是Inline Hook直接改写函数入口的汇编指令为一条跳转适用范围更广但对指令长度的处理更挑剔稍有差错目标进程就会崩。实操里大多数wpe版本会混合使用优先IAT失败再考虑Inline。你不需要关心它内部用哪种但你要知道这个机制决定了两个边界。第一个边界是wpe只能看到应用层调用socket API时传入的缓冲区内容。目标进程在调send之前自己做了AES加密或者走了TLS层那你抓到的是密文不是明文。第二个边界是如果程序不走Winsock而用Raw Socket、NDIS驱动或者用户态协议栈wpe完全看不到。想抓网卡上的原始帧应该用Wireshark而不是wpe。这对你的实际意义是拿wpe调试自己写的协议、逆向我们自己拥有授权的老程序、分析C/S架构里的自定义TCP/UDP协议非常顺手想阅读HTTPS流量或者分析非Winsock通信它无能为力。把这层边界记牢后续排查大半问题都不用猜。2.2 界面拆解从滤镜区到发送区每个区域对应哪个动作wpe的界面结构多年没大变过核心区域大致是目标进程选择区、封包列表区、滤镜设置区、发送区、日志状态区。每个区域背后对应一个调试动作选择谁、看什么、筛什么、回什么。目标进程选择区通常是一个下拉框或列表列出当前系统里带网络连接的进程。选中的进程就是你要注入的对象。附加之前先确认权限wpe和目标程序大都是32位进程注入64位进程的兼容性要提前验证。很多版本的下拉框里64位进程能显示但附加后没有反应这是常见现象。封包列表区按行展示每个被拦到的数据序号、方向、长度、十六进制内容。方向的标记各家不一常见用S和R或者用箭头。这里要提醒一句wpe里一个“包”指的是应用层一次send/recv调用传递的完整缓冲区不是TCP分段。你发一个10KB的字符串底层的TCP可能切成10个报文段但wpe只显示一条10KB的记录。这一点和Wireshark完全不同后面会专门说。滤镜区用来控制显示和定位常见筛选条件有只显示发送、只显示接收、按长度范围过滤、按十六进制内容搜索。发送区则是把选中的封包内容载入、修改后重发可以设定循环次数和间隔。日志区会输出附加进程、DLL注入这类状态提示很多新手忽略它其实“附加失败”的直接原因就在日志里。把界面当成“附加—观察—筛选—修改—重发”的闭环来理解比死记按钮位置有效得多。下面这一节说三个工具怎么搭配。2.3 WPE、Wireshark、Fiddler怎么分工选型不是越多越好经常有人问有了Wireshark还需要wpe吗两者解决的问题不在同一层。我用一张表说明各自的位置和适用场景。工具工作层级典型场景不适合的场景Wireshark网卡层/链路层看原始帧TCP握手、重传分析、全流量审计HTTPS明文内容解密配置很麻烦FiddlerHTTP/HTTPS会话层Web接口调试、网页登录流程分析非HTTP的自定义TCP/UDP协议wpeWinsock API层看应用层收发缓冲自定义协议抓包改包、C/S联调、教学实验TLS密文、非Winsock通信我一般会先问自己一句我要看的是“程序之间在聊什么”还是“这些数据在网络里长什么样”。前者用wpe后者用Wireshark。比如程序之间传了一段自定义二进制指令wpe能直接给你看buffer省去你从以太网帧里层层剥壳的功夫。反过来你想确认TCP重传、乱序、Nagle算法有没有影响延迟wpe帮不上忙果断换Wireshark。选型还有个实际考量wpe的DLL注入行为容易被目标程序的异常处理捕获尤其是一些带自校验、带反调试的项目。而Fiddler作为HTTP代理不注入但也不覆盖非HTTP协议。真遇到注入不进又必须调Winsock层的情况我常用的是自己写一个小的API Monitor脚本或者退一步用Wireshark对照着看十六进制内容推协议。把这三个工具的关系搞顺后面遇到“抓不到包”的时候你至少知道是工具选错了还是操作用错了。3. 抓包与定位把目标程序的关键封包从噪声里挑出来这一章解决的是核心操作问题怎么让wpe稳定地抓到包怎么从一大串封包里找到你关心的那一个。配套一个我自己在用的解析脚本把wpe复制出来的十六进制内容转成结构化数据方便做后续分析和存档。3.1 附加进程的正确顺序先启动哪个权限怎么对齐附加进程这一步的坑比想象中多。最常见的失败现场是wpe启动了目标程序也启动了选择进程、点击附加日志区显示成功但随便操作目标程序封包列表始终空白。这时候先检查权限——wpe是不是用了管理员运行目标程序是不是用了普通权限或者反过来。权限不一致时DLL注入经常是“半成功”状态。我习惯的顺序是先把目标程序用固定权限启动然后以相同权限运行wpe。最好两个都以管理员运行不要一个管理员一个普通用户。如果目标程序是自研的建议编译成32位版本拿来练习因为多数主流wpe是32位的64位目标程序的注入兼容性各省版本差异大不要在环境问题上浪费半小时。附加时机也要注意。先附加进程再触发你要观察的操作。有人先把登录流程跑完了才想起来开wpe回头列表里只有心跳包这是顺序搞反了。另外多进程程序要先确认通信发生在哪个进程里。判断方法很简单打开任务管理器看进程列表里谁的“网络”列在跳变或者直接在wpe里对几个候选进程逐个附加一次抓几条包对比。附加成功后先别急着操作目标程序。等一两秒观察列表里有没有周期性数据。很多程序都有心跳包这正好可以用来验证wpe是否真的在工作。如果心跳能抓到说明注入成功接下来才能谈定位关键封包。3.2 封包列表里的四类信息方向、序号、长度、内容怎么读wpe的封包记录每条都包含四个核心信息序号、方向、长度、十六进制内容。读懂它们比会点按钮重要因为这决定了你能否从一段交互里准确猜出协议结构。序号是按捕获顺序递增的。方向表示这条数据是目标进程发送出去的Send还是接收到的Recv。长度是应用层缓冲区的大小单位是字节。十六进制内容就是send/recv拿到的原始字节wpe会同时在旁边给出ASCII预览。以最常见的二进制协议为例一段内容通常这样排布开头几个字节是协议魔数或长度中间是命令字和参数字段最后可能是校验字段。举例说AA 55 01 00 64 00 00 00 1C 3A这样的串如果前两个字节AA 55是固定魔数第三个字节01是命令类型后面四个字节是某个整数参数最后两个字节很可能就是CRC16校验结果。这个分析不是靠肉眼硬看而是靠改变目标程序的输入来对照。具体手法是先把列表清空只做一个非常简单的操作比如在程序里把数值从1改成2然后看这次操作新增了哪条封包。多试几次每次只改变一个变量对比封包内容的变化位置你就能逐步标注出哪个字节段对应哪个字段。这个过程不需要任何高级技能耐心比对就能拆出结构。wpe的封包列表支持复制内容把每条包复制到文本里慢慢对比在界面上盯着一行十六进制省力得多。3.3 过滤与定位用最小操作法把目标封包从噪声里拎出来目标程序一旦联网封包列表就会被心跳、日志上报、时间同步这类周期性数据刷屏。直接在里面翻找你关心的那条数据效率太低。定位的关键不是更快的眼力而是让数据自己“站出来”。做法分三步清空、最小操作、按特征查。先点清空列表的按钮或者重新附加进程把列表清零。接着在目标程序里做一次最小操作比如点一个按钮、切换一个开关。如果这个操作能被拆成多个动作就拆开做每做完一个动作回wpe看一次新增了哪些包把动作和封包一一对应起来。我实际操作时会把每个动作和对应的包序号记在纸上久而久之这套方法操作起来非常快几乎是肌肉记忆。如果目标程序自带长连接心跳列表会不断滚动干扰很大。这时用wpe自带的过滤器一般会支持按方向过滤、按长度范围过滤、按十六进制内容搜索。举个例子你已知目标包长度固定是64字节那就把过滤条件设为长度64以下不显示瞬间列表就安静了。再比如依赖内容搜索前提是你大概知道封包里的某几个字节是什么直接搜十六进制子串就能定位。还有个土办法也很有效操作前记录当前列表末尾的序号比如停在128号。操作后直接看128号后面的新记录不用翻整个列表。这个习惯帮我处理过很多次“明明抓到了却找不到”的尴尬。定位到目标封包后下一步要把它保存下来见下一节。3.4 把wpe复制的十六进制内容转成结构化文件一份解析脚本wpe允许把封包内容复制成文本。全选封包列表复制粘贴到一个txt文件里每行通常是一条封包的十六进制内容可能带方向标记也可能只有纯十六进制。这个文本拿去存档和对比都不太方便我一般会用Python脚本把它解析成CSV把方向、长度、hex、ASCII预览都拆成独立列后面做差异分析时用Excel或者脚本都顺手。import csv import re import sys def parse_wpe_hexdump(path, out_csv): rows [] with open(path, r, encodingutf-8, errorsignore) as f: for line in f: line line.strip() if not line: continue # wpe复制出来的行可能带 S: A5 5A ... 或 这类方向标记统一用正则可选提取 raw_hex re.sub(r^[^0-9a-fA-F]*, , line) tokens re.findall(r[0-9a-fA-F]{2}, raw_hex) if not tokens: continue direction S if (S in line[:2] or in line[:2]) else R raw bytes.fromhex(.join(tokens)) ascii_view .join(chr(b) if 32 b 127 else . for b in raw) rows.append({ direction: direction, length: len(raw), hex: raw.hex( ), ascii: ascii_view }) with open(out_csv, w, newline, encodingutf-8-sig) as f: writer csv.DictWriter(f, fieldnames[direction, length, hex, ascii]) writer.writeheader() writer.writerows(rows) print(fparsed {len(rows)} packets - {out_csv}) if __name__ __main__: parse_wpe_hexdump(sys.argv[1], sys.argv[2])这段脚本的思路是先把每行开头可能存在的方向标记和标签字符用正则清掉只保留十六进制字符串再用正则找所有成对的十六进制字符并转成字节最后按方向、长度、hex、ASCII四列输出。ASCII预览里不可打印的字符用点号代替方便肉眼扫看。参数上就两个输入txt路径和输出CSV路径命令行调用示例是python parse_wpe.py dump.txt result.csv。需要说明的是wpe各版本的复制格式略有差异行首的标记不一定相同如果你粘贴出来每行没有方向标记脚本会统一当成接收包处理。我一般在粘贴前会手动在每行后面补一个S或R标记或者干脆直接在wpe里按方向分开复制两遍再解析这样得到的CSV更干净。4. 修改与重放从改一个字节到构造完整请求序列抓包是为了看懂改包才是wpe的核心用途。这一章讲修改、校验处理、重放节奏最后给一个能在本地跑通的最小实验。很多教程到这里直接教“双击包然后改”但漏了长度字段重算和校验算法这两个关键前提结果新手一改就翻车。4.1 修改封包的基本操作改数、改长、改类型顺序不能乱在封包列表里双击一条记录通常会打开内容编辑窗口里面按十六进制展示这条封包。修改时鼠标定位到想改的字节直接改十六进制值。常见需求有三种改数值参数、改类型或命令字、改长度。其中改长度最麻烦。改数值参数最简单比如某个四字节字段表示经验值你把它从1改成100通常只要找到对应的字节段替换即可。但前提是协议本身没有校验有校验的话见4.3。改类型或命令字要小心边界值命令字改成服务端不认识的编号服务端可能直接断开连接而不是忽略。改长度必须同步重算协议头里的长度字段很多自定义协议会在固定位置存放载荷长度。比如第2到第3字节是小端序的长度值表示从第4字节开始的剩余数据长度你往数据区新增了4个字节长度字也要加4漏一步对端就会按错误边界解析。我踩过的教训是第一轮修改永远做等长替换不要加长或缩短。等长替换是指保持整包字节数不变只改动其中某几个字节的值。这样即使你改的字段不对目标程序在解析长度时不会出错排查时至少能确定问题出在语义上而不是格式上。等长替换能通再尝试加长或缩短配合长度字段重算。顺序一旦反了改完包目标程序直接崩或断连你根本没法判断是改错了还是长错了。4.2 重放的节奏控制延时、循环、次数怎么设才不崩wpe的发送区一般允许载入一条封包设置循环次数、间隔时间然后发送。初学者最容易犯的错是把间隔设成0或者极短拼命循环发送结果服务端不是回了一堆异常就是直接封了连接。重放的本质是模拟一次合法的客户端请求频率和节奏要尽量贴近真实操作。简单验证用固定次数更稳。比如载入一条登录请求封包设置只发送1次观察服务端响应是否符合预期。如果服务端有频率限制或防重放机制先确认原封包重放是否成功再谈修改。这条经验非常重要改包前先拿原始封包原样重放一次记录结果作为对照组。没有对照组就改包出了问题你连是不是自己改坏的都不知道。时间敏感型协议要严格对齐节奏。有的服务端会校验请求时间戳或者用滑动窗口拒绝过期的数据包。纯靠wpe改包很难伪造出正确的新时间戳实践里常见的做法是把整个请求序列抓下来按原始间隔重放中间不做修改成功率反而最高。循环发送的间隔参数通常按毫秒设置真实的客户端操作之间少说也有几十毫秒的间隔重放设置低于这个值就要有被服务端拒绝的心理准备。响应观察放在日志区和后续的新封包里。重放之后回到封包列表看有没有新增的回应包有则说明请求被处理了没有优先怀疑校验没过或被防重放拦截。判断依据不是“感觉”而是服务端有没有新的输出。4.3 校验与加密封包怎么判断看到CRC和密文怎么办修改二进制封包遇到最多的问题就是校验字段。判断一条封包有没有校验方法很粗暴改动内容里的一个字节原样重放看服务端还认不认。如果服务端立即断开或回错误码多半是校验不过或者你改的字段被语义解析报了错。两者怎么区分把改动位置换成对语义没有影响但会改变数据的字节比如保留原值这种混乱的对比方式不好理解更直接的办法是先试试只改动一个你认为无害的字段如果服务端的错误是“校验失败”这类明确逻辑就能确认是校验。常见校验类型有CRC16、CRC32、累加和、异或和。其中CRC16出现概率最高多项式厂家各异。下面给一个CRC16-Modbus的实现多项式是0xA001很多小厂自定义协议爱用这个变体。def crc16_modbus(data: bytes) - int: crc 0xFFFF for b in data: crc ^ b for _ in range(8): if crc 0x0001: crc (crc 1) ^ 0xA001 else: crc 1 return crc # 模拟一个协议载荷(payload) CRC16小端 payload bytes([0x01, 0x10, 0x00, 0x64]) crc crc16_modbus(payload) packet payload crc.to_bytes(2, little) print(packet.hex())这段代码的意思是对载荷部分计算CRC16并追加在小端序的末尾。如果目标协议用的是CRC16但多项式不同计算结果会不一致。安全做法是把抓到的一段已知封包截成“载荷校验”两部分用这段代码算一次比对结果是否能对上原始校验字节。对上了再用它重算改包后的封包对不上就换CRC32或累加和再试。加密封包的特征更明显数据部分像是无规律字节ASCII预览全是乱码长度往往呈固定块常见是16字节的倍数如果同一程序启动两次封包开头几字节不同而后面相同那开头很可能是加密用的初始化向量。加密协议下wpe能做的只剩“原样回放”改动任何一个字节都会让解密结果变成垃圾数据。遇到这种情况别再跟校验算法死磕换思路要么关掉加密做测试要么在更上层的地方下钩子。4.4 一个最小实验本地回环抓包改包验证这一节给一个可以在自己机器上完整走通的实验。我们写一个只监听本地回环地址的TCP服务端自定义一个带CRC16的协议。用wpe附加客户端或者服务端来抓包、改包、重放全流程不涉及任何外部系统。import socket import struct def crc16(data): crc 0xFFFF for b in data: crc ^ b for _ in range(8): crc (crc 1) ^ 0xA001 if crc 1 else crc 1 return crc def handle(conn): while True: head conn.recv(7) # 魔数2字节 命令1字节 参数4字节 if len(head) 7: break _magic, cmd, val struct.unpack(HBI, head) crc_recv struct.unpack(H, conn.recv(2))[0] if crc16(head) ! crc_recv: conn.sendall(bCRC_ERROR) continue if cmd 1: conn.sendall(struct.pack(I, val 1)) else: conn.sendall(bUNKNOWN_CMD) srv socket.socket(socket.AF_INET, socket.SOCK_STREAM) srv.bind((127.0.0.1, 9000)) srv.listen(1) print(server on 127.0.0.1:9000) while True: conn, _ srv.accept() handle(conn)这个服务端的协议格式定义得很明确前2字节是魔数0xAA 0x55第3字节是命令字第4到第7字节是四字节大端整数参数最后2字节是对前7字节计算的CRC16小端值。客户端可以随便写或者用现成的网络调试工具连上来发一条AA 55 01 00 00 00 64 3E 66试试其中3E 66是CRC16小端值。实验步骤先启动这个Python服务端再用32位客户端或调试工具连接同时用wpe附加这个客户端进程。连接后发一条正常请求wpe里能看到这条封包。复制这条封包在wpe的发送区载入把参数从100改成200同时用上面的脚本重算CRC并替换末尾两个字节重放。服务端回包里的数值如果是201说明整条链路已经跑通。这个实验的成功标准很清楚原封包能通改包后带纠错CRC也能通。它帮你把抓包、改包、重放、校验重算整条流程串起来之后再面对真实项目至少不会慌。5. 使用wpe的常见问题排查6个翻车现场和对应解法前四章覆盖了从原理到操作的全流程但实际用的时候一定会有各种“怎么就对不上”的情况。这一章整理六个我在实践里高频遇到的翻车场景每条按现象、原因、解决讲清楚。5.1 附加进程失败或一个包都收不到现象1在wpe里选中目标进程后点击附加日志区提示成功但目标程序怎么操作封包列表都是空的。原因九成是权限不一致。wpe以普通权限运行目标程序以管理员权限运行注入动作实际失败但界面没有明确报错。另外就是架构不匹配32位wpe附加64位进程时也可能静默失败。解决先将wpe和目标程序都设为“以管理员身份运行”再重新启动两者并附加。依然失败的话确认目标进程是不是64位。如果是找一个32位版本的目标程序来调试或者临时编译一个32位的测试程序。这一步排查完空列表的问题基本能解决。现象2附加的不是真正通信的那个进程。列表里能抓到一些包但和你操作的功能对不上。原因很多程序采用多进程架构界面进程、逻辑进程、通信进程是分开的wpe只注入了一个没注入真正做网络的进程。解决打开任务管理器观察各进程的网络活动列锁定真正产生流量的PID。如果界面能显示就先附加这个进程再复现一次操作。这个方法对基于浏览器的调试同样适用——确定哪个进程在做网络请求然后对症下药。5.2 重放没反应或者目标程序直接崩溃现象3把原始封包载入发送区原样重放服务端没有任何响应。原因原封包携带的上下文已经失效。比如登录态过期、一次性token被消耗、时间戳太旧或服务端有防重放缓存。还有一个可能重放使用的连接和抓包时的连接不是同一条服务端点验了连接状态。解决先用同一条连接、在抓包后立即重放这样能排除大部分上下文失效问题。再不行就抓一条完整交互序列登录、操作、登出按原顺序和原间隔重放不要只挑中间某一条包单独发。现象4修改重放的封包后目标程序当场崩溃。原因大概率是你加了字节长度而接收端缓冲区按原长度解析出现了越界访问。这类崩溃常见于C/C写的服务端或客户端对畸形长度没有防护。解决回到等长替换。改数值、改命令字都可以但不要改变整包长度这是最稳妥的验证方式。非要加长或缩短一定要同步重算长度字段并且先在自己的实验程序上验证不要直接拿去改别人的成熟系统。5.3 抓到的包和Wireshark对不上数量、顺序、内容都有出入现象5同一个操作Wireshark显示几十个包wpe只显示几个TCP三次握手和断开过程在wpe里完全看不到。原因二者工作层级不同。Wireshark看清了网卡上的所有帧包括TCP握手、确认号、窗口调整wpe只看Winsock层send/recv的应用数据缓冲区TCP分段对wpe不可见确认包更不会出现。解决需要分析TCP状态机或重传行为的时候直接用Wireshark需要在应用层看一次send调用的完整数据用wpe。两者对照使用时不要用“包的数量一致”来校验而应用“会话的内容一致”来对照。现象6wpe里启用了过滤器后发送区里载入的封包内容不对发出去没反应。原因过滤器影响了界面显示和选择逻辑有些版本在过滤状态下复制或载入封包时会载入过滤后列表里的相邻记录而不是你心里想的那条。解决操作发送前先清空所有过滤条件回到完整列表重新选中目标封包再载入。这个动作很蠢但很有效我因为这个浪费过不少时间。凡是涉及“载入发送区”这个动作一律先关掉过滤器。6. 进阶技巧用wpe的抓包结果做协议回归验证最后一章说一个我自己长期在用的进阶习惯把wpe抓到的封包当成协议实现的质量基线用来做回归验证。很多人调完协议就关工具结果两周后改了代码逻辑把之前的兼容性改没了而不自知。我在做自研协议对接时会针对每个核心功能保留下“黄金封包”一段原始客户端发出的请求、它对应的响应以及操作步骤说明。之后每次改完协议解析代码就重新执行同样的操作用wpe抓一份新包和黄金封包做十六进制对比。对比不能直接看整包因为可变字段会干扰视线。我的习惯是写一个小脚本把时间戳、会话ID、随机数这类必变字段先归一化成固定占位符再做逐字节diff。归一化规则按协议的实际布局写比如前4字节是自增序号就把它整体替换为00000000再比较其他部分。响应包的对比只比对长度和关键命令字不追求整包一致因为响应内容里经常包含当时的时间或随机盐。这套验证方式把wpe从一个“抓包改包工具”变成了日常开发里的回归测试工具。有一次我就是靠这个习惯抓到一个隐蔽问题数据解析代码改了一个字节序的宏定义理论上不影响单次请求但导致所有大于127的参数值在序列化后被读错。单测全过直到拿新包和黄金包做diff才发现参数区第3个字节在所有包里都比原来多出0x80。那一刻我特别庆幸自己存过那些封包。现在但凡做协议相关的项目我第一件事就是搭一套“抓包存档 归一化对比”的流程前期花两小时后期能省无数个排查的深夜。希望帮到你。本文还有配套的精品资源点击获取