向应用程序发送击键,SendKeys.Send()vs SendMessage()

时间:2013-12-06 12:41:03

标签: c# winforms

我创建了一个简单的机器人来自动化游戏中的某些东西。我目前通过将游戏窗口置于前台并使用SendKeys发送密钥来向游戏发送命令,如下所示:

SendKeys.Send("{ENTER}")

我想知道的是,从可检测性的角度来看,如果反作弊引擎更容易检测到这样的事情(使用SendMessage):

public static void SendKeystroke(ushort k)
{
    const uint WM_KEYDOWN = 0x100;
    const uint WM_SYSCOMMAND = 0x018;
    const uint SC_CLOSE = 0x053;

    IntPtr WindowToFind = FindWindow(null, "Untitled1 - Notepad++");

    IntPtr result3 = SendMessage(WindowToFind, WM_KEYDOWN, 
                                    ((IntPtr)k), (IntPtr)0);
}

SendKeystroke(Keys.Enter);

最后,游戏会收到输入密钥的keydown事件,对吗?

2 个答案:

答案 0 :(得分:3)

这是一个概念性问题,也是技术问题。

  • SendKeys.Send() - 是WinAPI SendInput()函数的Windows窗体包装器。此功能直接用于鼠标和键盘输入流。虽然有一些限制(请阅读相关文档)。

  • SendMessage() - 是一个WinAPI函数。它用于将特定消息发送到窗口。除鼠标或键盘输入外,它还可用于发送其他消息。这是一种更高级别的消息传递队列,其中许多其他消息被聚合,以发送到窗口。在进程之间封送消息也存在限制。

  • 可检测性:这实际上取决于您可以模仿按下按钮的过程有多好以及反作弊引擎有多好。当人按下按钮时,几乎没有其他消息被发送到窗口。除WM_KEYDOWN外,还有WM_KEYUP和其他一些。您的任务是尽可能地重新创建该序列。您将不得不对此主题进行自己的研究。您已经可以看到人类按下按钮,无法创建仅向窗口发送WM_KEYDOWN的情况,WM_KEYUP必须跟进。两者之间的延迟也应该是人类可能的等等......

我也相信,SendMessage()可能无法正常运行游戏,因为他们中的许多人使用DirectX DirectInput,在这种情况下,我认为WinAPI SendInput()函数可以做得更好,因为它是一个较低级别API并直接使用输入流。

答案 1 :(得分:3)

  • SendKeys.Send通常使用SendInput。 UAC不支持使用基于日志挂钩的替代方法,因此我们假设SendKeys.Send解析为SendInput
  • SendMessage以同步方式将消息直接发送到窗口过程。

所以,这更容易检测。好吧,肯定答案是SendMessage。这些是到达窗口过程的输入消息,而没有通过调用GetMessage从队列中取出。这很容易被发现。您只需记录有关从队列中提取的最新消息的一些信息,并在窗口过程中,根据最新排队的消息检查消息。

现在,区分SendInput和真实的人类输入可能比那更难。我很确定它有可能。一种方法是安装低级键盘钩子并查找LLKHF_INJECTED标志。更难,但不是那么难。