dotnet 简单写一个 pdb 符号文件下载器

news/2024/11/28 10:44:10/文章来源:https://www.cnblogs.com/lindexi/p/18571309

本文将以拉取 ntdll.dll 为例子告诉大家如何从 msdl.microsoft.com 下载符号

我先将自己电脑上的 ntdll.dll 拷贝到输出路径,方便我进行访问。读取 C 盘的 Windows 文件夹的 DLL 文件也是有读取权限的,即不拷贝到输出路径也不会有任何的问题的

整体步骤是先读取 dll 的 PE 文件信息,获取到调试信息,即 PDB 名加 Guid 和 Age 参数,由以上三个参数拼接为下载地址

本文使用的 PEReader 等辅助类为 .NET Core 1.0 引入,如需在 .NET Framework 使用,请安装 System.Reflection.Metadata 库

本文建立的是 dotnet 9 的控制台文件

先使用 File.OpenRead 打开要读取的 DLL 文件,代码如下

var file = @"ntdll.dll";using var fileStream = File.OpenRead(file);

接着放入到 PEReader 里面读取,如此即可非常方便完成对 PE 文件的读取,代码如下

var peReader = new PEReader(fileStream);

尝试读取传入的 PE 文件的调试目录信息,代码如下

var debugDirectoryEntries = peReader.ReadDebugDirectory();

这里的调试目录可能有很多,咱只需使用 DebugDirectoryEntryType.CodeView 类型的即可

foreach (var debugDirectoryEntry in debugDirectoryEntries)
{if (debugDirectoryEntry.Type != DebugDirectoryEntryType.CodeView){continue;}...
}

在 DebugDirectoryEntry 里面存放的只是一些地址偏移和大小的信息,需要进一步调用 ReadCodeViewDebugDirectoryData 方法读取到更多信息,代码如下

foreach (var debugDirectoryEntry in debugDirectoryEntries)
{if (debugDirectoryEntry.Type != DebugDirectoryEntryType.CodeView){continue;}var readCodeViewDebugDirectoryData = peReader.ReadCodeViewDebugDirectoryData(debugDirectoryEntry);var path = readCodeViewDebugDirectoryData.Path;var guid = readCodeViewDebugDirectoryData.Guid;var age = readCodeViewDebugDirectoryData.Age;var pdbName = path;...
}

如此即可获取到下载地址拼接的信息

    var downloadUrl = $"http://msdl.microsoft.com/download/symbols/{pdbName}/{(guid.ToString("N").ToUpperInvariant() + age.ToString())}/{pdbName}";

继续使用 HttpClient 将其下载下来,代码如下

    var httpClient = new HttpClient();using var httpResponseMessage = await httpClient.GetAsync(downloadUrl, HttpCompletionOption.ResponseHeadersRead);var pdbFile = Path.GetFullPath(pdbName);await using var downloadFileStream = File.Create(pdbFile);await httpResponseMessage.Content.CopyToAsync(downloadFileStream);

下载文件的方法十分简单,先是准备要下载的文件存放的路径,我这里使用的是相对工作路径的方式,即 var pdbFile = Path.GetFullPath(pdbName); 简单的方式拿到绝对路径。这里获取绝对路径仅仅只是为了方便调试而已,无实际逻辑意义

接着使用 File.Create 方法创建文件,且返回 FileStream 对象,方便进行下载内容的 CopyToAsync 写入到文件

以上代码的另一个细节是请求的时候带上了 HttpCompletionOption.ResponseHeadersRead 参数,带上这个参数将告诉 HttpClient 不要等待内容都拉取完了再让 GetAsync 方法返回,而是只要 http 的头信息拿到了,就应该返回了。这一点对下载文件来说,比较有优化,大部分下载的文件的文件长度都不小,全等待下载完成再让 GetAsync 返回,再拷贝到文件,这个逻辑相对来说是比较亏的。只有对 API 调用形的后台访问,才合适使用默认的 HttpCompletionOption.ResponseContentRead 参数,全部完成再返回,如此可以更简化异常处理情况,确保网络通讯完成再返回

通过上文简单的方式即可完成对 DLL 的符号文件下载

以上代码其实还隐藏了另一个功能,那就是自己组建符号服务器,可以自己在构建完成之后,根据如上信息,将 PDB 符号文件存放到合适的路径里面或记录到数据库里面,不依赖 symstore 工具

本文的 Program.cs 代码如下

using System.Reflection.PortableExecutable;
using System.Runtime.InteropServices;
using System.Text;var file = @"ntdll.dll";using var fileStream = File.OpenRead(file);var peReader = new PEReader(fileStream);
var httpClient = new HttpClient();var debugDirectoryEntries = peReader.ReadDebugDirectory();
foreach (var debugDirectoryEntry in debugDirectoryEntries)
{if (debugDirectoryEntry.Type != DebugDirectoryEntryType.CodeView){continue;}var readCodeViewDebugDirectoryData = peReader.ReadCodeViewDebugDirectoryData(debugDirectoryEntry);var path = readCodeViewDebugDirectoryData.Path;var guid = readCodeViewDebugDirectoryData.Guid;var age = readCodeViewDebugDirectoryData.Age;var pdbName = path;var downloadUrl = $"http://msdl.microsoft.com/download/symbols/{pdbName}/{(guid.ToString("N").ToUpperInvariant() + age.ToString())}/{pdbName}";using var httpResponseMessage = await httpClient.GetAsync(downloadUrl, HttpCompletionOption.ResponseHeadersRead);var pdbFile = Path.GetFullPath(pdbName);await using var downloadFileStream = File.Create(pdbFile);await httpResponseMessage.Content.CopyToAsync(downloadFileStream);
}

本文代码放在 github 和 gitee 上,可以使用如下命令行拉取代码。我整个代码仓库比较庞大,使用以下命令行可以进行部分拉取,拉取速度比较快

先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码

git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 6bc0a171f53f4da8a968257c621c9df7a6de77a3

以上使用的是国内的 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码,将 gitee 源换成 github 源进行拉取代码。如果依然拉取不到代码,可以发邮件向我要代码

git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin 6bc0a171f53f4da8a968257c621c9df7a6de77a3

获取代码之后,进入 Workbench/WerjiwaijogoNemcuryecho 文件夹,即可获取到源代码

更多技术博客,请参阅 博客导航

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

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

相关文章

读数据质量管理:数据可靠性与数据质量问题解决之道16数据认证

数据认证1. 对数据进行认证 1.1. 数据认证是指在数据资产满足关于数据质量、可观测性、权责分配、问题解决和沟通等公司内共同遵守的SLA后,批准它们被用于整个组织的过程 1.2. 数据认证为人员、框架和技术构建了关键流程,使其与核心业务政策保持一致 1.3. 数据认证的要求会因…

FinalShell-Decoder:一款FinallShell密码解密的GUI工具

项目介绍 FinalShell-Decoder是一款FinallShell密码解密的GUI工具,目前使用 Maven 进行了重构,jdk11以上版本可自行打包,使用时记得添加环境变量 : java--module-path "%JDK_INSTALL_PATH%\javafx-sdk-11.0.2\lib" --add-modules javafx.controls,javafx.fxml -ja…

鸿蒙NEXT元服务:利用App Linking实现无缝跳转与二维码拉起

【效果】 元服务链接格式(API>=12适用):https://hoas.drcn.agconnect.link/ggMRM 生成二维码后效果:​ 【参考网址】 使用App Linking实现元服务跳转:https://developer.huawei.com/consumer/cn/doc/AppGallery-connect-Guides/agc-applinking-atomic-link-0000002046…

模糊耗散合成神经编解码器中的拉普拉斯熵模型

模糊耗散合成神经编解码器中的拉普拉斯熵模型 虽然用条件扩散模型代替高斯解码器,可以提高神经图像压缩中重建的感知质量,但它们缺乏对图像数据的感应偏差,限制了它们实现最先进感知水平的能力。为了解决这一局限性,在解码器侧采用了非各向同性扩散模型。该模型施加了一种感…

记一次固态硬盘玩游戏卡顿的解决过程

现在是2024年11月27日,星期三 我的系统是windows 10,这一段时间我给我的笔记本电脑换了一个1t的固态硬盘,原先是500G的固态硬盘, 把系统复制过来之后,正常使用,电脑使用一些比如浏览器呀,vscode之类的软件都没啥问题, 我喜欢玩永劫无间这个游戏,这个游戏也算是大型游戏了, 然后…

朋友

朋友 题目背景 小明在 A 公司工作,小红在 B 公司工作。 题目描述 这两个公司的员工有一个特点:一个公司的员工都是同性。 A 公司有 \(N\) 名员工,其中有 \(P\) 对朋友关系。B 公司有 \(M\) 名员工,其中有 \(Q\) 对朋友关系。朋友的朋友一定还是朋友。 每对朋友关系用两个整…

Golang网络模型netpoll源码解析

0、引言 在学习完了Socket编程的基础知识、Linux系统提供的I/O多路复用的实现以及Golang的GMP调度模型之后,我们进而学习Golang的网络模型——netpoll。本文将从为什么需要使用netpoll模型,以及netpoll的具体流程实现两个主要角度来展开学习。当前使用的Go的版本为1.22.4,Li…

骁龙 8 Elite 至尊版 对比 电脑端cpu

台式/笔记本 参考https://socpk.com/cpu/ 骁龙 8 Elite是260 M4 (4+6) 是360而M4对比笔记本cpu参考

线性版本HierHolzer正确性说明

晚上在研究怎么求欧拉图回路,看到 \(O(n+m)\) 版本的 HierHolzer 算法实现,让我很迷惑。 void dfs(int x){for(int i = 1;i <= 500; ++i){if(g[x][i]){--g[x][i]; --g[i][x];dfs(i);}}ans[++cnt] = x; }OI-Wiki 上对于这段代码的描述是这样的:将找回路的 DFS 和 Hierholz…

plus_one

2024/11/26 --2024/11/28 验证哥德巴赫猜想 打印漏斗 1.统计字符 1. 不需要数组,在循环中统计各个种类的字符 2. 一定把各个种类初始化为0 3. 一个一个字符输入,不是字符串一次输入哦 4. 空格是 回车是 \n 5. 大小写字母的ASCII码不连续,所以是(s >= a&& s<…

Python基础语法 11月22日到11月26日学习过程

Python的环境配置 python安装安装地址官网网址:https://www.python.org 华为云镜像站地址:https://mirrors.huaweicloud.com/homepython根目录介绍根目录截图python的根目录【安装目录】:D:\soft\Python37Scriptspip # 从python官网上下载第三方的库 pip3.7 pip3Lib # py…