我有一个调用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 ++时,应用程序不会崩溃! 我通过调试器,我发现访问冲突异常仍然发生,但不知何故吞下了异常。 该应用程序工作正常!我可以加载和保存文件。
我有以下想法。你觉得他们怎么样?
写一下......就像一个像Spy ++一样的Loader.exe。 在调用两个API时吞下访问冲突异常。
使用DLL注入和API挂钩。 我可以使用自定义DLL中的自定义实现来挂钩GetOpenFileName和GetSaveFileName。我的实现将修复结构并将更正的结构传递给原始的API调用。
使用SetWindowsHook挂钩窗口消息?!?!?!
修补二进制文件。是否可以通过使用HEX编辑器修补来修复此结构大小问题?
哪一个会起作用? 你对我如何解决这个问题有更好的了解吗?
我无法获取此旧应用程序的源代码。 我必须使用现有的二进制文件来修复它。 我的解决方案必须至少在Windows XP和Windows 7(x86,x64)上运行
工具PEiD向我展示了有关旧应用程序的以下信息: 链接器信息:2.55 MS Visual C ++ 4.0
答案 0 :(得分:1)
(1)纯粹的黑客可能很难做到(Spy ++行为的哪个方面呢?或者你想重新发明完整的Syp ++?),即使你这样做,你怎么能确定应用程序会“吞噬异常”后正确工作(对于所有输入)?程序的内部状态可能未定义,并在以后导致其他问题。
(2)假设你没有来源,所以你无法以正常的方式解决它,这个恕我直言似乎是最好的解决问题。
(3)我看不出这对你有什么帮助。
(4)可能但很多工作可能。假设堆栈中有一些数据,那么通过调整其中一个数据(OPENFILENAMEA
结构)可以移动其他数据,因此您必须“修复”对这些数据的引用。
答案 1 :(得分:1)
结构的大小为76字节(使用Windows 7 x64进行测试)。我明白了 GetOpenFileNameA或者GetOpenFileNameA时的访问冲突异常 调用GetSaveFileNameA。我假设在运行时窗口尝试 读取88个字节而不是76个字节。
如果您查看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之前使用编译器/链接器构建的程序。
写的......就像一个像Spy ++一样的Loader.exe。 调用两个API时吞下访问冲突异常。 这是一个公平的观点。如果你要在顶层插入异常处理,你可以做你想要的事情,但它可能会导致副作用,具体取决于究竟是什么原因引起了异常(即哪些内存被覆盖)。使用DLL注入和API挂钩。我可以挂钩GetOpenFileName和 GetSaveFileName在自定义DLL中具有自定义实现。我的 实现将修复结构并将更正的结构传递给 原始的API调用。 这与第一个问题非常相关。我认为这将是最简单和最安全的,因为这样你可以在没有太多入侵的情况下纠正行为。请在下面进一步阅读。另外,请查看NInjectLib。
使用SetWindowsHook挂钩窗口消息?!?!?! 我没有看到除了促进DLL的注入(对于1.和2。)而言有什么帮助。
修补二进制文件。是否可以通过修复此结构大小问题 使用HEX编辑器修补? 这可能是最棘手的,取决于
OPENFILENAME
是在二进制文件(初始化数据)内还是在堆栈上,或者它是否在堆上分配(然后很容易)。
1.和2.的一种可能的混合方法是:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options
添加一个子项(例如foo.exe
)REG_SZ
的{{1}}值,并将值设置为我将尝试简要描述的程序。这有效地为您的旧应用程序设置了一个调试器,这意味着我们要编写的调试器将接收应用程序的命令行作为参数。它很方便,因为它对最终用户是透明的,您可以根据自己的需要进行调整。
您需要编写调试器。这个任务并不像最初看起来那么苛刻,因为你可以使用Win32提供的调试助手。要点在调试器循环中。通常,您使用Debugger
传递适当的标志来自己创建目标进程以便能够对其进行调试。使用CreateProcess
和WaitForDebugEvent
来控制执行。出于所有实际目的,您可能根本不需要调试器循环,因为您可以创建目标应用程序的主线程暂停(将ContinueDebugEvent
传递给CREATE_SUSPENDED
),然后指向CreateProcess
在最开始的主线程到你自己的代码,然后调用CONTEXT
。这样你就可以在主线程开始之前完成。但是,由于ResumeThread(pi.hThread)
的{{1}}工作方式(包括使用Win32子系统kernel32.dll
注册新线程),这可能会导致问题。因此,建议在内存或类似的东西中修补目标的IAT。毕竟你只对两个功能感兴趣。
我更喜欢根据来自PaiMei的CreateThread
来编写我的调试器,但我确实没有尝试在csrss.exe
中使用这样的基于Python的调试器。