using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Timers; using KaduhServer; namespace PatcherServer.FileCheck { public class HackServer { private Socket sListener; private Timer sTimer = new Timer(1000); public Dictionary Sessions = new Dictionary(); public HackServer() { try { sListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); sListener.Bind(new IPEndPoint(IPAddress.Any, FileSecurity.HackPort)); sListener.Listen(100); sTimer.Start(); sTimer.Elapsed += new ElapsedEventHandler(sTimer_Elapsed); sListener.BeginAccept(new AsyncCallback(OnConnect), sListener); } catch (SocketException ex) { Log.WriteLine(ELogLevel.Exception, "IDSserver error: {0}", ex.Message); } } List toRemove = new List(); void sTimer_Elapsed(object sender, ElapsedEventArgs e) { //check authenciated delay try { lock (Sessions) { foreach (var x in Sessions) { if (x.Value.didFileCheck) { if ((DateTime.Now - x.Value.Authenciated).TotalMinutes > 2) { toRemove.Add(x.Key); Log.WriteLine(ELogLevel.Warn, "Sitzung abgelaufen {0}", x.Key); } } } toRemove.ForEach(p => Sessions[p].Disconnect()); toRemove.Clear(); } } catch { } } public void SendMessage(string message, bool shutdown, HackClient client) { Packet lolz = new Packet(7); lolz.WriteString(message); lolz.WriteBool(shutdown); client.SendPacket(lolz); } public bool isAuth(string IP) { return Sessions.ContainsKey(IP); } private void OnConnect(IAsyncResult ar) { try { Socket client = sListener.EndAccept(ar); HackClient hClient = new HackClient(client); hClient.OnDisconnect += new HackClient.HackClientPass(hClient_OnDisconnect); string IP = client.RemoteEndPoint.ToString().Split(':')[0]; lock (Sessions) { if (Sessions.ContainsKey(IP)) Sessions.Remove(IP); Sessions.Add(IP, hClient); } Log.WriteLine(ELogLevel.Debug, "Neue Sitzung empfangen von: {0}", IP); hClient.OnPacketReceived += new HackClient.PassPacket(hClient_OnPacketReceived); sListener.BeginAccept(new AsyncCallback(OnConnect), sListener); } catch (SocketException) { Sessions.Clear(); Log.WriteLine(ELogLevel.Error, "DDoS Attack Detected"); sListener.BeginAccept(new AsyncCallback(OnConnect), sListener); } } void hClient_OnPacketReceived(Packet pPacket, HackClient pClient) { ushort opcode; if (!pPacket.ReadUShort(out opcode)) { pClient.Disconnect(); return; } switch (opcode) { default: Log.WriteLine(ELogLevel.Warn, "Invalid opcode: {0}", opcode); break; case 38: string error = ""; if(!pPacket.ReadString(out error)) return; Log.WriteLine(ELogLevel.Error, "Client reported error: {0}", error); break; case 2: //PC Info string OSVersion = ""; long Time = 0; if (!pPacket.ReadString(out OSVersion) || !pPacket.ReadLong(out Time)) { pClient.Disconnect(); return; } TimeSpan timeDifference = DateTime.Now - new DateTime(Time); if (Math.Abs(timeDifference.Hours) > 24) { pClient.Disconnect(); return; } pClient.OS = OSVersion; pClient.gotPCInfo = true; RequestFileCheck(pClient); break; case 3: string username = ""; if (!pPacket.ReadString(out username)) { pClient.Disconnect(); return; } pClient.Username = username; //TODO: on disconnection process ip + username break; case 5: //filecheck response HandleFileChecks(pPacket, pClient); break; } } void hClient_OnDisconnect(HackClient pClient) { lock (Sessions) { if (Sessions.ContainsKey(pClient.IP)) { Sessions.Remove(pClient.IP); } else Log.WriteLine(ELogLevel.Exception, "Tried to dispose client object without when null."); } } void RequestFileCheck(HackClient pClient) { Packet requestFileCheck = new Packet(4); requestFileCheck.WriteUShort((ushort)FileSecurity.FileChecks.Count); foreach (var x in FileSecurity.FileChecks) { requestFileCheck.WriteString(x.Key); } pClient.SendPacket(requestFileCheck); } void HandleFileChecks(Packet packet, HackClient client) { try { ushort count = 0; if (!packet.ReadUShort(out count)) { client.Disconnect(); return; } if (count != FileSecurity.FileChecks.Count) { ModifiedFiles(client); return; } Dictionary Files = new Dictionary(); foreach (var x in FileSecurity.FileChecks) Files.Add(x.Key, false); for (ushort i = 0; i < count; ++i) { string fileName = ""; byte[] checksum = new byte[16]; if (!packet.ReadString(out fileName) || !packet.ReadBytes(checksum) || !FileSecurity.FileChecks.ContainsKey(fileName)) { client.Disconnect(); //TODO: log here return; } byte[] realCheck = FileSecurity.FileChecks[fileName]; if (!Files.ContainsKey(fileName)) { client.Disconnect(); return; } Files[fileName] = BitConverter.ToInt64(checksum, 0) == BitConverter.ToInt64(realCheck, 0); } if (Files.Count == FileSecurity.FileChecks.Count) { foreach (var x in Files) { if (x.Value == false) { ModifiedFiles(client); return; } } } client.didFileCheck = true; client.Authenciated = DateTime.Now; client.GUID = System.Guid.NewGuid().ToString(); SendGUID(client, client.GUID); Log.WriteLine(ELogLevel.Debug, "Client hat zugelassene Daten. Verbindung zugelassen."); // sowas besser dynamisch machen LaunchProgram(FileSecurity.ClientName, "-i 95.211.135.154", client); } catch (Exception ex) { Log.WriteLine(ELogLevel.Exception, ex.Message); } } void SendGUID(HackClient client, string GUID) { Packet pack = new Packet(8); pack.WriteString(GUID); client.SendPacket(pack); } void ModifiedFiles(HackClient client) { SendMessage("Du benutzt nicht die zugelassenen Daten.", true, client); client.Disconnect(); } void LaunchProgram(string filename, string pParams, HackClient client) { Packet pack = new Packet(6); pack.WriteString(filename); pack.WriteString(pParams); client.SendPacket(pack); } } }