Automatic detection of cheaters using render.Capture
13 replies, posted
Firstly this is more of a discussion than a release and I'm looking for feedback as well (the actual implementation isn't that difficult, though if there's interest I can release it). I'm quitting GMod soon so I thought about talking about a technique I started using a few weeks ago to detect hackers with a specific focus on C++ cheats that use visuals. Its been pretty effective at picking up people using ESPs that would otherwise be very difficult (if not impossible) to detect in lua.
The concept is pretty simple, draw a black screen in lua and prevent anything being drawn over it on a client and then check the output of render.Capture to see if it matches the expected (determinable) output. The client will see a black screen for a few frames and they will not be aware of whats happening (to be honest the black screen is only visible for a split second and is not a bother for anyone).
If it detects anything abnormal you can upload it to a webserver and then its really simple to review.
I was unsure of the most efficient way to process the output (reading each pixel would be silly) - I ended up base64 encoding the output and then checking if the sequence of characters is as expected (it should produce a determinable output for any given resolution).
I'm not entirely sure how this approach would stack up with (good) private cheats but it currently detects all public C++ hacks + Aimware.
My GLua/C++ knowledge isn’t good enough to make sweeping assumptions but I believe that its pretty difficult (if not impossible) for cheats to avoid without specifically targeting the implementation. Detouring render.Capture and returning nil or something else like a cached image would be detected, returning a clean screen is detectable as its not the black screen.
(A few specifics of my (poorly coded) implementation to make it slightly less creepy and more effective)
Trigger when a key (other than shit/tab) is pressed and a players position has changed.
Trigger when another player is in the players FOV.
Only take an image of a central portion of the screen - basically because many clients have legitimate things drawn on their screen like curse/skype.
Personally I think cheaters are a big issue (and an increasingly bigger issue) for GMod. I know there was some nice changes in the last update but ideally an official AC (GAC V2?) would be great to wipe out 90% of the silly cheaters.
Examples of a few detections:
[url]http://imgur.com/a/gxjkn[/url]
Interesting idea, however, there are cheats out there with "anti-screenshot" features, some specifically target render.Capture(which isn't a problem unless they just render a black screen). I'm not sure entirely what some of then do, but they may just render a black screen for render.Capture when activated.
I see you have some methods to try and detect them using the steamoverlay (if they are in game, they likely aren't shift+tabbed). Interesting methods, and in theory should yield very little false positives.
Just to be safe, before running the screen check, you could check and make sure render.Capture is not detoured or changed in any way, rather than the alternate method of making a local copy of it in your script(as some hacks could load in before and detour it, making your script think it's local copy it has the right function).
Perhaps you could make a color database on the server too, and every so often have the server dispatch a different color to use, that could cause some confusion.
I know for a fact that this is a function used in at least 2 anti-cheats and 1 administration tool, so I don't think you're the first person to do it. I've always thought it was a good idea, though.
Not a big GMod player, but according to gmod wiki render.Capture captures the current render target, this can be easily avoided simply by rendering directly to the game window or creating a separate transparent overlay window and rendering to that instead.
[QUOTE=cartman300;49840982]Not a big GMod player, but according to gmod wiki render.Capture captures the current render target, this can be easily avoided simply by rendering directly to the game window or creating a separate transparent overlay window and rendering to that instead.[/QUOTE]
Well it captures steamoverlay, and things like curse. So I'm assuming the first method wont get around it, however, the second method would definitely get around it.
But as it stands now, most cheats don't really seem to have systems like that, and don't really seem to be designed for detection methods like this(yet), so it can't really hurt anything to have a system like this.
I don't think using render.Capture would be a good idea since it would be tricky to distinguish the normal HUD from any hacker-created HUDs (at least if you're checking for the ENTIRE screen to be black)
[editline]1st March 2016[/editline]
Even if you hide the HUD, I think render.Capture still captures the steam overlay if it's open, so someone could be detected as a hacker if they had that open
[QUOTE=MPan1;49841917]I don't think using render.Capture would be a good idea since it would be tricky to distinguish the normal HUD from any hacker-created HUDs (at least if you're checking for the ENTIRE screen to be black)
[editline]1st March 2016[/editline]
Even if you hide the HUD, I think render.Capture still captures the steam overlay if it's open, so someone could be detected as a hacker if they had that open[/QUOTE]
You can disable/draw ontop of the HUD obviously.. render.Capture DOES capture the steamoverlay, that's why he wrote this:
[quote]
Trigger when a key (other than shit/tab) is pressed and a players position has changed.
Trigger when another player is in the players FOV.
[B][U]Only take an image of a central portion of the screen - basically because many clients have legitimate things drawn on their screen like curse/skype.[/U][/B]
[/quote]
He only has it activate when the player is interacting with the game world somehow, which you can't do if you're in steamoverlay(and he stated it doesn't activate with keys like shift+tab). But he stated above that he only has it capture the central portion of the screen...
Still, if someone has a weird system of drawing custom crosshairs, the render.Capture could capture the crosshair if the rectangle somehow gets drawn underneath it
[editline]1st March 2016[/editline]
Also, with this:
[QUOTE=Brassx;49842082]He only has it activate when the player is interacting with the game world somehow[/QUOTE]
What if he's in the spawnmenu or changing something in a derma panel?
[editline]1st March 2016[/editline]
My point with my post before was that the whole render.Capture idea could be gotten around if a hacker used HUDPaint to draw his targets or whatever, then the black rectangle would likely be drawn on top of the HUDPaint stuff, making the check useless
[editline]1st March 2016[/editline]
Also, if he's only capturing the center of the screen, then why not have a bunch of hack buttons or something off to the side of the screen where they won't be found?
[QUOTE=MPan1;49842162]Still, if someone has a weird system of drawing custom crosshairs, the render.Capture could capture the crosshair if the rectangle somehow gets drawn underneath it[/QUOTE]
Well I imagine that if you set this system up on your server, you would be able to stop false positives like that by making sure your crosshair system doesn't interfere with it.
The client can not have custom crosshairs without the server owner setting up an addon and what not, so if they have their OWN crosshair, separate from what the server says is allowed, they probably used external means to enable it. Which is a security risk, because if they can run a crosshair, they can run wallhacks, aimbots, etc. So detecting that is fine by me.
There are several ways of actually drawing on the users screen so that it will always be on top of any in-game element, so again, anything drawn after that is an external overlay in the game window.
For example:
[code]
local f = vgui.Create("DPanel");
f:SetDrawOnTop(true);
f:SetSize(2, 2);
f:Center();
function f:Paint(w, h)
//since the size is 2 x 2, we know the direct center of the screen is 1, 1 in local coords.
DisableClipping(true);//This will allow you to draw outside of the panel from this function
surface.SetDrawColor(Color(0, 0, 0));
surface.DrawRect(1 - (ScrW() * .5), 1 - ScrH() * .5, ScrW(), ScrH());
DisableClipping(false);
end
timer.Simple(5, function()
f:Remove();
end)
[/code]
This would draw a completely black screen that even draws on top of the main menu/console (feel free to try it).
This method is mainly for detecting external c++ hacks, as they usually overlay their elements on the game window. Any lua hacks that use HUDPaint or anything can be detected by other means. This isn't a solution for everything, just something helpful to detect c++ hacks, that are pretty damn hard to detect with lua by other means. It's job is to mainly detect wallhacks, as you can't have those off to the side or anything of the sort. Also if you look at the UI for c++ hacks like aimware, it takes up a large chunk of the screen, and is an overlay (drawn ontop of everything else), so this would detect that.
I assumed other people had similar systems but I've personally never seen it discussed on FP before.
A key thing is I do not have any autobanning system in place, they all get collated on a webpage and then it takes seconds to see if it was a false positive.
Also, though this is implementation specific detouring render.Capture is unlikely to bypass this. They could return a black screen but its not difficult to use randomised different shades of black and ReadPixel to check the colour.
[quote]
Not a big GMod player, but according to gmod wiki render.Capture captures the current render target, this can be easily avoided simply by rendering directly to the game window or creating a separate transparent overlay window and rendering to that instead.
[/quote]
I don't really know how graphics work so I could be talking out my ass, but I thought render.Capture would take the current frame buffer so anything rendered ingame would be shown. The second is actually kinda cool idea but as far as I know no cheats do that at the moment.
[QUOTE=MPan1;49842162]
[editline]1st March 2016[/editline]
Also, with this:
What if he's in the spawnmenu or changing something in a derma panel?
[editline]1st March 2016[/editline]
My point with my post before was that the whole render.Capture idea could be gotten around if a hacker used HUDPaint to draw his targets or whatever, then the black rectangle would likely be drawn on top of the HUDPaint stuff, making the check useless
[editline]1st March 2016[/editline]
Also, if he's only capturing the center of the screen, then why not have a bunch of hack buttons or something off to the side of the screen where they won't be found?[/QUOTE]
Though its not 100% effective I draw the blackscreen in RenderScreenspaceEffects and prevent anything legitimate form being drawn afterwards. Though I only did this as I was getting impatient for C++ cheats to join and wanted to pickup as many people as possible before my server closes.
Here's an example of a cheater I assume had derma open at the time (as it was open in the follow up screenshot a second later).
[url]https://i.gyazo.com/6d116cdd199366c0c41ab3351184bfda.png[/url]
There's a check to start when players are in the FOV and its mainly targeting ESPs/bounding boxes moving stuff would not help.
[QUOTE=Brassx;49842225]
This method is [B]mainly for detecting external c++ hacks[/B], as they usually overlay their elements on the game window. Any lua hacks that use HUDPaint or anything can be detected by other means. This isn't a solution for everything, [B]just something helpful to detect c++ hacks, that are pretty damn hard to detect with lua by other means[/B]. It's job is to mainly detect wallhacks, as you can't have those off to the side or anything of the sort. Also if you look at the UI for c++ hacks like aimware, it takes up a large chunk of the screen, and is an overlay (drawn ontop of everything else), so this would detect that.[/QUOTE]
Exactly.
Instead of writing a lua anticheat, why not write a C++ anticheat?
I'm installing GMod once again, i'm going to test what exactly render.Capture does by trying to render to the game window using a few different ways. I'm gonna get back to you.
Besides, i think steam overlay hooks the graphics API directly, because else you wouldn't be able to render anything directly to the game window in true fullscreen as the game takes exclusive access to the screen.
[QUOTE=Jonzky;49839768]Firstly this is more of a discussion than a release and I'm looking for feedback as well (the actual implementation isn't that difficult, though if there's interest I can release it). I'm quitting GMod soon so I thought about talking about a technique I started using a few weeks ago to detect hackers with a specific focus on C++ cheats that use visuals. Its been pretty effective at picking up people using ESPs that would otherwise be very difficult (if not impossible) to detect in lua.
The concept is pretty simple, draw a black screen in lua and prevent anything being drawn over it on a client and then check the output of render.Capture to see if it matches the expected (determinable) output. The client will see a black screen for a few frames and they will not be aware of whats happening (to be honest the black screen is only visible for a split second and is not a bother for anyone).
If it detects anything abnormal you can upload it to a webserver and then its really simple to review.
I was unsure of the most efficient way to process the output (reading each pixel would be silly) - I ended up base64 encoding the output and then checking if the sequence of characters is as expected (it should produce a determinable output for any given resolution).
I'm not entirely sure how this approach would stack up with (good) private cheats but it currently detects all public C++ hacks + Aimware.
My GLua/C++ knowledge isn’t good enough to make sweeping assumptions but I believe that its pretty difficult (if not impossible) for cheats to avoid without specifically targeting the implementation. Detouring render.Capture and returning nil or something else like a cached image would be detected, returning a clean screen is detectable as its not the black screen.
(A few specifics of my (poorly coded) implementation to make it slightly less creepy and more effective)
Trigger when a key (other than shit/tab) is pressed and a players position has changed.
Trigger when another player is in the players FOV.
Only take an image of a central portion of the screen - basically because many clients have legitimate things drawn on their screen like curse/skype.
Personally I think cheaters are a big issue (and an increasingly bigger issue) for GMod. I know there was some nice changes in the last update but ideally an official AC (GAC V2?) would be great to wipe out 90% of the silly cheaters.
Examples of a few detections:
[url]http://imgur.com/a/gxjkn[/url][/QUOTE]
[url]https://github.com/Leystryku/Nikyuria/blob/master/src/overlay.cpp[/url]
Overlays like this can't be detected at all even though it uses C++ and is public :v:
[QUOTE=Leystryku;49844036][url]https://github.com/Leystryku/Nikyuria/blob/master/src/overlay.cpp[/url]
Overlays like this can't be detected at all even though it uses C++ and is public :v:[/QUOTE]
Cool, I'll take a look at the source soon. Just curious though, do you think its possible to detect your visuals (in that cheat) from lua?
Surely there comes a point where an official AC or blacklisting of modules is needed - games like Hide and Seek, Prophunt completely break when there are cheats and server owners are becoming increasingly less equipped to handle them.
Here are some screenshots I took back in 2013 when I first developed my script.
[URL]https://imgur.com/a/2WJd2[/URL]
Also some of the more recent ones.
[URL]https://imgur.com/a/Rfp5Z[/URL]
I have to say though. I feel as though I need an upgrading on my anti-cheat even still after being able to catch them now. There's much I can do automatically now.
Any other recommendations? PM if needed.
Sorry, you need to Log In to post a reply to this thread.