【问题标题】:Best Practices for DLL Injection?DLL 注入的最佳实践?
【发布时间】:2013-04-21 16:58:05
【问题描述】:
假设我想将一个 DLL 注入一个想要每 250 毫秒编辑一次地址 A 的值的进程。我需要使用 DllMain,对吗?问题是我不允许在 DllMain 内等待。所以我必须创建一个线程?还是没有绕过限制?我该怎么做呢?
另外,使用 DLL 注入来编辑应用程序的内存比使用 EXE 有什么好处吗?
另外,CreateThread 中的堆栈大小应该是多少?如果它太小或太大怎么办?我怎么知道我需要多少?
【问题讨论】:
标签:
c++
dll
reverse-engineering
dll-injection
memory-editing
【解决方案1】:
根据您的描述,您似乎已经知道如何让目标进程加载您的 DLL。如果我的假设是正确的,那么答案很简单:从 DLLMain 创建一个线程并在线程中实现您的逻辑。只要您的代码遵守下面列出的规则,就可以了。
document 描述了在 DLLMain 中可以做什么和不可以做什么以及为什么。
如文档所述,您永远不应在 DllMain 中执行以下任务:
- 调用 LoadLibrary 或 LoadLibraryEx(直接或间接)。
这可能会导致死锁或崩溃。
- 与其他线程同步。这可能会导致死锁。
- 获取由等待获取加载器的代码拥有的同步对象
锁。这可能会导致死锁。
- 使用 CoInitializeEx 初始化 COM 线程。在一定条件下,这个函数可以调用
LoadLibraryEx。
- 调用注册表函数。这些函数在 Advapi32.dll 中实现。如果 Advapi32.dll 未在您的 DLL 之前初始化,则 DLL 可以访问未初始化的内存并导致进程崩溃。
- 调用 CreateProces。创建一个进程可以加载另一个 DLL。
- 调用退出线程。在 DLL 分离期间退出线程可能会导致再次获取加载程序锁,从而导致死锁或崩溃。
- 调用 CreateThread。如果你不与其他线程同步,创建一个线程可以工作,但它是有风险的。
- 创建命名管道或其他命名对象(仅限 Windows 2000)。在 Windows 2000 中,命名对象由终端服务 DLL 提供。如果此 DLL 未初始化,则对该 DLL 的调用可能会导致
崩溃的过程。
- 使用动态 C 运行时 (CRT) 中的内存管理功能。如果 CRT DLL 未初始化,对这些函数的调用可能会导致进程崩溃。
- 在 User32.dll 或 Gdi32.dll 中调用函数。某些函数加载另一个 DLL,该 DLL 可能未初始化。
- 使用托管代码。
在 DllMain 中可以安全地执行以下任务:
- 在编译时初始化静态数据结构和成员。
- 创建和初始化同步对象
- 分配内存并初始化动态数据结构(避免上面列出的函数。)
- 设置线程本地存储 (TLS)。
- 打开、读取和写入文件。
- 调用 Kernel32.dll 中的函数(上面列出的函数除外)。
- 将全局指针设置为 NULL,推迟动态成员的初始化。在 Microsoft Windows Vista™ 中,您可以使用一次性初始化函数来确保代码块在多线程环境中只执行一次。
你的第二个问题对我来说不太清楚。要将代码注入另一个进程,您必须从某个地方(浏览器、exe 等)开始,然后写入目标进程内存以使其加载您的 DLL。