在内存中固定一个 DLL(增加引用计数) [英] Pinning a DLL in memory (increase reference count)

查看:35
本文介绍了在内存中固定一个 DLL(增加引用计数)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试运行一个应用程序,但该应用程序由于访问冲突而退出.在调试器中运行应用程序我可以看到这是由卸载的库引起的.我迫不及待地等待应用程序的下一个版本,所以我正在尝试解决这个问题.

I am trying to run an application, but the application exits due to an access violation. Running the application in the debugger I can see that this is caused by an unloaded library. I can not wait for the next release of the application, so I'm trying to workaround the problem.

我想知道 WinDbg 是否提供了一种增加加载模块的引用计数的方法,类似于 C++ LoadLibrary() 调用.然后我可以中断模块加载并增加受影响的 DLL 的引用计数,看看我是否可以使用该应用程序.

I wonder whether WinDbg provides a way of increasing the reference count of a loaded module, similar to the C++ LoadLibrary() call. I could then break on module loads and increase the reference count on the affected DLL to see if I can use the application then.

我已经寻找了以 .load!load.lock!lock 开头的命令, .mod!mod 在 WinDbg 帮助中..load 会将 DLL 作为扩展加载到调试器进程中,而不是加载到目标进程中.

I have already looked for commands starting with .load, !load, .lock, !lock, .mod and !mod in WinDbg help. .load will load the DLL as an extension into the debugger process, not into the target process.

更新

忘了说我没有源代码,所以我不能简单地实现 LoadLibrary() 调用作为解决方法并重新编译.

Forgot to mention that I have no source code, so I can't simply implement a LoadLibrary() call as a workaround and recompile.

Hans Passant 的评论将我引向 .call 并且我尝试使用它

The comment by Hans Passant leads me to .call and I tried to use it like

.call /v kernel32!LoadLibraryA("....dll")

但它给出了错误信息

符号不是'.call/v kernel32!LoadLibraryA("..dll")'中的函数

Symbol not a function in '.call /v kernel32!LoadLibraryA("....dll")'

更新 2

可能 .call 中文件名的字符串应该是指向目标进程中某些内存的指针,而不是驻留在我键入命令的 WinDbg.exe 中的字符串.这再次意味着我可能打算分配一些内存来存储字符串,所以这可能会变得更复杂.

Probably the string for the file name in .call should be a pointer to some memory in the target process instead of a string which resides in WinDbg.exe where I type the command. That again means I would probably mean to allocate some memory to store the string inside, so this might become more complex.

推荐答案

在 windbg 中使用 .call 对我来说一直很挑剔.我相信你遇到了问题,因为 kernel32 只有公共符号,所以调试器不知道它的参数是什么样的.

Using .call in windbg as always been finicky to me. I believe you are having trouble with it because kernel32 only has public symbols so the debugger doesn't know what it's arguments look like.

那么让我们看看一些替代方案...

So let's look at some alternatives...

您可以使用 Process Hacker 之类的工具,我认为这是对任何调试器工具的绝佳补充胸部.它可以选择将 DLL 注入进程.

You can go grab a tool like Process Hacker, which I think is a wonderful addition to any debugger's tool chest. It has an option to inject a DLL into a process.

在幕后,它调用 CreateRemoteThread 在目标进程中生成一个线程,该线程调用所选 DLL 上的 LoadLibrary.运气好的话,这将增加模块引用计数.您可以通过在 dll 注入之前和之后运行 !dlls 命令来验证 Windbg 中的 LoadCount 是否已增加.

Behind the scenes, it calls CreateRemoteThread to spawn a thread in the target process which calls LoadLibrary on the chosen DLL. With any luck, this will increase the module reference count. You can verify that the LoadCount has been increased in windbg by running the !dlls command before and after the dll injection.

您还可以深入研究 Windows 用于跟踪进程加载的模块并使用 LoadCount 的内部数据结构.这在 Windows 版本之间会发生变化,这是一个严重的禁忌.但是,我们正在调试,所以,到底是什么?让我们这样做.

You can also dig into the internal data structures Windows uses to keep track of a process's loaded modules and play with the LoadCount. This changes between versions of Windows and is a serious no-no. But, we're debugging, so, what the hell? Let's do this.

首先使用 !dlls 获取已加载模块的列表.假设我们关心 your.dll;我们可能会看到类似的内容:

Start by getting a list of loaded modules with !dlls. Suppose we care about your.dll; we might see something like:

0x002772a8: C:path	oyour.dll
      Base   0x06b80000  EntryPoint  0x06b81000  Size        0x000cb000    DdagNode     0x002b3a10
      Flags  0x800822cc  TlsIndex    0x00000000  LoadCount   0x00000001    NodeRefCount 0x00000001

我们可以看到当前加载计数为1.修改它,我们可以使用模块路径之前打印的地址.它是进程为该模块保存的 ntdll!_LDR_DATA_TABLE_ENTRY 的地址.

We can see that the load count is currently 1. To modify it, we could use the address printed before the module path. It is the address of the the ntdll!_LDR_DATA_TABLE_ENTRY the process holds for that module.

r? @$t0 = (ntdll!_LDR_DATA_TABLE_ENTRY*) 0x002772a8

而且,现在您可以将 LoadCount 成员更改为更大的内容:

And, now you can change the LoadCount member to something larger as so:

?? @$t0->LoadCount = 2

但是,正如我所说,这些东西会随着 Windows 的新版本而改变.在 Windows 8 上,LoadCount 成员已从 _LDR_DATA_TABLE_ENTRY 移出并移到新的 ntdll!_LDR_DDAG_NODE 结构中.取而代之的是一个 ObsoleteNodeCount,这不是我们想要的.

But, as I said, this stuff changes with new versions of Windows. On Windows 8, the LoadCount member was moved out of _LDR_DATA_TABLE_ENTRY and into a new ntdll!_LDR_DDAG_NODE structure. In place of it, there is now an ObsoleteNodeCount which is not what we want.

在 Windows 8 上,我们将运行以下命令:

On Windows 8, we would run the following command instead:

?? @$t0->DdagNode->LoadCount = 2

而且,是时候检查我们的工作了...

And, time to check our work...

0x002772a8: C:path	oyour.dll
      Base   0x06b80000  EntryPoint  0x06b81000  Size        0x000cb000    DdagNode     0x002b3a10
      Flags  0x800822cc  TlsIndex    0x00000000  LoadCount   0x00000002    NodeRefCount 0x00000001

棒极了.现在是2.这将教 FreeLibrary 在我们说可以之前卸载我们的 DLL.

Awesome. It's 2 now. That'll teach FreeLibrary a lesson about unloading our DLLs before we say it can.

先尝试简单的方法.如果这不起作用,您可以开始查看 Windows 用于跟踪此类内容的内部数据结构.我不提供困难的方法,希望您能实际尝试一下,但它可能会让您在将来更轻松地使用 !dlls 命令和那些数据结构.

Try the easy way first. If that doesn't work, you can start looking at the internal data structures Windows uses to keep track of this kind of stuff. I don't provide the hard way hoping you'll actually try it, but that it might make you more comfortable around the !dlls command and those data structures in the future.

尽管如此,所有对 LoadCount 的修改都会让您确认您看到 DLL 在它应该卸载之前被卸载了.如果在人为增加 LoadCount 后问题消失,这意味着您已经证实了您的理论,您将不得不采用不同的方法来调试它——弄清楚它何时以及为何被卸载.

Still, all modifying the LoadCount will afford you is confirmation that you are seeing a DLL get unloaded before it should have. If the problem goes away after artificially increasing the LoadCount, meaning that you've confirmed your theory, you'll have to take a different approach to debugging it -- figuring out when and why it got unloaded.

这篇关于在内存中固定一个 DLL(增加引用计数)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆