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

查看:920
本文介绍了在内存中固定一个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 ,<$ c在WinDbg帮助中,$ c>!lock , .mod !mod .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中的$ code> .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...

你可以去抓住进程黑客等工具,这对任何调试器的工具箱来说都是一个很好的补充。它有一个可以将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版本之间发生变化,是一个严重的no-no。但是,我们正在调试,那么到底是什么?

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\to\your.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\to\your.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天全站免登陆