扩展现有程序的功能我没有源代码

时间:2012-04-13 02:46:48

标签: windows winapi hook reverse-engineering

我正在开发一个第三方程序,它聚合来自一系列不同的现有Windows程序的数据。每个程序都有一个通过GUI导出数据的机制。最麻醉的方法是让我通过使用AutoIt或其他一些GUI操作程序生成提取物,以通过GUI生成提取。这样做的问题是,当突然某些自动程序接管时,人们可能正在与计算机进行交互。那不好。我真正想做的是以某种方式每天运行一次程序并静默(即不弹出任何GUI)从每个程序导出数据。

我的研究告诉我,我需要挂钩每个应用程序(假设这些应用程序始终在运行)并注入一个自定义DLL来触发每个导出。我是否正在接近正确的轨道?我是一个相当有经验的软件开发人员,但我不太了解逆向工程或挂钩。任何建议或指示都将不胜感激。

编辑:我正在尝试管理某种专业人员的可用性。他们的时间表存储在专有系统中。经过他们的许可,我想在他们的系统上安装一个应用程序,从他们使用的系统中提取他们的日程安排,并将信息上传到中央服务器,以便我可以将这些信息提供给潜在的客户。

1 个答案:

答案 0 :(得分:5)

我知道有四种方法可以提取您想要的信息,包括它们的优点和缺点。在您执行任何操作之前,您需要知道您创建的任何解决方案都无法保证,并且实际上如果目标应用程序更新,则不太可能继续工作。原因是,在每种情况下,您都依赖于实施细节,而不是通过其导出数据的预定义界面。

挂钩GUI

第一种方法是按照建议挂钩GUI。在这种情况下,您正在做的只是阅读实际用户会看到的内容。这通常更容易,因为您正在挂钩明确定义的WinAPI。一个危险是程序显示的内容与它应该代表的内部数据相比是不一致或不完整的。

通常,有两种常见的方法可以执行WinAPI挂钩:

  • DLL注入。您创建一个DLL,您将其加载到其他程序的虚拟地址空间。这意味着您对目标的整个内存具有读/写访问权限(可通过VirtualProtect获得可写访问权限)。从这里你可以蹦床调用设置UI信息的函数。例如,要检查窗口是否更改了其文本,您可以蹦出SetWindowText函数。请注意,每个control都有不同的接口用于设置它们显示的内容。在这种情况下,您将挂钩代码调用的函数来设置显示。
  • SetWindowsHookEx。在封面下,这与DLL注入类似,在这种情况下,实际上只是扩展/破坏控件接收的消息控制流的另一种方法。在这种情况下,您想要做的是挂钩每个子控件的窗口过程。例如,当某个项目添加到ComboBox时,它会收到CB_ADDSTRING条消息。在这种情况下,您将挂钩显示更改时收到的消息。

这种方法的一个警告是它只有在目标使用或扩展WinAPI控件时才有效。

从GUI中读取

您可以使用WinAPI直接从目标窗口读取,而不是挂钩GUI。但是,在某些情况下,可能不允许这样做。在这种情况下没什么可做的,但要试着看看它是否有效。事实上,这可能是最简单的方法。通常,您将发送WM_GETTEXT之类的消息来查询目标窗口以查找当前显示的内容。为此,您需要获取包含您感兴趣的控件的确切窗口层次结构。例如,假设您要读取编辑控件,您需要在窗口层次结构中查看其上方的父窗口为了获得它的窗口句柄。

从内存中读取(高级)

这种方法是迄今为止最复杂的方法,但如果您能够对目标程序进行完全逆向工程,则最有可能为您提供一致的数据。这种方法可以帮助您从目标进程中读取内存。这种技术在游戏黑客中非常常用,以增加功能性。并观察游戏的内部状态。

考虑到除了在GUI中存储信息之外,程序通常还拥有自己的所有数据的内部模型。当使用的控件是virtual并且只是查询要显示的数据的子集时尤其如此。这是前两种方法没有多大用处的情况的一个例子。这些数据通常以某种抽象数据类型保存,例如列表或甚至是数组。诀窍是在内存中找到此列表并直接读取值。这可以通过ReadProcessMemory在外部完成,也可以通过DLL内部再次执行。困难主要在于两个先决条件:

  • 首先,您必须能够可靠地找到这些数据结构。这样做的问题是代码不能保证在同一个地方,尤其是ASLR等功能。通俗地说,这有时被称为代码转换。通过使用模块基址的偏移量并使用GetModuleHandle等函数动态获取模块基址,可以消除ASLR。与ASLR一样,发生这种情况的原因是动态内存分配(例如通过malloc)。在这种情况下,您需要找到存储指针的堆地址(例如,返回malloc),取消引用并找到您的列表。该指针将倾向于ASLR而不是指针,它可能是双指针,三指针等。
  • 您遇到的第二个问题是每个列表项很少是基本类型。例如,您可能会遇到一个对象列表,而不是字符数组(字符串)列表。您需要进一步对每个对象类型进行逆向工程并理解内部布局(至少能够根据其与对象库的偏移量来确定您感兴趣的原始值的偏移量)。更高级的方法围绕实际对vtable对象进行逆向工程并调用其API' API。

您可能会注意到我无法在此处提供具体的信息。原因在于,就其本质而言,使用这种方法需要对目标的内部结构进行深入了解,因此,具体情况仅由目标的编程方式来定义。除非你有逆向工程的知识和经验,否则你不太可能想要走这条路。

挂钩目标的内部API(高级)

与上述解决方案一样,您需要挖掘内部API,而不是挖掘数据结构。我在前面讨论vtable时简要介绍了这一点。您将尝试查找修改GUI时调用的内部API,而不是这样做。通常,当修改视图/ UI时,程序将拥有自己的包装函数,而不是直接调用WinAPI来更新它,而是调用WinPI调用WinAPI。你只需要找到这个函数并挂钩它。这是可能的,但需要逆向工程技能。您可能会发现自己想要调用的功能。在这种情况下,除了能够找到函数的位置之外,还必须对其所需的参数进行反向工程,调用约定,并且需要确保调用函数没有副作用。

我会认为这种方法是先进的。它当然可以完成,是游戏黑客中用来观察内部状态和操纵目标行为的另一种常用技术,但很难!


前两种方法非常适合从WinAPI程序读取数据,并且要容易得多。后两种方法允许更大的灵活性。通过足够的工作,您可以阅读目标封装的任何内容,但需要很多技能。

与您的案例有关或可能没有关系的另一个关注点是,如果每个目标都要更新,那么将解决方案更新到工作是多么容易。使用前两种方法,更有可能不需要进行任何更改或进行小的更改。使用后两种方法,即使源代码中的少量更改也可能导致重新定位您所依赖的偏移量。解决此问题的一种方法是使用字节签名来动态生成偏移。我前段时间写过another answer,其中解释了如何做到这一点。

我所写的只是对可以用于实现目标的各种技术的简要总结。我可能错过了方法,但这些是我所知道并且有经验的最常见的方法。由于这些本身就是大型主题,如果您想获得有关任何特定主题的详细信息,我建议您提出一个新问题。请注意,在我讨论的所有方法中,没有一个方法遭受外界可见的任何交互,因此您可以毫无问题地弹出任何内容。正如你所描述的那样,它将是“无声的”。


这是关于迂回/蹦蹦的相关信息,我从previous answer我写过:

  

如果您正在寻找程序绕道他人执行的方法   过程,通常通过以下两种方式之一:

     
      
  • 动态(运行时)绕行 - 这是更常用的方法,也是Microsoft Detours等库使用的方法。这里有一个   相关论文,其中函数的前几个字节被覆盖   无条件地分支到仪器。
  •   
  • (静态)二进制重写 - 这是一种不太常见的rootkit方法,但是被研究项目使用。它允许绕道而行   通过静态分析和覆盖二进制文件来执行。一个老   执行此操作的Windows(不公开)包   蚀刻。 This paper提供了有关其工作原理的高级视图   概念上。
  •   
     

虽然Detours演示了一种动态绕行的方法,但那里有   是行业中使用的无数方法,尤其是相反的方法   工程和黑客竞技场。这些包括IAT和断点   我上面提到的方法。为了让你指向正确的方向'对于   这些,你应该看看研究'在田野里演出   研究项目和逆向工程。