Author Topic: Odd Issue  (Read 846 times)

WolfTechGames

  • Newbie
  • *
  • Thank You
  • -Given: 6
  • -Receive: 4
  • Posts: 35
    • View Profile
Odd Issue
« on: June 10, 2017, 02:50:46 PM »
So I have an issue where hosting a server in the editor works fine even connecting works fine. In the build exe, it makes the exe not respond when hosting and it force closes. If you try connecting from build, it just force closes the exe without a warning. I checked the log files and couldn't find any errors or anything. I am really confused as it seems to only be with this project. All my other projects that use TNet are fine.

Note: the project was converted from using Forge, it's only the hosting part that has an issue right now.

WolfTechGames

  • Newbie
  • *
  • Thank You
  • -Given: 6
  • -Receive: 4
  • Posts: 35
    • View Profile
Re: Odd Issue
« Reply #1 on: June 10, 2017, 07:40:33 PM »
After reading on the forums I think this may be an issue related to Application.Quit() being called. I will look into my code.

WolfTechGames

  • Newbie
  • *
  • Thank You
  • -Given: 6
  • -Receive: 4
  • Posts: 35
    • View Profile
Re: Odd Issue
« Reply #2 on: June 10, 2017, 08:02:59 PM »
Issue resolved: Anti-cheat is being triggered forcing the game to close but the game just says not responding.

WolfTechGames

  • Newbie
  • *
  • Thank You
  • -Given: 6
  • -Receive: 4
  • Posts: 35
    • View Profile
Re: Odd Issue
« Reply #3 on: June 10, 2017, 08:11:33 PM »
Does TNet possibly try to inject a dll or something at runtime when starting or joining a server? Seems like the injection detection was causing this.

cmifwdll

  • Global Moderator
  • Sr. Member
  • *****
  • Thank You
  • -Given: 0
  • -Receive: 149
  • Posts: 285
  • TNet Alchemist
    • View Profile
Re: Odd Issue
« Reply #4 on: June 10, 2017, 10:57:17 PM »
No, and the anticheat toolkit asset is absolutely horrendous and should never be used. Its "injection detection" just scans loaded assemblies and if a name isn't whitelisted the "detection" event is fired. It's possible TNet's RuntimeCode package creates and loads an assembly at runtime, but extremely unlikely. I don't have the package to verify.

Seriously though, that anticheat is a complete joke. A brain-dead paraplegic monkey can completely bypass it several different ways with no risk of detection.

WolfTechGames

  • Newbie
  • *
  • Thank You
  • -Given: 6
  • -Receive: 4
  • Posts: 35
    • View Profile
Re: Odd Issue
« Reply #5 on: June 11, 2017, 11:21:37 AM »
No, and the anticheat toolkit asset is absolutely horrendous and should never be used. Its "injection detection" just scans loaded assemblies and if a name isn't whitelisted the "detection" event is fired. It's possible TNet's RuntimeCode package creates and loads an assembly at runtime, but extremely unlikely. I don't have the package to verify.

Seriously though, that anticheat is a complete joke. A brain-dead paraplegic monkey can completely bypass it several different ways with no risk of detection.

Haha you knew right away. Ya, it has to be something triggering it. Anyways, do you know of any other anti-cheat solutions I could use in Unity? I don't really have the drive to mess around with developing my own anti-cheat solution right now as I will have to learn more about hacks themselves. I will eventually get to it but at the time I am looking for a quick solution.

cmifwdll

  • Global Moderator
  • Sr. Member
  • *****
  • Thank You
  • -Given: 0
  • -Receive: 149
  • Posts: 285
  • TNet Alchemist
    • View Profile
Re: Odd Issue
« Reply #6 on: June 12, 2017, 12:21:06 AM »
I think the only real solution is to go with a well-established anticheat (EAC, punkbuster, VAC, battleye, etc). The guys behind anticheat's are far more experienced and knowledgeable. The concepts involved in building a solid anticheat are entirely different than game development or even general programming.

The best advice I can offer that I think most would agree with: go native. Anything managed can be rewritten (on the disk or at runtime) in a way that (probably?) can't be detected from the managed environment. Additionally, from a cheater's viewpoint, working with managed code is a lot easier than trying to make sense of compiled native code, so you'll deter a good deal of cheaters simply by moving your anticheat to the native environment.

I think this should prove easy and (somewhat) low-effort enough, but still offer far greater security than that (in my opinion) silly anticheat toolkit asset:
Compile a native DLL named 'anticheat'. The sole purpose of this DLL is to manual-map your actual anticheat module into your process. You could write the anticheat stub to your exe manually and save the change, but I think having the obviously-named DLL will lure would-be cheaters into thinking their target is the DLL (rather than the actual stub). They'll eventually figure out the DLL just writes the stub, but it's all about wasting their time.

The stub itself is the entirety of your anticheat logic, and so should have a few goals:
Detect mono injection, detect common cheat processes, and detect common cheating techniques. These are in order of simplicity with the first being the most simple.

Note before continuing: my usage of the term 'stub' above isn't really accurate. Stub generally refers to raw code with no (or little) data or library calls. I just mean that your anticheat module should probably be encrypted before it's loaded into your game process, and I'm referring to this encrypted blob as a 'stub'.

Detecting mono injection:
Since this is Unity, the best thing you can do is hook some mono functions to detect mono injection. mono_domain_assembly_open(...) would be a good choice. If the filename isn't on a whitelist then flag as cheater. You could probably implement file integrity checks on your own managed DLLs here too, though I'm not sure about Unity's execution order of native plugins. You'd need your hook to be installed before Unity loads Assembly-CSharp.
mono_thread_attach(...) is another good choice: read the stack to find the caller, if the caller isn't a known function (ie an actual Unity function) then flag as cheater.

The two remaining goals should run in an infinite loop on a separate thread. Sleep every X seconds (you don't want to be scanning *constantly* as these are very expensive operations).

Detecting common cheat processes:
In addition to the obvious scanning of process names, you can enumerate all windows and check the class name. You can use EnumWindows and EnumChildWindows. Some common cheat processes: Cheat Engine, ReClass, IDA, ollydbg, Extreme Injector. You'll have to gather the class names (could use Microsoft's Spy++ tool which can be launched from Visual Studio>Tools). If the class name is too generic, try to find some other unique but constant data. If a blacklisted match is found then try to find some other application-specific info then flag the account as a suspected cheater and close your game. Important that a detection here doesn't auto-ban as these tools could be used for non-cheating tasks as well.

Detecting common cheating techniques:
This is where the real cat and mouse game begins. There are innumerable ways of getting data out of your game or putting logic into your game. I'll just list some common techniques, a way to detect that technique (cat), and possibly a way to counter the detection of that technique (mouse):
  • Using tools like Cheat Engine to read from / write to your game's memory
    • Anticheat #1: Enumerate all process' open handles using NtQuerySystemInformation. If a process has a handle to your game, check what it's up to.
    • Anti-anticheat #1: Close the handle immediately, or share a handle with a "safe" process like an antivirus.
    • Anticheat #2: Install a system-wide API hook for ReadProcessMemory and WriteProcessMemory using SetWindowsHookEx, check if the target is your game. System-wide API hooks will put a hamper on system performance as the hook DLL will be injected into each and every process.
    • Anti-anticheat #2: Don't call the high-level function directly, or detect and overwrite the hook.
  • Inject a DLL into your game using CreateRemoteThread & LoadLibrary
    • Anticheat #1: Hook LoadLibrary (in your process, not system-wide) and check the DLL's path.
    • Anti-anticheat #1: Call LdrLoadDLL instead of LoadLibrary.
    • Anticheat #2: Check for newly-created threads in your process. Maybe you can install a system-wide hook for CreateRemoteThread. Unity may create/destroy threads at will, so keeping a list of known "safe" threads isn't feasible, but you could check whether any given thread is within your application's known address space. Could also maybe detect thread creation in your process using TLS, but I haven't looked into it, and I'm not sure if you can install TLS callbacks at runtime.
    • Anti-anticheat #2: Whatever, use a different injection technique.
  • Inject a DLL into your game using manual-mapping
    • Anticheat #1: See above regarding ReadProcessMemory / WriteProcessMemory
    • Anti-anticheat #1: See above
    • Anticheat #2: Try to keep track of your process' memory. The cheater will (almost certainly) have to allocate memory for their code, try to detect that allocation.
    • Anti-anticheat #2: I dunno, hook whatever calls are used to detect allocations or target the anticheat directly. Could also write to existing, but unused memory within the process (sections are often padded, aren't they?)
  • Inject a DLL using SetWindowsHookEx
    • Anticheat #1: I don't know how SetWindowsHookEx works under the hood, so no clue. Probably a combination of the above could work.
  • Inject a DLL using AppInit_DLLs registry key. DLLs here are loaded by user32.dll, and Unity imports user32.dll
    • Anticheat #1: Check the AppInit_DLLs registry key.
    • Anti-anticheat #1: Restore the registry key once injected into target process, maybe?

The list goes on and on, and this is just userland stuff. Kernel cheats comprise an entirely different set of techniques and are gaining popularity. This doesn't even get into protecting your anticheat from direct attacks, either. You can see why using an established anticheat is the best option :P I think implementing everything listed here will catch 95% of cheaters, though. Just the first two goals, and maybe checking for open handles, should catch 90% of cheaters.

Also worth noting that anticheat should begin on the server, too: trust the client with as little as possible and they simply won't be able to cheat a whole lot of things. God mode, noclip, flying, speed hacks, item spawning, etc can all be detected (and prevented) server-side. This is tricky with TNet as it's client (technically host)-authoritative but still possible.

Finally, as I'm sure ArenMook will pop in and say, you probably shouldn't be worrying about anticheat until it becomes a problem. Let's be real: far more games exist than cheat-makers, so it's impossible for there to be cheaters in every game. They usually flock to the major hits.

I just can't believe something (in my opinion) so ineffective like that anticheat toolkit asset is actually being used (or even exists), so I feel it's my responsibility to steer people away from it anytime I see it mentioned/used. In my opinion, it does so, so... *so* little to actually protect your game. A cheater can just destroy the GameObject that holds the "detector" components, or modify the IL using something like reflexIL to completely remove the "detection" function calls before the game is even launched. Just two of many ways to *completely* disable this asset (or any similar existing solely in the managed environment) with less effort than I put into this post.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,154
  • Toronto, Canada
    • View Profile
Re: Odd Issue
« Reply #7 on: June 18, 2017, 07:56:22 PM »
Just to add to cmifwdll's post, CheatEngine has been the most common thorn in my experience as it's so simple that any noob can use it -- and let's face it, most cheaters are exactly that. It's not difficult to defeat it. Simply obfuscate your values. Don't store integers / floats in memory. For example if your player has 2345 HP, it's trivial to search for exactly that value in memory and find it, thus making it possible to edit it. Obfuscating this value somehow will make it quite a bit more difficult to find it. That said, getting damaged will change the player's HP, which will make it possible to locate it and "freeze" it to force invulnerability -- but not if you use two values -- one for the HP, another for a timestamp or something similar. Timestamp could be checked against some other value and if it's evident that it was frozen, quit the game. AntiCheat, while completely horrible for anything serious, does offer a way to obfuscate values for you and detect unauthorized changes from what I recall -- but that toolkit's usefulness pretty much ends there.