3

我正在开发一个应用程序,它保存自定义进程的状态,然后从停止的点恢复它。

现在有以下问题。当系统重新启动时,系统模块的所有基地址都是随机的(ntdll.dllkernelbase.dllkernel32.dll)。操作系统是 Windows 7 x64 企业版。在重新启动后尝试恢复应用程序时,它显然会崩溃(但在重新启动前从恢复点开始工作正常)。我看到了两个解决方案:

  1. 在应用程序中加载系统模块时,使它们的地址保持静态
  2. 修补应用程序中对目标模块的所有引用(堆栈上的函数地址,可能保存在堆中的地址等)

显然,第二种方法是困难的。我们要进行完整的应用程序分析,将代码与数据不同,将数据与系统模块的引用不同,其中可能是简单的整数......所以我选择了第一种方式。

在虚拟内存中加载模块时,操作系统首先检查物理内存中是否已经存在具有此名称的模块。如果有,它只是将此模块映射到虚拟地址空间。在这种情况下,模块从其初始位置加载,如果是ntdll.dll- from C:\Windows\System32\ntdll.dll。即使您将此模块复制到应用程序目录,禁用 ASLR 标志并将图像库修补为某个值,该模块仍将从系统目录加载。需要某种重定向方式。

MSDN我们了解到以下内容(“桌面应用程序的搜索顺序”部分):

桌面应用程序可以通过指定完整路径、使用DLL 重定向或使用清单来控制加载 DLL 的位置。如果没有使用这些方法,系统会在加载时搜索 DLL,如本节所述。

因此,至少有两种方法可以实现目标。

在关于 DLL 重定向的页面上,我们看到:

无法重定向已知的 DLL。有关已知 DLL 的列表,请参阅以下注册表项:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs。系统使用 Windows 文件保护来确保诸如此类的系统 DLL 不会被更新或删除,除非通过操作系统更新(例如服务包)。

我要重定向的模块是已知的 DLL,因此无法应用此变体。

留下清单。有一篇关于使用它们的优秀文章。文章的作者创建了存根 DLL 来替换原来的 ( user32.dll),然后让应用程序加载这个替换的 DLL。关键是这个DLL是在搜索导入函数时加载的,而不是在应用程序一开始就加载,比如ntdll.dll.

更具体地说,让我们参考“Windows Internals, Sixth Edition”, p. 359解释了进程创建的细节。那里有7个阶段:

  1. 转换和验证参数和标志
  2. 打开要执行的镜像
  3. 创建 Windows 执行进程对象
  4. 创建初始线程及其堆栈和上下文
  5. 执行 Windows 子系统特定的初始化后
  6. 开始执行初始线程
  7. 在新进程的上下文中执行进程初始化

这里最重要的几点:

  • 映射ntdll.dll发生在第 3 阶段;

  • 在第 5 阶段开始时,我们阅读(重点是我的):

此时,Kernel32.dll 向 Windows 子系统发送一条消息,以便它可以设置 SxS 信息(有关并行程序集的更多信息,请参见本节末尾),例如 清单文件、DLL 重定向路径和新进程的进程外执行。

这意味着ntdll.dll在重定向有机会发生之前加载。关于重定向的主题有很多关于 SO 的问题,但它们都是关于在搜索导入函数时加载的 DLL 或LoadLibrary在应用程序中可能发生重定向时显式通过 加载的 DLL。

但是,ntdll.dll无论如何在很早的阶段就被加载到应用程序中。

使用到目前为止我收集的所有信息,我能够进行应用程序搜索,例如,kernel32.dll在应用程序的目录中(使用本段中的链接)。但我无法重定向搜索ntdll.dll

用户模式是否有可能?


PS 有一种全局禁用 ASLR 的方法,请参阅这篇文章。然而,这是一种非常粗鲁的方式,像Internet Explorer,之类的应用程序Adobe Reader无法运行,并且整个操作系统都存在漏洞。

4

2 回答 2

3

ntdll 在进程创建期间从内核映射。当进程中的第一个用户模式指令开始执行时(这是来自 ntdll 的 LdrInitializeThunk)ntdll 已经在进程中映射(在开始时只有 exe 和 ntdll 映射,所有另一个 dll 由 ntdll 加载或由 exe 延迟加载)。并且ntdll必须在所有进程中加载​​的相同地址,因为系统使用位于ntdll中的一些回调的地址(LdrInitializeThunk,KiUser*Dispatcher)

于 2016-05-30T19:21:20.280 回答
1

有一些(理论上的)选项:

  • 在 Windows 10 上为 WOW64 进程使用委派 ntdll(我从未尝试过,但理论上您应该能够指定注册表设置来执行此操作。请参阅http://redplait.blogspot.de/2017/07/delegatedntdll.html
  • 设置一些兼容性选项(以确保加载了 apphelp.dll)并使用清单文件加载自定义的 apphelp.dll,您可以使用它来加载您自己的 ntdll 并修补加载的模块列表以使您自己的 dll 成为用作任何其他模块的导入。到目前为止我没有这样做(我喜欢在有时间的时候尝试一下),但是我能够加载一个自定义的 win32u.dll,它将大多数导出转发到原始 win32u.dll 的副本并挂钩到一些 win32系统调用。另请参阅http://stackoverflow.com/questions/2100973/dll-redirection-using-manifests
于 2018-03-04T22:33:33.013 回答