c++ - 替换或修改外部应用程序中的 API 调用(GetOpenFileName、GetSaveFileName)

标签 c++ winapi crash hook .net-assembly

我有一个调用 GetOpenFileNameA 和 GetSaveFileNameA 的旧应用程序。 两次调用都是错误的。应用程序崩溃! 我已经使用 OllyDbg 和 API Monitor 来读取存储在 OPENFILENAME 结构中的大小。 该结构的大小为 76 字节(使用 Windows 7 x64 进行测试)。 调用 GetOpenFileNameA 或 GetSaveFileNameA 时出现访问冲突异常。 我假设在运行时窗口试图读取 88 字节而不是 76 字节。 看看这个: http://dotnetbutchering.blogspot.de/2007/10/vc-60-getting-0xc0000005-access.html 还有这个 http://www.asmcommunity.net/board/index.php?topic=5768.15

我做了一些研究,同时我发现了以下行为: 运行 Microsoft Spy++ 时应用程序不会崩溃!! 我单步调试调试器,发现访问冲突异常仍然发生,但异常被吞没了。 该应用程序工作正常!我可以加载和保存文件。

我有以下想法。你觉得他们怎么样?

  1. 写某事。就像 Loader.exe 一样,它的功能与 Spy++ 相同。 在调用两个 API 时吞下访问冲突异常。

  2. 使用 DLL 注入(inject)和 API Hook 。 我可以将 GetOpenFileName 和 GetSaveFileName 与自定义 DLL 中的自定义实现 Hook 。我的实现将修复该结构并将更正后的结构传递给原始 API 调用。

  3. 使用 SetWindowsHook Hook 窗口消息 ?!?!?!

  4. 修补二进制文件。是否可以通过使用 HEX 编辑器进行修补来解决此结构大小问题?

哪一个会起作用? 你有更好的办法解决这个问题吗?

我无法获得这个旧应用程序的源代码。 我必须使用现有的二进制文件修复它。 我的解决方案必须至少适用于 Windows XP 和 Windows 7(x86、x64)

工具 PEiD 向我显示了有关旧应用程序的以下信息: 链接器信息:2.55 MS Visual C++ 4.0

最佳答案

The size of the struct is 76 Bytes (testing with Windows 7 x64). I get an access violation exception while GetOpenFileNameA or GetSaveFileNameA is called. I assume that at runtime windows tries to read 88 Bytes instead of 76 Bytes.

如果您查看 OPENFILENAME struct,您会注意到:

#if (_WIN32_WINNT >= 0x0500)
  void *        pvReserved;
  DWORD         dwReserved;
  DWORD         FlagsEx;
#endif // (_WIN32_WINNT >= 0x0500)

在 32 位程序中(VC++ 4 不支持 64 位目标)转换为恰好 12 字节的差异。只要调用者正确设置了 lStructSize,这根本就不是问题。可能值得使用 Microsoft/Sysinternals 的 procdump 来获取确切状态的小型转储(或附加调试器并进行调查)。您遇到的异常不一定是由于 struct 大小造成的。如果是的话,微软很可能在向后兼容这个功能时失手了。显然 OPENFILENAME::lStructSize 用于对 struct 进行版本控制,并确保不会发生您遇到的情况。但是,我们谈论的是使用 Windows 2000 之前的编译器/链接器构建的程序。

write sth. like a Loader.exe which does the same like Spy++. Swallowing the access violation exception when both APIs are called. It's a fair point. If you would insert exception handling at the top level you could do things you want, but it may cause side-effects depending on what exactly caused the exception (i.e. which exact memory was overwritten).

Use DLL Injection and API Hooking. I could hook GetOpenFileName and GetSaveFileName with a custom implementation in a custom DLL. My implementation would fix the struct and pass the corrected struct to the original API calls. This is pretty much related to the first one. I think it will be easiest and safest in all, because this way you can correct the behavior without too much intrusion. Please read further below. Also, check out NInjectLib.

Use SetWindowsHook to hook a window message ?!?!?! I don't see how that helps other than facilitating the injection of a DLL (for 1. and 2.).

Patch the binary file. Is it possible to fix this struct size issue by patching using a HEX Editor? This may be the trickiest, depending on whether the OPENFILENAME is inside the binary (initialized data) or on stack or whether it gets allocated on the heap (easy then).


1. 和 2. 的一种可能的混合方法是:

  1. 将一个子项添加到 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options 以您正在执行的程序命名(例如 foo.exe)
  2. 在新创建的子项中创建一个名为 DebuggerREG_SZ 值,并将该值设置为我现在将尝试简要描述的程序。

这有效地为您的这个旧应用程序设置了一个调试器,这意味着我们要编写的调试器将接收您的应用程序的命令行作为参数。它很方便,因为它对最终用户是透明的,您可以根据自己的需要进行调整。

您需要编写一个调试器。这个任务并不像最初看起来那么难,因为您可以使用 Win32 提供的调试助手。要点在调试器循环中。通常,您可以使用 CreateProcess 传递适当的标志来自行创建目标进程,以便能够对其进行调试。使用 WaitForDebugEventContinueDebugEvent 来控制执行。出于所有实际目的,您甚至可能根本不需要调试器循环,因为您可以创建目标应用程序的主线程挂起(将 CREATE_SUSPENDED 传递给 CreateProcess)然后指向最开始将主线程的CONTEXT设置为自己的代码,然后调用ResumeThread(pi.hThread)。这样你就可以在主线程启动之前完成。但是,由于 kernel32.dllCreateThread 工作方式(它涉及向 Win32 子系统又名 csrss.exe< 注册新线程,这可能会导致问题)。因此,最好在内存或类似的东西中修补目标的 IAT。毕竟您只对两个功能感兴趣。

查看两篇文章 herehere以更详细地了解该主题。

我个人更喜欢基于来自 PaiMeiPyDbg 编写我的调试器,但我承认我没有尝试在 Image File Execution Options 中使用这样一个基于 Python 的调试器。

关于c++ - 替换或修改外部应用程序中的 API 调用(GetOpenFileName、GetSaveFileName),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10739312/

相关文章:

c++ - 写入是否超出 union UB 中较小尺寸成员的尺寸?

c++ - 如何在进程间通信中获取其他端点的进程ID

c - 获取SDL 2应用程序的窗口句柄

ios - NSURLConnectionLoader 线程中的奇怪崩溃

ios - 如何在没有堆栈的情况下调试iOS断言失败崩溃

android-studio - Android Studio - 用于发布崩溃的签名 APK

c++ - 分而治之数组算法C++

c++ - 如何对不同的静态类进行分组?

c++ - closesocket 线程安全吗?

c++ - 如何在 Win32 上的 WS_EX_CLIENTEDGE "Edit"文本字段上打断文本行