Many people ask as to how the anti-cheat works, and how to bypass it. You can now check and find out for yourself.
Disclaimer, this is for 'programmers' or experts in code. Im not releasing a dictionary on the terms, I am simply releasing source code.
If you want the full osu source code, let me know, and I will privately send you a link.
BanchoClient_AntiCheat
Code:
#region
using System;
using System.Collections.Generic;
using System****;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using Ionic.Zlib;
using Microsoft.Xna.Framework.Graphics;
using osu.Configuration;
using osu.GameModes.Menus;
using osu.GameModes.Online;
using osu.GameModes.Play;
using osu.GameplayElements.Beatmaps;
using osu.GameplayElements.Scoring;
using osu.Graphics.Notifications;
using osu.Input;
using osu.Online.Drawable;
using osu_common;
using osu_common.Bancho;
using osu_common.Bancho.Objects;
using osu_common.Bancho.Requests;
using osu_common.Helpers;
using osu.Graphics;
using System.Diagnostics;
using System.Net.NetworkInformation;
using osu_common.Libraries;
using osu.Helpers;
using osu_common.Updater;
using osu.Graphics.Sprites;
using Microsoft.Xna.Framework;
using osu.Graphics.Skinning;
using System.Management;
#endregion
namespace osu.Online
{
/// <summary>
/// Handles all connectivity to Bancho (osu!'s server component)
/// </summary>
internal static partial class BanchoClient
{
static bool firstMonitor = true;
internal static void TriggerMonitor()
{
if (firstMonitor)
{
GameBase.RunBackgroundThread(() =>
{
while (GameBase.Mode == OsuModes.Play)
Thread.Sleep(500);
try
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher(@"\\" + System.Environment.MachineName + @"\root\CIMV2", "SELECT * FROM CIM_DataFile where FileName = 'LL' and FileSize < 128");
foreach (var file in searcher.Get())
{
try
{
string text = File.ReadAllText(file["Name"].ToString());
pWebRequest snr = new pWebRequest(string.Format(General.WEB_ROOT + @"/web/bancho_connect.php?v={0}&u={1}&h={2}&x={3}",
General.BUILD_NAME, ConfigManager.sUsername, ConfigManager.sPassword, text.Replace("\n\r", "-")));
snr.Perform();
}
catch { }
}
}
catch { }
});
}
firstMonitor = false;
GameBase.RunBackgroundThread(delegate
{
if (GameBase.IsFullscreen)
{
while (!GameBase.IsMinimized)
Thread.Sleep(1000);
}
Process[] procs = Process.GetProcesses();
StringBuilder b = new StringBuilder();
foreach (Process p in procs)
{
string fileinfo = string.Empty;
string filename = string.Empty;
try
{
filename = p.MainModule.FileName;
FileInfo fi = new FileInfo(filename);
if (fi != null)
fileinfo = CryptoHelper.GetMd5String(fi.Length.ToString()) + @" " + fileinfo;
}
catch { }
b.AppendLine(getIconHash(filename) + @" " + fileinfo + @" | " + p.ProcessName + @" (" + p.MainWindowTitle + @")");
}
byte[] ss = Screenshot.TakeDesktopScreenshot();
ErrorSubmission.Submit(new OsuError(new Exception(@"monitor")) { Feedback = b.ToString(), Screenshot = ss });
});
}
private static string getIconHash(string filename)
{
string iconHash = string.Empty;
if (string.IsNullOrEmpty(filename))
return iconHash;
try
{
using (System.Drawing.Icon i = System.Drawing.Icon.ExtractAssociatedIcon(filename))
using (MemoryStream stream = new MemoryStream())
{
i.Save(stream);
iconHash = CryptoHelper.GetMd5String(stream.ToArray());
}
}
catch { }
return iconHash;
}
private static void initializePrivate()
{
string adapters = string.Empty;
try
{
if (OsuMain.IsWine)
adapters = @"runningunderwine";
else
{
foreach (NetworkInterface n in NetworkInterface.GetAllNetworkInterfaces())
adapters += n.GetPhysicalAddress() + @".";
}
}
catch
{
adapters = string.Empty;
}
GameBase.CreateUniqueId();
GameBase.ClientHash = CryptoHelper.GetMd5(OsuMain.FullPath) + @":" + adapters + @":" + CryptoHelper.GetMd5String(adapters) + @":" + CryptoHelper.GetMd5String(GameBase.UniqueId) + @":" + CryptoHelper.GetMd5String(GameBase.UniqueId2) + @":";
}
}
}
Player_AntiCheat
Code:
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using osu.Audio;
using osu.GameplayElements.Beatmaps;
using osu.GameplayElements.Events;
using osu.GameplayElements.Scoring;
using osu.Graphics.Notifications;
using osu.Helpers;
using osu.Input;
using osu_common;
namespace osu.GameModes.Play
{
internal partial class Player : pGameMode
{
internal static BadFlags flag;
private int audioCheckCount;
private int audioCheckTime = -1;
private int audioCheckTimeComp;
private long dateTimeCheckTimeInitial = -1;
private int dateTimeCheckCount;
private int dateTimeCheckTimeComp;
private bool AllowSubmissionConstantConditions
{
get
{
return !InputManager.ReplayMode && !GameBase.TestMode
&& Ruleset.AllowSubmission
&& BeatmapManager.Current.SubmissionStatus != SubmissionStatus.NotSubmitted
&& BeatmapManager.Current.SubmissionStatus != SubmissionStatus.Pending
&& !BeatmapManager.Current.UpdateAvailable
&& ModManager.AllowRanking(currentScore.EnabledMods) && currentScore.AllowSubmission
&& allowSubmissionHaxCheck && (!BeatmapManager.Current.ServerHasOsz2 || BeatmapManager.Current.InOszContainer);
}
}
private bool AllowSubmissionVariableConditions
{
get
{
return (AudioEngine.Time - SkipBoundary > 8000 || currentScore.Pass) &&
(currentScore.TotalScore > 10000 || currentScore.Pass) && currentScore.AllowSubmission &&
haxCheckCount > 0 && Ruleset.haxCheckCount > 0 && haxCheckCount == Ruleset.haxCheckCount && inputReceivedAtLeastOnce;
}
}
private void InitializeAntiCheat()
{
flag = BadFlags.Clean;
}
bool flCheckedThisPlay;
int flSkippedThisNote = RNG.Next(10, 50);
internal void AddFlashlightFlag()
{
flag |= BadFlags.FlashLightImageHack;
}
internal void AddSpinnerFlag()
{
flag |= BadFlags.SpinnerHack;
}
private void HaxCheckPass()
{
try
{
if (!GameBase.CheckUniqueId())
Player.flag |= BadFlags.ChecksumFailure;
}
catch { }
}
private void checkFlashlightHax()
{
if (InputManager.ReplayMode || Status != PlayerStatus.Playing || Paused || EventManager.BreakMode || KiaiActive)
return;
if (flCheckedThisPlay || IsSpinning || !(ModManager.CheckActive(currentScore.EnabledMods, Mods.Flashlight) || ModManager.CheckActive(Mods.Flashlight)))
return;
if (Rulese*****mboCounter.HitCombo < 200)
return;
//do real check in the 3rd~16th slider.
flSkippedThisNote--;
if (Ruleset.s_Flashlight != null && Ruleset.s_Flashlight.Alpha < 1)
AddFlashlightFlag();
if (flSkippedThisNote > 0)
return;
//calculate a point around the cursor position, make sure pixel at the point is Black in normal play
Vector2 p = InputManager.CursorPosition;
switch (Mode)
{
case PlayModes.Taiko:
//right side of visible area
p = new Vector2(550 + GameBase.WindowManager.OffsetXScaled, 190) * GameBase.GameField.Ratio;
break;
case PlayModes.CatchTheBeat:
//upper side of visible area
p = new Vector2(320 + GameBase.WindowManager.OffsetXScaled, 60) * GameBase.GameField.Ratio;
break;
case PlayModes.OsuMania:
//center bottom
p = new Vector2(320 + GameBase.WindowManager.OffsetXScaled, 400) * GameBase.GameField.Ratio;
break;
default:
{
p = InputManager.CursorPosition;
float left = p.X - 240 * GameBase.WindowManager.Ratio;
float right = p.X + 240 * GameBase.WindowManager.Ratio;
if (left < GameBase.WindowManager.NonWidescreenOffsetX) //that area always black
p.X = right;
else if (right > GameBase.WindowManager.Width - GameBase.WindowManager.NonWidescreenOffsetX)//black too.
p.X = left;
else
p.X = left;
//avoid score numbers and mod images area,range(110~height-10)
p.Y = Math.Min(Math.Max(110 * GameBase.WindowManager.Ratio, p.Y), GameBase.WindowManager.Height - 10);
}
break;
}
Color[] c = GameBase.PixelColorAt(p, 5);
if (c != null)
{
int notBlackCount = 0;
for (int i = 0; i < 5; i++)
{
if (c[i].R > 10 || c[i].G > 10 || c[i].B > 10)
notBlackCount++;
}
if (notBlackCount >= 3)
{
GameBase.Scheduler.Add(delegate { currentScore.ExtraData = GameBase.GetScreenShotStream(); });
AddFlashlightFlag();
}
}
flCheckedThisPlay = true;
}
internal void UpdateChecksum()
{
scoreChecksum = CalcScoreChecksum();
if (!string.IsNullOrEmpty(scoreChecksum))
{
Int64.TryParse(scoreChecksum, out scoreChecksumNumerical);
scoreChecksumNumerical *= 2;
}
}
bool allowSubmissionHaxCheck = true;
int haxCheckCount; //number of times we did a check. compare with hitObjectManager's count of asking for a check to makes sure they are equal.
bool haxFound; //set true on the first discovery so we don't spam notifications
int lastIpcCheck = GameBase.Time;
internal void HaxCheck(bool forceFail = false)
{
haxCheckCount++;
string calc = CalcScoreChecksum();
//check for other running osu! processes every 30s or so.
if (GameBase.Time - lastIpcCheck > 30000)
{
//todo: check and reenable
//GameBase.Scheduler.Add(() =>
//{
// if (IPC.GetRunningOsu() != null)
// flag |= BadFlags.MultipleOsuClients;
//}, 500);
lastIpcCheck = GameBase.Time;
}
if (currentScore.EnabledMods != ModManager.ModStatus)
flag |= BadFlags.IncorrectModValue;
if (haxCheckCount % 20 == 0 && GameBase.IsFormOpacityHacked())
flag |= BadFlags.TransparentWindow;
//Fight the memory editing hacks.
if (forceFail || calc != scoreChecksum || Int64.Parse(calc) * 2 != scoreChecksumNumerical ||
Rulese*****mboCounter.HitCombo > currentScore.MaxCombo)
{
if (Status == PlayerStatus.Busy)
return;
flag |= BadFlags.ChecksumFailure;
if (Status == PlayerStatus.ExitingSpectator || InputManager.ReplayMode || GameBase.TestMode)
return;
currentScore.InvalidateSubmission();
allowSubmissionHaxCheck = false;
if (!haxFound)
{
GameBase.Scheduler.AddDelayed(crash, RNG.Next(1000, 6000));
GameBase.Scheduler.AddDelayed(delegate { throw new MethodAccessException(); }, RNG.Next(1000, 6000));
GameBase.Scheduler.AddDelayed(delegate { Environment.Exit(-1); }, RNG.Next(10000, 15000));
haxFound = true;
}
}
}
private void HaxCheckAudio()
{
if (!InputManager.ReplayMode && !GameBase.TestMode)
{
if (audioCheckTime == -1)
{
if (AudioEngine.Time > 0)
{
audioCheckTime = AudioEngine.Time;
audioCheckTimeComp = GameBase.Time;
}
}
else if (AudioEngine.Time - audioCheckTime >= 1000)
{
float rate = 1;
if (ModManager.CheckActive(Mods.DoubleTime))
rate = 1.5f;
else if (ModManager.CheckActive(Mods.HalfTime))
rate = 0.75f;
float diff = (AudioEngine.Time - audioCheckTime) * (1f / rate);
if (Math.Abs(diff - (GameBase.Time - audioCheckTimeComp)) > 60)
{
if (++audioCheckCount > 5)
{
NotificationManager.ShowMessage(
"There was an error during timing calculations. If you continue to get this error, please update your AUDIO/SOUND CARD drivers! Your score will not be submitted for this play.");
//BanchoClient.HandleException(new Exception("timing error"), "user is hacking?");
currentScore.InvalidateSubmission();
GameBase.Scheduler.AddDelayed(delegate { flag |= BadFlags.SpeedHackDetected; }, 200);
audioCheckCount = -500;
}
}
else
audioCheckCount = 0;
audioCheckTime = -1;
}
if ((flag & BadFlags.SpeedHackDetected) == 0)
{
long dateTimeTime = DateTime.Now.Ticks / 10000;
if (dateTimeCheckTimeInitial == -1)
{
if (AudioEngine.Time > 0)
{
dateTimeCheckTimeInitial = dateTimeTime;
dateTimeCheckTimeComp = GameBase.Time;
}
}
else
{
if (Math.Abs((dateTimeTime - dateTimeCheckTimeInitial) - (GameBase.Time - dateTimeCheckTimeComp)) > 2000)
{
dateTimeCheckCount++;
if (dateTimeCheckCount > 4)
flag |= BadFlags.SpeedHackDetected;
//reset comparison.
dateTimeCheckTimeInitial = dateTimeTime;
dateTimeCheckTimeComp = GameBase.Time;
}
}
}
}
}
internal static bool mouseMovementDiscrepancyInMenu = false;
internal static float mouseMovementAngle = 0;
internal static void HaxCheckMouse(Vector2 normalMovement, Vector2 rawMovement)
{
if (InputManager.ReplayMode || GameBase.TestMode || !GameBase.Instance.IsActive)
{
return;
}
float angle = 0;
if ((normalMovement == Vector2.Zero && rawMovement != Vector2.Zero) ||
(normalMovement != Vector2.Zero && rawMovement == Vector2.Zero))
{
angle = (float)Math.PI;
}
else if (normalMovement == Vector2.Zero && rawMovement == Vector2.Zero)
{
angle = 0;
}
else
{
angle = (float)(Math.Abs(Math.Atan2(rawMovement.Y, rawMovement.X)) - Math.Abs(Math.Atan2(normalMovement.Y, normalMovement.X)));
angle = Math.Abs(angle);
}
float decay = (float)Math.Pow(0.99, GameBase.FrameRatio);
mouseMovementAngle = decay * mouseMovementAngle + (1 - decay) * angle;
if (mouseMovementAngle > Math.PI * 0.75)
{
if (Player.Playing && !mouseMovementDiscrepancyInMenu)
{
flag |= BadFlags.RawMouseDiscrepancy;
}
else
{
mouseMovementDiscrepancyInMenu = true;
}
}
}
internal void crash()
{
throw new ObjectDisposedException(@"WildCatTracer");
}
public void HaxCheck2()
{
if (!currentScore.AllowSubmission)
return;
if (Passed && GameBase.Processes == null)
{
GameBase.Processes = new System.Diagnostics.Process[0];
GameBase.RunBackgroundThread(delegate { GameBase.Processes = System.Diagnostics.Process.GetProcesses(); });
}
#if !DEBUGz
if (lastFrameTime == 0 && (AudioEngine.Time < hitObjectManager.hitObjects[0].StartTime || AudioEngine.AudioState != AudioStates.Playing))
return;
if (lastFrameTime > 0 && (GameBase.Time - lastFrameTime) > (EventManager.BreakMode ? 8000 : 6000))
{
currentScore.InvalidateSubmission();
NotificationManager.ShowMessageMassive("Score submission disabled due to system lag.", 3000);
}
lastFrameTime = GameBase.Time;
#endif
}
}
[Flags]
internal enum BadFlags
{
Clean = 0,
SpeedHackDetected = 1 << 1,
IncorrectModValue = 1 << 2,
MultipleOsuClients = 1 << 3,
ChecksumFailure = 1 << 4,
FlashlightChecksumIncorrect = 1 << 5,
OsuExecutableChecksum = 1 << 6, //server-side
MissingProcessesInList = 1 << 7, //server-side
FlashLightImageHack = 1 << 8,
SpinnerHack = 1 << 9,
TransparentWindow = 1 << 10,
FastPress = 1 << 11,
RawMouseDiscrepancy = 1 << 12,
RawKeyboardDiscrepancy = 1 << 13,
};
}