如何使用 Hardware ID Extractor 修复 Ntdll.dll APPCRASH?

How to fix Ntdll.dll APPCRASH with Hardware ID Extractor?

我正在使用 http://www.soft.tahionic.com/download-hdd_id/index.html 的硬件 ID 提取器库(用 Delphi 编写),目的是生成唯一的系统指纹。

这个库真的很好,不像我在市场上看到的其他任何东西,但它的主要问题是它在 运行 .NET 应用程序时不稳定,这意味着它有时可以工作,有时则不行适用于几个函数调用,然后主应用程序崩溃,或者大多数时候应用程序在调用 dll 函数时立即崩溃。

正如库的开发者所指出的(在我收到的最后一封支持电子邮件中),问题出在 ntdll.dll,正如我亲眼所见:

以下是我为测试 dll 函数而创建的演示项目的 link(因此,为了确保没有其他干扰,演示应用程序会执行此操作,并且只会执行此操作 - 它调用dll函数)。 http://www.mediafire.com/download/1jws7zh9218v88a/HardwareIdExtractDllTest.zip 该存档包含 Visual Studio 2013 项目,带有源代码和编译的演示应用程序,如下所示:

dll 包含的函数列表可以在这里找到: http://www.soft.tahionic.com/download-hdd_id/hardware%20id%20programming%20source%20code/exported%20functions%20for%20non-Delphi.html

如果哪位有知识愿意测试demoproject/application对问题进行测试或发表个人意见,然后与我分享可能的解决方案,将不胜感激。

如果您认为有什么办法可以解决这个问题,请告诉我是否可以做些什么来进一步帮助解决这个问题。

编辑:这就是我声明 dll 函数的方式

    [DllImport("HardwareIDExtractorC.dll")]
    private static extern bool EnterKey(int key);

    [DllImport("HardwareIDExtractorC.dll")]
    private static extern bool IsCPUIDAvailable();

    [DllImport("HardwareIDExtractorC.dll")]
    private static extern int GetCPUCount();

    [DllImport("HardwareIDExtractorC.dll")]
    private static extern byte CoreNumber2CoreMask(byte cpuCore);

    [DllImport("HardwareIDExtractorC.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, EntryPoint = "GetCPUID")]
    [return: MarshalAs(UnmanagedType.LPStr)]
    private static extern string GetCPUID(byte cpuCore);

    [DllImport("HardwareIDExtractorC.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, EntryPoint = "GetCpuIdNow")]
    [return: MarshalAs(UnmanagedType.LPStr)]
    private static extern string GetCpuIdNow(); 

    [DllImport("HardwareIDExtractorC.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, EntryPoint = "GetIDESerialNumber")]
    [return: MarshalAs(UnmanagedType.LPStr)]
    private static extern string GetIDESerialNumber(byte driveNumber);

失败的功能是 return string。这样的 p/invoke 将 return 值编组为指向空终止字符数组的指针,然后在由非托管代码 return 编辑的原始指针上调用 CoTaskMemFree

字符串未分配到 COM 堆的概率接近 1,因此错误很可能出现在 C# p/invoke 声明中。然后在 ntdll 中出现访问冲突是非常合理的。

因此,要取得进展,您需要修复 p/invoke 调用。我无法告诉您如何操作,因为您没有显示非托管函数声明。或者,更重要的是,内存是如何分配的。


documentation

有一些线索
procedure ReleaseMemory (P: PAnsiChar); stdcall;

我认为这告诉我们 DLL 编辑的字符串 return 必须由 DLL 通过调用此函数释放。大概是因为它们是由 DLL 的堆分配器分配的。

因此,return 函数的 return 类型使用 IntPtr,return 文本。调用 Marshal.PtrToStringAnsi 转换为 C# 字符串。然后将指针传递给ReleaseMemory

例如:

[DllImport(DllPath, CallingConvention = CallingConvention.StdCall)]
private static extern IntPtr GetCPUID(ushort CoreMask);

[DllImport(DllPath, CallingConvention = CallingConvention.StdCall)]
private static extern void ReleaseMemory(IntPtr P);

....

IntPtr ptr = GetCPUID(CoreMask);
string cpuid = Marshal.PtrToStringAnsi(ptr);
ReleaseMemory(ptr);