WinDBG查找C++句柄泄露
C++代码(频繁点击About按钮导致Mutex句柄泄露)
HANDLE _mutexHandle;LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{switch (message){case WM_COMMAND:{int wmId = LOWORD(wParam);// 分析菜单选择:switch (wmId){case IDM_ABOUT:_mutexHandle = CreateMutex(NULL, FALSE, L"abc");DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);break;case IDM_EXIT:DestroyWindow(hWnd);break;default:return DefWindowProc(hWnd, message, wParam, lParam);}}break;case WM_PAINT:{PAINTSTRUCT ps;HDC hdc = BeginPaint(hWnd, &ps);// TODO: 在此处添加使用 hdc 的任何绘图代码...EndPaint(hWnd, &ps);}break;case WM_DESTROY:PostQuitMessage(0);break;default:return DefWindowProc(hWnd, message, wParam, lParam);}return 0;
}
编译后生成exe程序,设置WinDBG的源码目录和pdb目录:
File-->Settings-->

File-->Start debugging
选择目标exe文件启动进程,点击左上角Go按钮,让ui显式,点击Break按钮让进程暂停,在WinDBG的命令行输入:
!htrace -enable
!htrace -snapshot
点击WinDBG左上角的Go按钮继续执行,点击UI上的按钮造成泄露;
点击WinDBG左上角的Break按钮进入调试模式;
在命令行输入:
!htrace 或 !htrace -diff,查看句柄泄露信息:
0:006> !htrace -diff
Handle tracing information snapshot successfully taken.
0x1a new stack traces since the previous snapshot.
Ignoring handles that were already closed...
Outstanding handles opened since the previous snapshot:
--------------------------------------
Handle = 0x00000000000002c0 - OPEN
Thread ID = 0x000000000000172c, Process ID = 0x0000000000003d7c0x00007ffac544eb64: ntdll!NtCreateMutant+0x0000000000000014
0x00007ffac2d38fa8: KERNELBASE!CreateMutexExW+0x0000000000000058
0x00007ff6436c6f00: CPPWindowsProject1!WndProc+0x00000000000000d0
0x00007ffac50cef5c: USER32!UserCallWinProcCheckWow+0x000000000000050c
0x00007ffac50ce684: USER32!DispatchMessageWorker+0x0000000000000494
0x00007ff6436c1d57: CPPWindowsProject1!wWinMain+0x0000000000000117
0x00007ff6436c2c62: CPPWindowsProject1!invoke_main+0x0000000000000032
0x00007ff6436c2b12: CPPWindowsProject1!__scrt_common_main_seh+0x0000000000000132
0x00007ff6436c29ce: CPPWindowsProject1!__scrt_common_main+0x000000000000000e
0x00007ff6436c2cfe: CPPWindowsProject1!wWinMainCRTStartup+0x000000000000000e
0x00007ffac37e7374: KERNEL32!BaseThreadInitThunk+0x0000000000000014
0x00007ffac53fcc91: ntdll!RtlUserThreadStart+0x0000000000000021
--------------------------------------
Handle = 0x00000000000002bc - OPEN
Thread ID = 0x000000000000172c, Process ID = 0x0000000000003d7c0x00007ffac544eb64: ntdll!NtCreateMutant+0x0000000000000014
0x00007ffac2d38fa8: KERNELBASE!CreateMutexExW+0x0000000000000058
0x00007ff6436c6f00: CPPWindowsProject1!WndProc+0x00000000000000d0
0x00007ffac50cef5c: USER32!UserCallWinProcCheckWow+0x000000000000050c
0x00007ffac50ce684: USER32!DispatchMessageWorker+0x0000000000000494
0x00007ff6436c1d57: CPPWindowsProject1!wWinMain+0x0000000000000117
0x00007ff6436c2c62: CPPWindowsProject1!invoke_main+0x0000000000000032
0x00007ff6436c2b12: CPPWindowsProject1!__scrt_common_main_seh+0x0000000000000132
0x00007ff6436c29ce: CPPWindowsProject1!__scrt_common_main+0x000000000000000e
0x00007ff6436c2cfe: CPPWindowsProject1!wWinMainCRTStartup+0x000000000000000e
0x00007ffac37e7374: KERNEL32!BaseThreadInitThunk+0x0000000000000014
0x00007ffac53fcc91: ntdll!RtlUserThreadStart+0x0000000000000021
--------------------------------------
Handle = 0x00000000000002b8 - OPEN
Thread ID = 0x000000000000172c, Process ID = 0x0000000000003d7c0x00007ffac5450d84: ntdll!NtTraceControl+0x0000000000000014
0x00007ffac53f2f86: ntdll!EtwpRegisterProvider+0x00000000000000ba
0x00007ffac53f30e5: ntdll!EtwNotificationRegister+0x00000000000000a5
0x00007ffac53f2ea0: ntdll!EtwEventRegister+0x0000000000000020
0x00007ffac36ec5ef: MSCTF!TraceLoggingRegisterEx_EventRegister_EventSetInformation+0x0000000000000053
0x00007ffac36ec579: MSCTF!wil::TraceLoggingProvider::Register+0x0000000000000019
0x00007ffac36e46b4: MSCTF!wil::details::static_lazy<CtfTraceLoggingTelemetry>::get+0x0000000000000094
0x00007ffac36e460c: MSCTF!CtfTraceLoggingTelemetry::IsEnabled+0x0000000000000010
0x00007ffac36e42ac: MSCTF!CtfTraceLoggingTelemetry::InputSessionStarted<unsigned short (&)[41],unsigned long &,_GUID &,_GUID &,unsigned short &,bool &,unsigned long &,unsigned long &,unsigned long &,bool &,unsigned long,bool &>+0x0000000000000034
0x00007ffac36e40b8: MSCTF!CInputSessionMgr::UpdateInputSession+0x0000000000000338
0x00007ffac36f378b: MSCTF!SYSTHREAD::RouteKeyToInputService+0x0000000000000103
0x00007ffac36f33f1: MSCTF!SYSTHREAD::OnKeyboardEvent+0x00000000000000d1
--------------------------------------
Handle = 0x00000000000002b4 - OPEN
Thread ID = 0x000000000000172c, Process ID = 0x0000000000003d7c0x00007ffac5450d84: ntdll!NtTraceControl+0x0000000000000014
0x00007ffac53f2f86: ntdll!EtwpRegisterProvider+0x00000000000000ba
0x00007ffac53f30e5: ntdll!EtwNotificationRegister+0x00000000000000a5
0x00007ffac53f2ea0: ntdll!EtwEventRegister+0x0000000000000020
0x00007ffac46f261f: ole32!InitializeTracing+0x000000000000016f
0x00007ffac4709727: ole32!DllMain+0x0000000000000033
0x00007ffac470650f: ole32!dllmain_dispatch+0x000000000000008f
0x00007ffac53c9a1d: ntdll!LdrpCallInitRoutine+0x0000000000000061
0x00007ffac541d2f7: ntdll!LdrpInitializeNode+0x00000000000001d3
0x00007ffac541d08a: ntdll!LdrpInitializeGraphRecurse+0x0000000000000042
0x00007ffac53ed947: ntdll!LdrpPrepareModuleForExecution+0x00000000000000bf
0x00007ffac53cfbae: ntdll!LdrpLoadDllInternal+0x000000000000019a
--------------------------------------
Handle = 0x00000000000002b0 - OPEN
Thread ID = 0x000000000000172c, Process ID = 0x0000000000003d7c0x00007ffac5450d84: ntdll!NtTraceControl+0x0000000000000014
0x00007ffac53f2f86: ntdll!EtwpRegisterProvider+0x00000000000000ba
0x00007ffac53f30e5: ntdll!EtwNotificationRegister+0x00000000000000a5
0x00007ffac53f2ea0: ntdll!EtwEventRegister+0x0000000000000020
0x00007ffac46f25b3: ole32!InitializeTracing+0x0000000000000103
0x00007ffac4709727: ole32!DllMain+0x0000000000000033
0x00007ffac470650f: ole32!dllmain_dispatch+0x000000000000008f
0x00007ffac53c9a1d: ntdll!LdrpCallInitRoutine+0x0000000000000061
0x00007ffac541d2f7: ntdll!LdrpInitializeNode+0x00000000000001d3
0x00007ffac541d08a: ntdll!LdrpInitializeGraphRecurse+0x0000000000000042
0x00007ffac53ed947: ntdll!LdrpPrepareModuleForExecution+0x00000000000000bf
0x00007ffac53cfbae: ntdll!LdrpLoadDllInternal+0x000000000000019a
--------------------------------------
Handle = 0x00000000000002ac - OPEN
Thread ID = 0x000000000000172c, Process ID = 0x0000000000003d7c0x00007ffac5450d84: ntdll!NtTraceControl+0x0000000000000014
0x00007ffac53f2f86: ntdll!EtwpRegisterProvider+0x00000000000000ba
0x00007ffac53f30e5: ntdll!EtwNotificationRegister+0x00000000000000a5
0x00007ffac53f2aaa: ntdll!EtwRegisterTraceGuidsW+0x000000000000009a
0x00007ffac46f2564: ole32!InitializeTracing+0x00000000000000b4
0x00007ffac4709727: ole32!DllMain+0x0000000000000033
0x00007ffac470650f: ole32!dllmain_dispatch+0x000000000000008f
0x00007ffac53c9a1d: ntdll!LdrpCallInitRoutine+0x0000000000000061
0x00007ffac541d2f7: ntdll!LdrpInitializeNode+0x00000000000001d3
0x00007ffac541d08a: ntdll!LdrpInitializeGraphRecurse+0x0000000000000042
0x00007ffac53ed947: ntdll!LdrpPrepareModuleForExecution+0x00000000000000bf
0x00007ffac53cfbae: ntdll!LdrpLoadDllInternal+0x000000000000019a
--------------------------------------
Handle = 0x0000000000000298 - OPEN
Thread ID = 0x000000000000388c, Process ID = 0x0000000000003d7c0x00007ffac544dc74: ntdll!NtDuplicateObject+0x0000000000000014
0x00007ffac2d6b37c: KERNELBASE!DuplicateHandle+0x000000000000004c
0x00007ffac35b0e03: RPCRT4!THREAD::THREAD+0x0000000000000087
0x00007ffac35b0d58: RPCRT4!ThreadSelfHelper+0x0000000000000028
0x00007ffac35c5850: RPCRT4!RpcpSetThreadpoolCallbackInstance+0x0000000000000050
0x00007ffac35d1343: RPCRT4!PerformGarbageCollection+0x0000000000000023
0x00007ffac5422719: ntdll!TppTimerpExecuteCallback+0x00000000000000a9
0x00007ffac53fd79a: ntdll!TppWorkerThread+0x000000000000068a
0x00007ffac37e7374: KERNEL32!BaseThreadInitThunk+0x0000000000000014
0x00007ffac53fcc91: ntdll!RtlUserThreadStart+0x0000000000000021
--------------------------------------
Handle = 0x0000000000000294 - OPEN
Thread ID = 0x000000000000388c, Process ID = 0x0000000000003d7c0x00007ffac544ddf4: ntdll!NtCreateEvent+0x0000000000000014
0x00007ffac2d66dfb: KERNELBASE!CreateEventW+0x000000000000006b
0x00007ffac35b2bc5: RPCRT4!EVENT::EVENT+0x000000000000002d
0x00007ffac35b0da6: RPCRT4!THREAD::THREAD+0x000000000000002a
0x00007ffac35b0d58: RPCRT4!ThreadSelfHelper+0x0000000000000028
0x00007ffac35c5850: RPCRT4!RpcpSetThreadpoolCallbackInstance+0x0000000000000050
0x00007ffac35d1343: RPCRT4!PerformGarbageCollection+0x0000000000000023
0x00007ffac5422719: ntdll!TppTimerpExecuteCallback+0x00000000000000a9
0x00007ffac53fd79a: ntdll!TppWorkerThread+0x000000000000068a
0x00007ffac37e7374: KERNEL32!BaseThreadInitThunk+0x0000000000000014
0x00007ffac53fcc91: ntdll!RtlUserThreadStart+0x0000000000000021
--------------------------------------
Handle = 0x0000000000000280 - OPEN
Thread ID = 0x000000000000172c, Process ID = 0x0000000000003d7c0x00007ffac544eb64: ntdll!NtCreateMutant+0x0000000000000014
0x00007ffac2d38fa8: KERNELBASE!CreateMutexExW+0x0000000000000058
0x00007ff6436c6f00: CPPWindowsProject1!WndProc+0x00000000000000d0
0x00007ffac50cef5c: USER32!UserCallWinProcCheckWow+0x000000000000050c
0x00007ffac50ce684: USER32!DispatchMessageWorker+0x0000000000000494
0x00007ff6436c1d57: CPPWindowsProject1!wWinMain+0x0000000000000117
0x00007ff6436c2c62: CPPWindowsProject1!invoke_main+0x0000000000000032
0x00007ff6436c2b12: CPPWindowsProject1!__scrt_common_main_seh+0x0000000000000132
0x00007ff6436c29ce: CPPWindowsProject1!__scrt_common_main+0x000000000000000e
0x00007ff6436c2cfe: CPPWindowsProject1!wWinMainCRTStartup+0x000000000000000e
0x00007ffac37e7374: KERNEL32!BaseThreadInitThunk+0x0000000000000014
0x00007ffac53fcc91: ntdll!RtlUserThreadStart+0x0000000000000021
--------------------------------------
Displayed 0x9 stack traces for outstanding handles opened since the previous snapshot.
代码中构造的mutex泄露,查找!htrace -diff输出内容,找到CPPWindowsProject1!WndProc+0x00000000000000d0
使用lsa CPPWindowsProject1!WndProc+0x00000000000000d0查看代码,如下:
143: {144: case IDM_ABOUT:145: //_condition_variable = new std::condition_variable();146: //_mutex = new std::mutex();
> 147: _mutexHandle = CreateMutex(NULL, FALSE, L"abc");148: DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);149: break;150: case IDM_EXIT:151: DestroyWindow(hWnd);152: break;
找到147行的代码位置。
windbg的lsa指令:显式指令对应的源码
相关文章:
WinDBG查找C++句柄泄露
C代码(频繁点击About按钮导致Mutex句柄泄露) HANDLE _mutexHandle;LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {switch (message){case WM_COMMAND:{int wmId LOWORD(wParam);// 分析菜单选择:switch (wmId){c…...
Linux查看服务器的内外网地址
目录: 1、内网地址2、外网地址3、ping时显示地址与真实不一致 1、内网地址 ifconfig2、外网地址 curl ifconfig.me3、ping时显示地址与真实不一致 原因是dns缓存导致的,ping这种方法也是不准确的,有弊端不建议使用,只适用于测试…...
深入MapReduce——引入
引入 前面我们已经深入了HDFS的设计与实现,对于分布式系统也有了不错的理解。 但HDFS仅仅解决了海量数据存储和读写的问题。要想让数据产生价值,一定是需要从数据中挖掘出价值才行,这就需要我们拥有海量数据的计算处理能力。 下面我们还是…...
Oracle之开窗函数使用
Oracle中的开窗函数(Window Functions)是一种强大的工具,用于在SQL查询中对数据进行复杂的分析和聚合操作,而无需改变原始查询结果的行数或顺序。以下是关于Oracle开窗函数的使用方法和常见示例: 1. 开窗函数的基本语法…...
航空客户价值的数据挖掘与分析(numpy+pandas+matplotlib+scikit-learn)
文章目录 航空客户价值的数据挖掘与分析(numpy+pandas+matplotlib+scikit-learn)写在前面背景与挖掘目标1.1 需求背景1.2 挖掘目标1.3 项目概述项目分析方法规划2.1 RFM模型2.2 LRFMC模型指标2.3 分析总体流程图数据抽取探索及预处理3.1 数据抽取3.2 数据探索分析3.3 数据预处…...
云原生时代,如何构建高效分布式监控系统
文章目录 一.监控现状二.Thanos原理分析SidecarQuerierStoreCompactor 三.Sidecar or ReceiverThanos Receiver工作原理 四.分布式运维架构 一.监控现状 Prometheus是CNCF基金会管理的一个开源监控项目,由于其良好的架构设计和完善的生态,迅速成为了监控…...
什么是CIDR技术? 它是如何解决路由缩放问题的
什么是CIDR技术? 它是如何解决路由缩放问题的 一. 什么是 CIDR?二. CIDR 是如何工作的?1. 高效地址分配2. 路由聚合(Route Aggregation)3. 精确满足需求 三. CIDR 的计算详解1. 子网掩码计算2. 地址范围计算3. 可用 IP…...
Unity URP 获取/设置 Light-Indirect Multiplier
Unity URP 获取/设置 Light-Indirect Multiplier 他喵的代码的字段名称叫:bounceIntensity ~~~~~~...
用Python和Tkinter标准模块建立密码管理器
用Python和Tkinter标准模块建立密码管理器 创建一个简单的密码管理器应用程序,帮助用户存储和管理他们的密码。使用Python的tkinter模块来创建一个图形用户界面(GUI)。 本程序支持 添加、查看、搜索、复制、修改、删除 功能。 本程序使用 …...
PyQt5菜单加多页签实现
pyqt tabs标签_哔哩哔哩_bilibili 代码实现 # coding:utf-8 import sys from PyQt5.QtCore import Qt from PyQt5 import QtCore,QtWidgets from PyQt5.QtWidgets import QApplication,QWidget from QhTabs01 import Ui_Form from PyQt5.Qt import *class QhLiangHuaGUI(QWidg…...
关注搜索引擎蜘蛛压力
以前在建站的时候,他们说蜘蛛来抓取的频率越多越好,因为蜘蛛来抓取说明了网站更新速度快,受搜索引擎的欢迎,但是在最近的网站统计中,发现很多蜘蛛爬取的频次非常的高,比如有的蜘蛛一天能来网站几万次&#…...
Python3 OS模块中的文件/目录方法说明三
一. 简介 前面文章简单学习了Python3中 OS模块中的文件/目录的部分函数。 本文继续来学习 OS模块中文件、目录的操作方法:os.fdopen()方法、os.fpathconf() 方法、os.fstat() 方法、os.fstatvfs() 方法。 二. Python3 OS模块中的文件/目录方法说明三 1. os.fdop…...
2024年终总结:技术成长与突破之路
文章目录 前言一、技术成长:菜鸟成长之路1. 学习与实践的结合2. 技术分享与社区交流 二、生活与事业的平衡:技术之外的思考1. 时间管理与效率提升2. 技术对生活的积极影响 三、突破与展望:未来之路1. 技术领域的突破2. 未来规划与目标 四、结…...
mysql-06.JDBC
目录 什么是JDBC: 为啥存在JDBC: JDBC工作原理: JDBC的优势: 下载mysql驱动包: 用java程序操作数据库 1.创建dataSource: 2.与服务端建立连接 3.构造sql语句 4.执行sql 5.关闭连接,释放资源 参考代码: 插…...
使用python调用JIRA6 进行OAuth1认证获取AccessToken
Jira配置应用程序链接 1) 创建应用程序链接 登录 JIRA 管理后台。转到 Administration > Applications > Application Links。在输入框中输入外部应用程序的 URL(例如 GitLab 或自定义应用),然后点击 Create new link。 2) 配置 Con…...
HTML5使用favicon.ico图标
目录 1. 使用favicon.ico图标 1. 使用favicon.ico图标 favicon.ico一般用于作为网站标志,它显示在浏览器的地址栏或者标签上 制作favicon图标 选择一个png转ico的在线网站,这里以https://www.bitbug.net/为例。上传图片,目标尺寸选择48x48&a…...
黑龙江锅包肉:酸甜香酥的东北经典
黑龙江锅包肉:酸甜香酥的东北经典 黑龙江锅包肉,作为东北菜的代表之一,尤其在黑龙江省哈尔滨市享有极高的声誉。这道美食不仅承载着丰富的历史文化内涵,更以其鲜明的地域特色,成为了黑龙江省乃至整个东北地区的标志性菜肴。 历史渊源 锅包肉的历史可以追溯到清朝光绪年间,其…...
Unity阿里云OpenAPI 获取 Token的C#【记录】
获取Token using UnityEngine; using System; using System.Text; using System.Linq; using Newtonsoft.Json.Linq; using System.Security.Cryptography; using UnityEngine.Networking; using System.Collections.Generic; using System.Globalization; using Cysharp.Thr…...
winfrom项目,引用EPPlus.dll实现将DataTable 中的数据保存到Excel文件
最近研究不安装office也可以保存Excel文件,在网上查询资料找到这个方法。 第一步:下载EPPlus.dll文件(自行去网上搜索下载) 第二步:引用到需要用的项目中,如图所示: 第三步:写代码…...
【C++基础】多线程并发场景下的同步方法
如果在多线程程序中对全局变量的访问没有进行适当的同步控制(例如使用互斥锁、原子变量等),会导致多个线程同时访问和修改全局变量时发生竞态条件(race condition)。这种竞态条件可能会导致一系列不确定和严重的后果。…...
30岁裸辞后,我用两个月拿下AI应用认证,现在OFFER选择困难症犯了
30岁裸辞那天,我最怕的不是没收入,而是突然发现:过去积累的经验,正在被AI重新定价。以前会写方案、做表格、跟项目,算是职场硬通货;到了2026年,招聘JD里开始频繁出现AI工具应用、智能工作流、Pr…...
从RD、CS到WK:一文讲透SAR主流成像算法的演进与选型实战
从RD、CS到WK:SAR成像算法选型实战指南 当无人机掠过灾区上空,或卫星扫描地球表面时,合成孔径雷达(SAR)正通过电磁波穿透云层和黑暗,将地面信息转化为高分辨率图像。而决定图像质量的关键,在于工…...
Unity渲染排序三要素:SortingLayer、Order in Layer与RenderQueue协同原理
1. 为什么刚进Unity的美术和程序总在“图层遮挡”上反复拉扯?“这个UI怎么被背景挡住了?”“粒子特效一开就穿模,明明Z轴没问题!”“我调了Order in Layer到999,还是被另一个Sprite挡住——它连Sorting Layer都没改过&…...
量子纠错码VarQEC:原理、实现与硬件优化
1. 量子纠错码基础与实验背景量子纠错码(Quantum Error Correction Codes, QEC)是量子计算中保护量子信息免受噪声影响的核心技术。与经典纠错码不同,量子纠错需要应对量子态特有的退相干和纠缠特性。传统QEC如[[5,1,3]]完美码虽然理论完备&a…...
用图神经网络做缺陷定位,准确率比传统方法高出30%
在现代软件工程的复杂迷宫中,缺陷定位始终是测试团队面临的核心挑战。想象这样一个场景:一个电商系统在特定压力条件下偶发订单丢失,日志中只留下泛泛的超时错误,问题可能深藏在上百个微服务的调用链、分布式事务的竞态条件或某个…...
【大模型聚合平台深度评测:阿里云百炼 vs 腾讯云 ADP,企业如何选型?】
大模型聚合平台深度评测:阿里云百炼 vs 腾讯云 ADP,企业如何选型? 随着大模型技术的快速发展,越来越多的企业开始将 AI 能力融入到业务流程中。然而,面对市场上众多的大模型产品,企业往往面临着 “选择困难…...
昇腾NPU模型服务化——从离线模型到高可用推理服务
模型训练完只是第一步。真正产生业务价值的是把模型部署成724小时在线服务——毫秒级延迟、支持动态Batching、能扛住流量洪峰,且具备高可用性。 这篇将手把手教你基于昇腾NPU构建生产级模型推理服务,涵盖框架选型、服务化架构、动态Batching优化、热加载…...
为什么92%的数据库重构失败?Claude设计辅助如何在48小时内规避反范式陷阱?
更多请点击: https://codechina.net 第一章:为什么92%的数据库重构失败?——反范式陷阱的本质溯源 数据库重构失败率高达92%,其核心症结并非技术能力不足,而是对“反范式”这一设计策略的误读与滥用。许多团队在性能压…...
DSP、FPGA、STM32大对决:谁才是嵌入式开发的“天选之子”?
在嵌入式开发的广阔天地里,DSP、FPGA 和 STM32(作为通用 MCU 的典型代表)可以说是三款绕不开的核心处理器。很多初学者甚至有一定经验的工程师在选择时都会陷入纠结:我的项目到底该选哪一个?为了帮你彻底理清思路&…...
Diablo Edit2:3步掌握暗黑破坏神2存档修改的终极秘籍
Diablo Edit2:3步掌握暗黑破坏神2存档修改的终极秘籍 【免费下载链接】diablo_edit Diablo II Character editor. 项目地址: https://gitcode.com/gh_mirrors/di/diablo_edit 还在为暗黑破坏神2中刷装备的漫长过程感到疲惫吗?Diablo Edit2这款免费…...
