跳转到主要内容

用于追踪Windows DLL加载的Python模块

项目描述

dlltracer

《dlltracer》工具是用于诊断Windows上DLL解析失败导致的CPython导入错误的一种辅助工具。

通常,任何DLL加载错误都报告为顶层扩展模块的ImportError。CPython无法显示更具体的信息,这可能会使得诊断变得困难。

此工具使用未充分记录的性能事件来报告导入扩展模块的中间步骤。这些事件未记录且不受支持,因此格式是通过示例推断出来的,可能会改变,但在它改变之前,它将报告实际发生的加载情况。然而,因为它无法报告从未发生的加载情况,所以您仍然需要进行一些工作来诊断失败的根源。

最有用的静态分析工具是dumpbin,它包含在Visual Studio中。当传递DLL或PYD文件以及/imports选项时,它将列出所有应加载的依赖项。它通过名称显示它们,即在路径解析之前。

dlltracer执行动态分析,显示在运行时加载的DLL及其完整路径。结合理解您模块的依赖关系图,更容易诊断整体导入失败的原因。

安装

pip install dlltracer

在您的环境中,pip命令可能需要替换为更合适的命令,例如python -m pippip3.9

使用

注意:无论输出如何收集,此工具都必须以管理员身份运行。否则,启动跟踪将失败,并出现PermissionError。整个机器上只能有一个线程进行跟踪。因为Windows无法很好地管理跟踪状态,所以此工具将尝试停止任何其他正在运行的跟踪。

基本跟踪,将消息打印到标准输出

import dlltracer
import sys

with dlltracer.Trace(out=sys.stdout):
    import module_to_trace

输出可能如下所示(对于import ssl

LoadLibrary \Device\HarddiskVolume3\Windows\System32\kernel.appcore.dll
LoadLibrary \Device\HarddiskVolume3\Program Files\Python39\DLLs\_ssl.pyd
LoadLibrary \Device\HarddiskVolume3\Windows\System32\crypt32.dll
LoadLibrary \Device\HarddiskVolume3\Program Files\Python39\DLLs\libcrypto-1_1.dll
LoadLibrary \Device\HarddiskVolume3\Program Files\Python39\DLLs\libssl-1_1.dll
LoadLibrary \Device\HarddiskVolume3\Windows\System32\user32.dll
LoadLibrary \Device\HarddiskVolume3\Windows\System32\win32u.dll
LoadLibrary \Device\HarddiskVolume3\Windows\System32\gdi32.dll
LoadLibrary \Device\HarddiskVolume3\Windows\System32\gdi32full.dll
LoadLibrary \Device\HarddiskVolume3\Windows\System32\msvcp_win.dll
LoadLibrary \Device\HarddiskVolume3\Windows\System32\imm32.dll
LoadLibrary \Device\HarddiskVolume3\Program Files\Python39\DLLs\_socket.pyd
LoadLibrary \Device\HarddiskVolume3\Program Files\Python39\DLLs\select.pyd

失败的导入可能如下所示(对于import ssl但缺少libcrypto-1_1.dll

LoadLibrary \Device\HarddiskVolume3\Windows\System32\kernel.appcore.dll
LoadLibrary \Device\HarddiskVolume3\Program Files\Python39\DLLs\_ssl.pyd
LoadLibrary \Device\HarddiskVolume3\Windows\System32\crypt32.dll
LoadLibrary \Device\HarddiskVolume3\Program Files\Python39\DLLs\libssl-1_1.dll
Failed \Device\HarddiskVolume3\Windows\System32\crypt32.dll
Failed \Device\HarddiskVolume3\Program Files\Python39\DLLs\libssl-1_1.dll
Failed \Device\HarddiskVolume3\Program Files\Python39\DLLs\_ssl.pyd
Traceback (most recent call last):
  File "C:\Projects\test-script.py", line 28, in <module>
    import ssl
  File "C:\Program Files\Python39\lib\ssl.py", line 98, in <module>
    import _ssl             # if we can't import it, let the error propagate
ImportError: DLL load failed while importing _ssl: The specified module could not be found.

请注意,缺少的DLL从未被提及,因此需要人工分析来诊断根本原因。

写入文件

要将输出写入文件对象(任何可以传递给printfile=参数的对象),将其作为Traceout=参数传递。

import dlltracer

with open("log.txt", "w") as log:
    with dlltracer.Trace(out=log):
        import module_to_trace

收集到列表

要将事件收集到可迭代的对象中,将collect=True传递给Trace并绑定上下文管理器。结果将是一个包含事件对象的列表,通常是dlltracer.LoadEventdlltracer.LoadFailedEvent

import dlltracer

with dlltracer.Trace(collect=True) as events:
    try:
        import module_to_trace
    except ImportError:
        # If we don't handle the error, program will exit before
        # we get to inspect the events.
        pass

# Inspect the events after ending the trace
all_loaded = {e.path for e in events if isinstance(e, dlltracer.LoadEvent)}
all_failed = {e.path for e in events if isinstance(e, dlltracer.LoadFailedEvent)}

引发审计事件

要为DLL加载引发审计事件,将audit=True传递给Trace。引发的事件是dlltracer.loaddlltracer.failed,并且两者都只包含路径作为参数。

import dlltracer
import sys

def hook(event, args):
    if event == "dlltracer.load":
        # args = (path,)
        print("Loaded", args[0])
    elif event == "dlltracer.failed":
        # args = (path,)
        print("Failed", args[0])

sys.add_audit_hook(hook)

with dlltracer.Trace(audit=True):
    import module_to_trace

其他事件

注意:这主要是为了开发dlltracer

因为事件格式可能会改变,并且可能对其他事件感兴趣但尚未处理,所以将debug=True选项传递给Trace将启用收集、写入或审计所有事件。常规事件被抑制。

import dlltracer
import sys

def hook(event, args):
    if event != "dlltracer.debug":
        return

    # args schema:
    #   provider is a UUID representing the event source
    #   opcode is an int representing the operation
    #   header is bytes taken directly from the event header
    #   data is bytes taken directly from the event data
    provider, opcode, header, data = args

sys.add_audit_hook(hook)

with dlltracer.Trace(debug=True, audit=True, collect=True, out=sys.stderr) as events:
    try:
        import module_to_trace
    except ImportError:
        pass

for e in events:
    assert isinstance(e, dlltracer.DebugEvent)
    # DebugEvent contains provider, opcode, header and data as for the audit event

贡献

此项目欢迎贡献和建议。大多数贡献都需要您同意贡献者许可协议(CLA),声明您有权并且实际上授予我们使用您贡献的权利。有关详细信息,请访问https://cla.opensource.microsoft.com

当您提交拉取请求时,CLA机器人将自动确定您是否需要提供CLA,并以适当的方式装饰PR(例如,状态检查,评论)。只需遵循机器人提供的说明即可。您只需要在整个使用我们的CLA的所有存储库中这样做一次。

此项目已采用Microsoft开源代码行为准则。有关更多信息,请参阅代码行为准则常见问题解答或通过opencode@microsoft.com联系以获取任何其他问题或评论。

商标

本项目可能包含项目、产品或服务的商标或标志。未经授权使用Microsoft商标或标志必须遵守并遵循Microsoft的商标和品牌指南。在修改版本的此项目中使用Microsoft商标或标志不得引起混淆或暗示Microsoft赞助。任何第三方商标或标志的使用均需遵守该第三方的政策。

项目详情


下载文件

下载适合您平台文件。如果您不确定选择哪一个,请了解更多关于安装包的信息。

源分发

dlltracer-1.0.2.tar.gz (109.9 kB 查看哈希值)

上传时间

构建分发

dlltracer-1.0.2-cp311-cp311-win_amd64.whl (84.1 kB 查看哈希值)

上传时间 CPython 3.11 Windows x86-64

dlltracer-1.0.2-cp310-cp310-win_amd64.whl (87.5 kB 查看哈希值)

上传时间 CPython 3.10 Windows x86-64

dlltracer-1.0.2-cp39-cp39-win_amd64.whl (87.6 kB 查看哈希值)

上传时间 CPython 3.9 Windows x86-64

dlltracer-1.0.2-cp38-cp38-win_amd64.whl (87.6 kB 查看哈希值)

上传时间 CPython 3.8 Windows x86-64

dlltracer-1.0.2-cp37-cp37-win_amd64.whl (85.0 kB 查看哈希值)

上传时间 CPython 3.7 Windows x86-64

由以下机构支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误记录 StatusPage StatusPage 状态页面