有什么方法可以确定程序是否使用了特定的 Windows API 函数?
Is there any way to determine if a program uses a specific Windows API functions?
好的,解释起来可能有点困难:
假设有人创建了一个 Windows 应用程序(使用 C# 或任何其他语言),该应用程序使用 user32.dll
上的 GetDesktopWindow()
函数来捕获屏幕截图,然后将此图像发送到任何在线服务。
由于它是定制的应用程序,所以没有防病毒软件能够确定它是病毒,因为它仍然是一个未知的应用程序。此外,此类 API 有合法用途,因此它不一定是病毒,它可以是无害的 window 捕获工具或某种间谍工具。
我想知道的是:有什么方法可以查看特定EXE文件对Windows函数的作用吗?我能知道 "myapp.exe" 是否使用 GetDesktopWindow()
或 user32.dll
吗?
这只是一个例子。还有很多其他 Windows 端点,我想知道它们何时被任何应用程序使用。
有办法吗?
这取决于你想做多长时间。它本质上是一场猫捉老鼠的游戏——坏人会试图通过跳过一些晦涩的圈套来寻找新的方法来绕过你的检测,你会为这些技巧添加更复杂的检测方法,他们会想出新的技巧,等等。
此外,这取决于您是想静态还是动态确定,以及您是否真的想知道 GetDesktopWindow
是否被调用,或者“程序是否获得桌面句柄 window”(也可以通过其他方式实现)。
这里是一个非详尽的想法列表:
- 您可以通过查看导入目录静态判断该函数是否被导入。研究 PE 文件结构以了解更多信息。 This article may help.
- 通过使用
LoadLibrary
和 GetProcAddress
. 动态导入函数,可以轻松绕过这种检测方法
- 您可以扫描文件中的字符串
GetDesktopWindow
以检测动态导入的可能用法。
- 通过打包、加密或以其他方式混淆动态导入函数的名称,可以轻松绕过这种检测方法。
- 您可以动态观察
GetDesktopWindow
函数是否被调用,方法是注册一个 AppInit_DLL
或一个注入到每个新进程中的全局挂钩,并从内部挂钩 GetDesktopWindow
函数通过跳转到您自己的代码来覆盖其第一个字节,以某种方式通知您的检测组件,执行原始字节并跳回。 (Microsoft Detours 可以提供帮助。)
- 如果目标注意到挂钩并在调用之前将其删除,则可以绕过这种检测方法,因为它在自己的进程中 space。 (你也可以像调试器一样做一些技巧,并在
GetDesktopWindow
的第一条指令上设置硬件断点,但同样会有检测或规避它的方法,因为目标也可以修改调试寄存器。 )
- 您可以构建一个从内核模式执行此操作的驱动程序,但现在我们变得非常深入。
请注意,到目前为止,我们关注的是 user32.dll
中的实际 GetDesktopWindow
函数。但是,如果目标只是使用不同的方式来实现其获得桌面 window 句柄的目标呢?
- 当前线程的桌面 window 句柄存储在 TIB(线程信息块)中,可从用户模式通过
fs:[18]
访问。您可以在 GetDesktopWindow
source code of ReactOS 中看到这一点,与 Microsoft 的实际实现(您可以通过在调试器中查看它来验证)相比,它非常准确。因此,目标可以只访问 TIB 并提取此值,甚至根本不需要调用 GetDesktopWindow
。
- 目标可以只采用已知的顶级 window,例如 shell 的隐藏兼容性 window,您可以通过
GetShellWindow()
或 -避免检测到 GetShellWindow
- 例如 FindWindow(NULL, "Program Manager")
(或者甚至是新创建的 window!)并在其上调用 GetAncestor(hWnd, GA_PARENT)
以获得桌面 window 句柄.
- 我敢肯定,如果有一些创造力,您的对手会想出比这些更聪明的主意。
此外,如果我们更进一步,看看截图的最终目标,还有其他方法可以实现。想到的第一个例子:他们可以使用 keybd_event
模拟按下 PrnSc 键,然后从剪贴板数据中读取屏幕截图。
所以这完全取决于你想走多远。
顺便说一下,您可能会发现 drltrace
项目很有趣 - 它是一个库调用跟踪器。
好的,解释起来可能有点困难:
假设有人创建了一个 Windows 应用程序(使用 C# 或任何其他语言),该应用程序使用 user32.dll
上的 GetDesktopWindow()
函数来捕获屏幕截图,然后将此图像发送到任何在线服务。
由于它是定制的应用程序,所以没有防病毒软件能够确定它是病毒,因为它仍然是一个未知的应用程序。此外,此类 API 有合法用途,因此它不一定是病毒,它可以是无害的 window 捕获工具或某种间谍工具。
我想知道的是:有什么方法可以查看特定EXE文件对Windows函数的作用吗?我能知道 "myapp.exe" 是否使用 GetDesktopWindow()
或 user32.dll
吗?
这只是一个例子。还有很多其他 Windows 端点,我想知道它们何时被任何应用程序使用。
有办法吗?
这取决于你想做多长时间。它本质上是一场猫捉老鼠的游戏——坏人会试图通过跳过一些晦涩的圈套来寻找新的方法来绕过你的检测,你会为这些技巧添加更复杂的检测方法,他们会想出新的技巧,等等。
此外,这取决于您是想静态还是动态确定,以及您是否真的想知道 GetDesktopWindow
是否被调用,或者“程序是否获得桌面句柄 window”(也可以通过其他方式实现)。
这里是一个非详尽的想法列表:
- 您可以通过查看导入目录静态判断该函数是否被导入。研究 PE 文件结构以了解更多信息。 This article may help.
- 通过使用
LoadLibrary
和GetProcAddress
. 动态导入函数,可以轻松绕过这种检测方法
- 通过使用
- 您可以扫描文件中的字符串
GetDesktopWindow
以检测动态导入的可能用法。- 通过打包、加密或以其他方式混淆动态导入函数的名称,可以轻松绕过这种检测方法。
- 您可以动态观察
GetDesktopWindow
函数是否被调用,方法是注册一个AppInit_DLL
或一个注入到每个新进程中的全局挂钩,并从内部挂钩GetDesktopWindow
函数通过跳转到您自己的代码来覆盖其第一个字节,以某种方式通知您的检测组件,执行原始字节并跳回。 (Microsoft Detours 可以提供帮助。)- 如果目标注意到挂钩并在调用之前将其删除,则可以绕过这种检测方法,因为它在自己的进程中 space。 (你也可以像调试器一样做一些技巧,并在
GetDesktopWindow
的第一条指令上设置硬件断点,但同样会有检测或规避它的方法,因为目标也可以修改调试寄存器。 ) - 您可以构建一个从内核模式执行此操作的驱动程序,但现在我们变得非常深入。
- 如果目标注意到挂钩并在调用之前将其删除,则可以绕过这种检测方法,因为它在自己的进程中 space。 (你也可以像调试器一样做一些技巧,并在
请注意,到目前为止,我们关注的是 user32.dll
中的实际 GetDesktopWindow
函数。但是,如果目标只是使用不同的方式来实现其获得桌面 window 句柄的目标呢?
- 当前线程的桌面 window 句柄存储在 TIB(线程信息块)中,可从用户模式通过
fs:[18]
访问。您可以在GetDesktopWindow
source code of ReactOS 中看到这一点,与 Microsoft 的实际实现(您可以通过在调试器中查看它来验证)相比,它非常准确。因此,目标可以只访问 TIB 并提取此值,甚至根本不需要调用GetDesktopWindow
。 - 目标可以只采用已知的顶级 window,例如 shell 的隐藏兼容性 window,您可以通过
GetShellWindow()
或 -避免检测到GetShellWindow
- 例如FindWindow(NULL, "Program Manager")
(或者甚至是新创建的 window!)并在其上调用GetAncestor(hWnd, GA_PARENT)
以获得桌面 window 句柄. - 我敢肯定,如果有一些创造力,您的对手会想出比这些更聪明的主意。
此外,如果我们更进一步,看看截图的最终目标,还有其他方法可以实现。想到的第一个例子:他们可以使用 keybd_event
模拟按下 PrnSc 键,然后从剪贴板数据中读取屏幕截图。
所以这完全取决于你想走多远。
顺便说一下,您可能会发现 drltrace
项目很有趣 - 它是一个库调用跟踪器。