3

我的程序在 Windows Vista Ultimate 和 Windows 7 上完美运行,但在 Windows XP 上却失败了。

首先,我的应用程序创建一个系统文件的进程,它调用 GetThreadContext(remote_thread) 并将 LPVOID 值设置为值 context->Eip,然后检查从 VirtualQueryEx 设置的结构 MEMORY_BASIC_INFORMATION 中的值。

以下是 VirtualQueryEx 在调用时返回的值:

视窗

  • 0 - 分配基数
  • 0 - 分配保护
  • 2088828928 - 基地址
  • 1 - 保护
  • 983040 - 区域大小
  • 65536 - 状态
  • 0 - 类型

Windows 7的

  • 2003959808 - 分配基地
  • 128 - 分配保护
  • 2004025344 - 基地址
  • 32 - 保护
  • 876544 - 区域大小
  • 4096 - 状态
  • 16777216 - 类型

视窗

  • 2006122496 - 分配基地
  • 128 - 分配保护
  • 2006536192 - 基地址
  • 32 - 保护
  • 389120 - 区域大小
  • 4096 - 状态
  • 16777216 - 类型

为什么当我在 Windows XP 上运行我的应用程序时,它没有分配基础和分配保护,以及与 Windows 7 和 Windows Vista 完全不同的值。

我计划在地址(上下文-> Eip)上使用 VirtualProtectEx,所以如果这些是 XP 上的值,那么 VirtualProtectEx 将不可避免地失败,因为我将访问无法访问的内存。

这是我创建流程的方式:

    if ( CreateProcessW(m_pwszContainerPath, NULL, NULL, NULL, FALSE, DETACHED_PROCESS | CREATE_SUSPENDED, NULL, NULL, &m_stStartInfo, &m_stProcessHandles) == TRUE )
    {
    // Get context of thread
    m_stContext.ContextFlags = CONTEXT_FULL;
    if ( GetThreadContext(m_stProcessHandles.hThread, &m_stContext) == FALSE )
        goto _CLEANUP;
    // Grab, Eip
    m_pvLdrInitEip = (LPVOID)m_stContext.Eip;
        }

事实是:这在 Windows 7 和 Windows Vista 上都能完美运行。

我在这里缺少什么吗?感谢您的任何帮助。

编辑 - 这是一张照片:

Windows 7的 视窗 Windows XP 显示内存中 EIP 的位置。 显示地址在 ntdll 中的 Windows 7 这是 olly 运行可执行文件的两个实例的图片,一个在 XP 虚拟机中,一个在外部。据我所知,XP 图片(下一张)将 EIP 设置为 ModuleEntryPoint,而 Windows 7 实例将其设置为 ntdll..

我进一步调查,发现 EIP 实际上是 kernel32.dll 映像(在 Windows XP 上),而不是应该的 ntdll.dll。

4

2 回答 2

5

创建一个进程CREATE_SUSPENDED意味着主进程在运行代码之前不会完成它的初始化。加载程序的实现方式会导致 XP 和 Vista/7 之间的不同效果,并且由于CREATE_SUSPENDED文档没有授予任何进程初始化,因此您不能真正指望该方法。该CREATE_SUSPENDED标志仅说明该进程是在主线程挂起的情况下创建的。
目前尚不清楚 OP 希望完成什么,但我想到了一些实现类似目标的方法:

  1. 编写调试器而不是远程操作另一个进程。一个简单的教程和代码示例可以在这里找到。调试器为每个生成的线程获取一个事件,您可能会使用它。

  2. 通过为您的代码创建一个新部分并在 PE 中放置一个 TLS 条目以在进程的内存空间内执行代码,修改 PE 以在任何其他代码之前执行您的代码。然后,您的代码将在进程的 EntryPoint 之前但在其初始化之后运行。

  3. 修改PE并EntryPoint用你自己的代码替换PE头中的,只要确保你自己执行原来的入口点。一些初始化将丢失,但将加载所有 PE 代码部分。

  4. 通过创建挂起的 DLL 并从不同的线程加载 DLL 或任何其他方法,将 DLL 注入进程的内存地址。本文列出了一些,您可以谷歌了解更多。如果您因为类似的问题而想要初始化进程,我不确定这是否适用于所有情况,但我确实认为调用 LoadLibrary 会为您带来所需的效果。这也是一种将代码放入另一个进程并对其进行操作的干净方法,同时比使用调试器更隐蔽。

  5. 您还可以尝试在进程挂起时扫描整个内存以查找要操作的代码块,这可能也适用于 XP。

  6. 您可以尝试创建未挂起的进程并让它在挂起线程之前运行一小段时间。在计时和一些测试之后,您会对初始化需要多少时间有一个合理的感觉。这有点冒险,但可能会奏效。

创建调试器将是最简单、最健壮/通用的方法,但缺点是容易被检测到(尽管您可以使用反反调试技巧)。如果您希望被操纵的进程无法检测到(如果它有任何反调试技巧),加载 DLL 将是最好的方法如果您想要针对您的特定需求的更多建议或建议,请编辑并详细描述您想要的内容完成,因为您的问题尚不清楚。有关该程序的更多详细信息(例如是本机程序还是 .net)也会有所帮助。

编辑:朋友提出的另一个猜测是内核在系统调用返回并且您调用VirtualQueryEx. WaitForSingleObject他说,一旦进程完全初始化,调用进程的句柄将返回,您可以访问所有信息并在之后恢复执行。

于 2013-06-20T14:43:43.283 回答
3

CreateProcess(CREATE_SUSPENDED)只做部分初始化。您可以尝试到VirtualAllocEx()EIP 区域并显式提交它,然后VirtualProtectEx,当然这是一个快速的 hack,您可以进行测试,我不确定这是否可以解决问题。顺便说一句,你这样做的真正目的是什么?如果你打算在进程执行的早期hook,最好在PE头的入口点打补丁,因为当指令控制流到达入口点时,进程必须已经完成了它的初始化,但这也有它的缺点,例如TLS回调在入口点被执行之前被调用。

于 2013-06-02T19:12:21.297 回答