Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detect game hack through screenshot analysis C#

I'm trying to write some code to detect a wallhack for a game. Basically, some hacks exist which create a windows aero transparent window, and they draw the hack onto this external window, so it can't be detected by taking a screenshot of the game itself.

My approach at the moment is to - 1. take a screenshot of the game window. 2. take a screenshot of the windows desktop for the same coordinates. 3. perform image analysis to compare screenshot 1 to screenshot 2 to see if there is a difference.

My problem is that screenshot 1 and screenshot 2 are not performed simultaneously so new game frames can be drawn between the two screenshots, causing false positives when the images are compared.

I want to know if there is a way to coordinate the screenshots so they occur at exactly the same time ? or somehow stop the screen drawing any new frames until my screenshots are finished?

This is the code I use for taking screenshots. Note, I have even tried to take the 2 screenshots in parallel by queuing two work items. However, even this doesn't result in the screenshots happening at exactly the same time. So I wonder if there is some way to stop any further updates to screen from the graphics card until my screenshots finish? Or any other way I can do this?

    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;
    }
like image 892
DaManJ Avatar asked Nov 02 '22 16:11

DaManJ


1 Answers

You are not going to be able to have both screenshots simultaneously, unless you resource to some graphic accelarators, meaning that that will not work in every computer...

About stopping rendering, as it is a game, I think this is not so good idea... you want your game to run smoothly.

Instead I would like to suggest to store recently rendered images of your game in memory, and when you take the screenshot compare it to them. If you can add some visual clue to decide which of the recent frames to compare to then it will work much better, because otherwise you will have to compare the screenshot to all of them and that will certainly eat some CPU/GPU time.

Are you using GDI to render? if so, what you want is to store the frames of your game in DIBs (Device Independent Bitmaps) to be able to compare them.

As for the clue to decide which image to use, I would go for some sort of time representation on screen, maybe a single pixel that changes color. If so, you will read the color of that pixel, use it to find the right frame, and them proced to compare the whole picture.

like image 60
Theraot Avatar answered Nov 15 '22 06:11

Theraot