5

ゲームのウォールハックを検出するコードを書き込もうとしています。基本的に、Windows エアロ透明ウィンドウを作成するいくつかのハックが存在し、ハックをこの外部ウィンドウに描画するため、ゲーム自体のスクリーンショットを撮っても検出できません。

現時点での私のアプローチは - 1. ゲーム ウィンドウのスクリーンショットを撮ります。2. 同じ座標の Windows デスクトップのスクリーンショットを撮ります。3. 画像解析を実行してスクリーンショット 1 とスクリーンショット 2 を比較し、違いがあるかどうかを確認します。

私の問題は、スクリーンショット 1 とスクリーンショット 2 が同時に実行されないため、2 つのスクリーンショットの間に新しいゲーム フレームが描画され、画像を比較したときに誤検知が発生することです。

スクリーンショットがまったく同時に発生するように調整する方法があるかどうか知りたいですか? または、スクリーンショットが完了するまで、画面が新しいフレームを描画するのを何らかの方法で停止しますか?

これは、スクリーンショットを撮るために使用するコードです。2 つの作業項目をキューに入れて、2 つのスクリーンショットを並行して撮ろうとしたことにも注意してください。ただし、これでもスクリーンショットがまったく同時に発生するわけではありません。スクリーンショットが終了するまで、グラフィックカードから画面への更新を停止する方法はあるのでしょうか? または、これを行うことができる他の方法はありますか?

    public void DoBitBlt(IntPtr dest, int width, int height, IntPtr src)
    {
        GDI32.BitBlt(dest, 0, 0, width, height, src, 0, 0, GDI32.SRCCOPY);
    }

    public struct Windows
    {
        public Bitmap window;
        public Bitmap desktop;
    }
    public Windows CaptureWindows(IntPtr window, IntPtr desktop, User32.RECT coords)
    {
        Windows rslt = new Windows();
        // get te hDC of the target window
        IntPtr hdcSrcWindow = User32.GetWindowDC(window);
        IntPtr hdcSrcDesktop = User32.GetWindowDC(desktop);

        // get the size
        int width = coords.right - coords.left;
        int height = coords.bottom - coords.top;

        // create a device context we can copy to
        IntPtr hdcDestWindow = GDI32.CreateCompatibleDC(hdcSrcWindow);
        IntPtr hdcDestDesktop = GDI32.CreateCompatibleDC(hdcSrcDesktop);
        // create a bitmap we can copy it to,
        // using GetDeviceCaps to get the width/height
        IntPtr hBitmapWindow = GDI32.CreateCompatibleBitmap(hdcSrcWindow, width, height);
        IntPtr hBitmapDesktop = GDI32.CreateCompatibleBitmap(hdcSrcDesktop, width, height);
        // select the bitmap object
        IntPtr hOldWindow = GDI32.SelectObject(hdcDestWindow, hBitmapWindow);
        IntPtr hOldDesktop = GDI32.SelectObject(hdcDestDesktop, hBitmapDesktop);
        // bitblt over
        var handle1 = new ManualResetEvent(false);
        var handle2 = new ManualResetEvent(false);
        Action actionWindow = () => { try { DoBitBlt(hdcDestWindow, width, height, hdcSrcWindow); } finally { handle1.Set(); } };
        Action actionDesktop = () => { try { DoBitBlt(hdcDestDesktop, width, height, hdcSrcDesktop); } finally { handle2.Set(); } };
        ThreadPool.QueueUserWorkItem(x => actionWindow());
        ThreadPool.QueueUserWorkItem(x => actionDesktop());
        WaitHandle.WaitAll(new WaitHandle[] { handle1, handle2 });

        rslt.window = Bitmap.FromHbitmap(hBitmapWindow);
        rslt.desktop = Bitmap.FromHbitmap(hBitmapDesktop);

        // restore selection
        GDI32.SelectObject(hdcDestWindow, hOldWindow);
        GDI32.SelectObject(hdcDestDesktop, hOldDesktop);
        // clean up
        GDI32.DeleteDC(hdcDestWindow);
        GDI32.DeleteDC(hdcDestDesktop);
        User32.ReleaseDC(window, hdcSrcWindow);
        User32.ReleaseDC(desktop, hdcSrcDesktop);
        // free up the Bitmap object
        GDI32.DeleteObject(hBitmapWindow);
        GDI32.DeleteObject(hBitmapDesktop);
        return rslt;
    }
4

1 に答える 1

2

いくつかのグラフィック アクセラレータを使用しない限り、両方のスクリーンショットを同時に取得することはできません。つまり、すべてのコンピュータで機能するとは限りません...

レンダリングを停止することについては、ゲームなのであまり良い考えではないと思います... ゲームをスムーズに実行したい。

代わりに、最近レンダリングされたゲームの画像をメモリに保存し、スクリーンショットを撮ったときにそれらと比較することをお勧めします。最近のどのフレームと比較するかを決定するための視覚的な手がかりを追加できれば、はるかにうまく機能します。そうしないと、スクリーンショットをすべてのフレームと比較する必要があり、CPU/GPU 時間が確実に消費されます。

レンダリングに GDI を使用していますか? その場合、ゲームのフレームを DIB (Device Independent Bitmaps) に保存して比較できるようにする必要があります。

どの画像を使用するかを決定する手がかりとして、画面上のある種の時間表現、おそらく色が変化する単一のピクセルを探します。その場合、そのピクセルの色を読み取り、それを使用して適切なフレームを見つけ、画像全体を比較します。

于 2013-10-11T09:31:13.883 に答える