diff --git a/FFXIVClassic.sln b/FFXIVClassic.sln
index b79d9e72..4a0fe45b 100644
--- a/FFXIVClassic.sln
+++ b/FFXIVClassic.sln
@@ -20,6 +20,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FFXIVClassic World Server",
 		{3A3D6626-C820-4C18-8C81-64811424F20E} = {3A3D6626-C820-4C18-8C81-64811424F20E}
 	EndProjectSection
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Launcher Editor", "Launcher Editor\Launcher Editor.csproj", "{0FFA9D2F-41C6-443C-99B7-665702CF548F}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -42,6 +44,10 @@ Global
 		{3067889D-8A50-40D6-9CD5-23AA8EA96F26}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{3067889D-8A50-40D6-9CD5-23AA8EA96F26}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{3067889D-8A50-40D6-9CD5-23AA8EA96F26}.Release|Any CPU.Build.0 = Release|Any CPU
+		{0FFA9D2F-41C6-443C-99B7-665702CF548F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{0FFA9D2F-41C6-443C-99B7-665702CF548F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{0FFA9D2F-41C6-443C-99B7-665702CF548F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{0FFA9D2F-41C6-443C-99B7-665702CF548F}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
diff --git a/Launcher Editor/App.config b/Launcher Editor/App.config
new file mode 100644
index 00000000..88fa4027
--- /dev/null
+++ b/Launcher Editor/App.config	
@@ -0,0 +1,6 @@
+
+
+     
+        
+    
+
\ No newline at end of file
diff --git a/Launcher Editor/Launcher Editor.csproj b/Launcher Editor/Launcher Editor.csproj
new file mode 100644
index 00000000..c1a98e86
--- /dev/null
+++ b/Launcher Editor/Launcher Editor.csproj	
@@ -0,0 +1,60 @@
+
+
+  
+  
+    Debug
+    AnyCPU
+    {0FFA9D2F-41C6-443C-99B7-665702CF548F}
+    Exe
+    Properties
+    Launcher_Editor
+    Launcher Editor
+    v4.5.2
+    512
+    true
+  
+  
+    AnyCPU
+    true
+    full
+    false
+    bin\Debug\
+    DEBUG;TRACE
+    prompt
+    4
+  
+  
+    AnyCPU
+    pdbonly
+    true
+    bin\Release\
+    TRACE
+    prompt
+    4
+  
+  
+    
+    
+    
+    
+    
+    
+    
+    
+  
+  
+    
+    
+  
+  
+    
+  
+  
+  
+
\ No newline at end of file
diff --git a/Launcher Editor/Program.cs b/Launcher Editor/Program.cs
new file mode 100644
index 00000000..53794df6
--- /dev/null
+++ b/Launcher Editor/Program.cs	
@@ -0,0 +1,508 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Launcher_Editor
+{
+    //ffxivboot.exe:
+    //Offset
+    //0x9663FC: Patch Server Port
+    //0x966404: Patch Server URL
+
+    //0x9663FC + 0x400000: Port Offset to search
+    //0x966404 + 0x400000: URL Offset to search
+
+    class Program
+    {
+        const string ORIGINAL_PATCH_PORT_STRING = "54996";
+        const string ORIGINAL_PATCH_URL_STRING = "ver01.ffxiv.com";
+        const string ORIGINAL_PATCH_LOGIN_STRING = "http://account.square-enix.com/account/content/ffxivlogin";
+
+        static void Main(string[] args)
+        {
+            byte[] exeDataBoot;
+            byte[] exeDataLogin;
+
+            string patchPortString;
+            string patchUrlString;
+            string loginUrlString;
+ 
+            string lobbyUrlString = "lobby01.ffxiv.com";
+
+            Console.WriteLine("---------------------");
+            Console.WriteLine("FFXIV 1.0 EXE Patcher");
+            Console.WriteLine("By Ioncannon");
+            Console.WriteLine("Version 1.0");
+            Console.WriteLine("---------------------");
+
+            Console.WriteLine("Please enter the full path to your FINAL FANTASY XIV folder. It should have ffxivgame.exe inside it.");
+            string path = Console.ReadLine();
+
+            if (!File.Exists(path + "\\ffxivboot.exe"))
+            {
+                Console.WriteLine("Missing ffxivboot.exe, aborting");
+                Console.ReadKey();
+                return;
+            }
+            if (!File.Exists(path + "\\ffxivgame.exe"))
+            {
+                Console.WriteLine("Missing ffxivgame.exe, aborting");
+                Console.ReadKey();
+                return;
+            }
+            if (!File.Exists(path + "\\ffxivlogin.exe"))
+            {
+                Console.WriteLine("Missing ffxivlogin.exe, aborting");
+                Console.ReadKey();
+                return;
+            }
+
+            Console.WriteLine("EXEs found!");
+
+            Console.WriteLine("Please enter the url to the patch webpage (do not include \"http://\", max 32 characters).");
+            patchUrlString = Console.ReadLine();
+            Console.WriteLine("Please enter the port to the patch webpage (usually 80).");
+            patchPortString = Console.ReadLine();
+
+            try
+            {
+                int.Parse(patchPortString);
+            }
+            catch (FormatException e)
+            {
+                Console.WriteLine("Not a number, aborting");
+                Console.ReadKey();
+                return;
+            }
+            catch (OverflowException e)
+            {
+                Console.WriteLine("Not a number, aborting");
+                Console.ReadKey();
+                return;
+            }
+
+            Console.WriteLine("Please enter the url to the login webpage (max 56 characters, please include \"http://\").");
+            loginUrlString = Console.ReadLine();
+
+            if (loginUrlString.Length > 0x56)
+            {
+                Console.WriteLine("URL too long, aborting");
+                Console.ReadKey();
+                return;
+            }
+
+            long patchPortStringOffset = 0;
+            long patchUrlStringOffset = 0;
+            long lobbyUrlStringOffset = 0;
+            long freeSpaceOffset = 0;
+
+            long loginUrlOffset = 0;
+            long freeSpaceInLoginOffset = 0;
+
+            Console.WriteLine("Patching started!");
+            exeDataBoot = File.ReadAllBytes(path + "\\ffxivboot.exe");
+            exeDataLogin = File.ReadAllBytes(path + "\\ffxivlogin.exe");
+
+            Console.WriteLine("---Editing FFXIVBOOT.EXE---");
+
+            patchPortStringOffset = PrintSearch(exeDataBoot, ORIGINAL_PATCH_PORT_STRING);
+            patchUrlStringOffset = PrintSearch(exeDataBoot, ORIGINAL_PATCH_URL_STRING);            
+            freeSpaceOffset = PrintFreeSpaceSearch(exeDataBoot);
+
+            if (patchPortStringOffset == -1 || patchUrlStringOffset == -1 || freeSpaceOffset == -1)
+            {
+                Console.WriteLine("There was an error finding the address locations...");
+                Console.ReadKey();
+                return;
+            }
+
+            Console.WriteLine("Writing \"{0}\" and updating offset to 0x{1:X}.", patchPortString, freeSpaceOffset);
+            WriteNewString(exeDataBoot, patchPortStringOffset, patchPortString, freeSpaceOffset);
+            Console.WriteLine("Writing \"{0}\" and updating offset to 0x{1:X}.", patchUrlString, freeSpaceOffset + 0x20);
+            WriteNewString(exeDataBoot, patchUrlStringOffset, patchUrlString, freeSpaceOffset + 0x20);
+
+            Console.WriteLine("---Editing FFXIVLOGIN.EXE---");
+            loginUrlOffset = PrintEncodedSearch(exeDataLogin, 0x739, ORIGINAL_PATCH_LOGIN_STRING);
+            freeSpaceInLoginOffset = PrintFreeSpaceSearch(exeDataLogin);
+
+            if (loginUrlOffset == -1 || freeSpaceInLoginOffset == -1)
+            {
+                Console.WriteLine("There was an error finding the address locations...");
+                Console.ReadKey();
+                return;
+            }
+
+            Console.WriteLine("Writing encoded \"{0}\" and updating offset to 0x{1:X}.", loginUrlString, freeSpaceInLoginOffset);
+            WriteNewStringEncoded(exeDataLogin, loginUrlOffset, 0x739, loginUrlString, freeSpaceInLoginOffset);
+
+            File.WriteAllBytes("C:\\Users\\Filip\\Desktop\\ffxivboot.exe", exeDataBoot);
+            File.WriteAllBytes("C:\\Users\\Filip\\Desktop\\ffxivlogin.exe", exeDataLogin);
+
+            Console.WriteLine("Done! New .EXEs created in the same folder as this application. Make sure to backup your originals!");
+            Console.WriteLine("Press any key to exit...");
+            Console.ReadKey();
+
+        }
+
+        public static void WriteNewString(byte[] exeData, long offsetLocation, string newString, long freeSpaceLocation)
+        {
+            using (MemoryStream memStream = new MemoryStream(exeData))
+            {
+                using (BinaryWriter binaryWriter = new BinaryWriter(memStream))
+                {
+                    binaryWriter.BaseStream.Seek(offsetLocation, SeekOrigin.Begin);
+                    binaryWriter.Write((uint)freeSpaceLocation + 0x400000);
+                    binaryWriter.BaseStream.Seek(freeSpaceLocation, SeekOrigin.Begin);
+                    binaryWriter.Write(Encoding.ASCII.GetBytes(newString), 0, Encoding.ASCII.GetByteCount(newString) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(newString));
+                }
+            }
+        }
+
+        public static void WriteNewStringEncoded(byte[] exeData, long offsetLocation, uint key, string newString, long freeSpaceLocation)
+        {
+            byte[] encodedString = FFXIVLoginStringEncode(key, newString);
+            using (MemoryStream memStream = new MemoryStream(exeData))
+            {
+                using (BinaryWriter binaryWriter = new BinaryWriter(memStream))
+                {
+                    //binaryWriter.BaseStream.Seek(offsetLocation, SeekOrigin.Begin);
+                    //binaryWriter.Write((uint)freeSpaceLocation + 0x400000);
+                    binaryWriter.BaseStream.Seek(offsetLocation, SeekOrigin.Begin);
+                    binaryWriter.Write(encodedString);
+                }
+            }
+        }
+
+        public static long PrintSearch(byte[] exeData, string searchString)
+        {
+            Console.Write("Searching for string \"{0}\"...", searchString);
+            long offset = SearchForStringOffset(exeData, searchString);
+
+            if (offset != -1)
+                Console.WriteLine(" FOUND @ 0x{0:X}!", offset);
+            else
+            {
+                Console.WriteLine(" ERROR, could not find string.");                
+            }
+
+            return offset;
+        }
+
+        public static long PrintEncodedSearch(byte[] exeData, uint key, string searchString)
+        {
+            Console.Write("Searching for encoded string \"{0}\"...", searchString);
+            long offset = SearchForEncodedStringOffset(exeData, key, searchString);
+
+            if (offset != -1)
+                Console.WriteLine(" FOUND @ 0x{0:X}!", offset);
+            else
+            {
+                Console.WriteLine(" ERROR, could not find string.");
+            }
+
+            return offset;
+        }
+
+        public static long PrintFreeSpaceSearch(byte[] exeData)
+        {
+            Console.Write("Searching for free space...");
+            long freeSpaceOffset = SearchForFreeSpace(exeData);
+            if (freeSpaceOffset != -1)
+                Console.WriteLine(" FOUND @ 0x{0:X}!", freeSpaceOffset);
+            else
+            {
+                Console.WriteLine(" ERROR, could not find free space.");
+            }
+
+            return freeSpaceOffset;
+        }
+
+        public static bool EditOffset(long offset, uint value)
+        {
+            return true;
+        }
+
+        public static long SearchForFreeSpace(byte[] exeData)
+        {
+            using (MemoryStream memStream = new MemoryStream(exeData))
+            {
+                using (BinaryReader binReader = new BinaryReader(memStream))
+                {
+                    //Find the .data section header
+                    long textSectionOffset = -1;
+                    int strCheckoffset = 0;
+                    while (binReader.BaseStream.Position + 4 < binReader.BaseStream.Length)
+                    {
+                        if (binReader.ReadByte() == ".text"[strCheckoffset])
+                        {
+                            if (strCheckoffset == 0)
+                                textSectionOffset = binReader.BaseStream.Position - 1;
+
+                            strCheckoffset++;
+                            if (strCheckoffset == Encoding.ASCII.GetByteCount(".data"))
+                                break;
+                        }
+                        else
+                        {
+                            strCheckoffset = 0;
+                            textSectionOffset = -1;
+                        }
+                    }
+
+                    //Read in the position and size
+                    binReader.BaseStream.Seek(textSectionOffset, SeekOrigin.Begin);
+                    binReader.ReadUInt64();
+                    uint virtualSize = binReader.ReadUInt32();
+                    uint address = binReader.ReadUInt32();
+                    uint sizeOfRawData = binReader.ReadUInt32();
+
+                    if (sizeOfRawData - virtualSize < 0x50)
+                        return -1;
+
+                    //Find a spot
+                    binReader.BaseStream.Seek(address + sizeOfRawData, SeekOrigin.Begin);
+                    while (binReader.BaseStream.Position >= address + virtualSize)
+                    {                        
+                        binReader.BaseStream.Seek(-0x50, SeekOrigin.Current);
+                        long newPosition = binReader.BaseStream.Position;
+
+                        bool foundNotZero = false;
+                        for (int i = 0; i < 0x50; i++)
+                        {
+                            if (binReader.ReadByte() != 0)
+                            {
+                                foundNotZero = true;
+                                break;
+                            }
+                        }
+
+                        if (!foundNotZero)                        
+                            return newPosition;                        
+                        else
+                            binReader.BaseStream.Seek(newPosition, SeekOrigin.Begin);
+                    }
+                }
+            }
+
+            return -1;
+        }
+
+        public static long SearchForStringOffset(byte[] exeData, string testString)
+        {
+            testString += "\0";
+
+            using (MemoryStream memStream = new MemoryStream(exeData))
+            {
+                using (BinaryReader binReader = new BinaryReader(memStream))
+                {
+                    long strOffset = -1;
+                    int strCheckoffset = 0;
+                    while (binReader.BaseStream.Position + 4 < binReader.BaseStream.Length)
+                    {
+                        if (binReader.ReadByte() == testString[strCheckoffset])
+                        {
+                            if (strCheckoffset == 0)
+                                strOffset = binReader.BaseStream.Position-1;
+
+                            strCheckoffset++;
+                            if (strCheckoffset == Encoding.ASCII.GetByteCount(testString))
+                                break;
+                        }
+                        else
+                        {
+                            strCheckoffset = 0;
+                            strOffset = -1;
+                        }
+                    }                    
+
+                    if (strOffset != -1)
+                    {
+                        strOffset += 0x400000;
+
+                        binReader.BaseStream.Seek(0, SeekOrigin.Begin);
+
+                        while (binReader.BaseStream.Position + 4 < binReader.BaseStream.Length)
+                        {
+                            if (binReader.ReadUInt32() == strOffset)
+                                return binReader.BaseStream.Position - 0x4;
+                        }
+
+                        return -1;
+                    }
+                    else
+                        return -1;
+                }
+            }
+        }
+
+        public static long SearchForEncodedStringOffset(byte[] exeData, uint testKey, string testString)
+        {
+            byte[] encoded = FFXIVLoginStringEncode(testKey, testString);
+
+            using (MemoryStream memStream = new MemoryStream(exeData))
+            {
+                using (BinaryReader binReader = new BinaryReader(memStream))
+                {
+                    long strOffset = -1;
+                    int strCheckoffset = 0;
+                    while (binReader.BaseStream.Position + 4 < binReader.BaseStream.Length)
+                    {
+                        if (binReader.ReadByte() == encoded[strCheckoffset])
+                        {
+                            if (strCheckoffset == 0)
+                                strOffset = binReader.BaseStream.Position - 1;
+
+                            strCheckoffset++;
+                            if (strCheckoffset == encoded.Length)
+                                break;
+                        }
+                        else
+                        {
+                            strCheckoffset = 0;
+                            strOffset = -1;
+                        }
+                    }
+
+                    return strOffset;
+                }
+            }
+        }
+
+        public static string FFXIVLoginStringDecodeBinary(string path)
+        {
+            Console.OutputEncoding = System.Text.Encoding.UTF8;
+            byte[] data = File.ReadAllBytes(path);
+            //int offset = 0x5405a;
+            //int offset = 0x5425d;
+            int offset = 0x53ea0;
+            while (true)
+            {
+                string result = "";
+                uint key = (uint)data[offset + 0] << 8 | data[offset + 1];
+                uint key2 = data[offset + 2];
+                key = RotateRight(key, 1) & 0xFFFF;
+                key -= 0x22AF;
+                key &= 0xFFFF;
+                key2 = key2 ^ key;
+                key = RotateRight(key, 1) & 0xFFFF;
+                key -= 0x22AF;
+                key &= 0xFFFF;
+                uint finalKey = key;
+                key = data[offset + 3];
+                uint count = (key2 & 0xFF) << 8;
+                key = key ^ finalKey;
+                key &= 0xFF;
+                count |= key;
+
+                int count2 = 0;
+                while (count != 0)
+                {
+                    uint encrypted = data[offset + 4 + count2];
+                    finalKey = RotateRight(finalKey, 1) & 0xFFFF;
+                    finalKey -= 0x22AF;
+                    finalKey &= 0xFFFF;
+                    encrypted = encrypted ^ (finalKey & 0xFF);
+
+                    result += (char)encrypted;
+                    count--;
+                    count2++;
+                }
+
+                return result;
+                //offset += 4 + count2;
+            }
+        }
+
+        public static string FFXIVLoginStringDecode(byte[] data)
+        {
+            Console.OutputEncoding = System.Text.Encoding.UTF8;
+            while (true)
+            {
+                string result = "";
+                uint key = (uint)data[0] << 8 | data[1];
+                uint key2 = data[2];
+                key = RotateRight(key, 1) & 0xFFFF;
+                key -= 0x22AF;
+                key &= 0xFFFF;
+                key2 = key2 ^ key;
+                key = RotateRight(key, 1) & 0xFFFF;
+                key -= 0x22AF;
+                key &= 0xFFFF;
+                uint finalKey = key;
+                key = data[3];
+                uint count = (key2 & 0xFF) << 8;
+                key = key ^ finalKey;
+                key &= 0xFF;
+                count |= key;
+
+                int count2 = 0;
+                while (count != 0)
+                {
+                    uint encrypted = data[4 + count2];
+                    finalKey = RotateRight(finalKey, 1) & 0xFFFF;
+                    finalKey -= 0x22AF;
+                    finalKey &= 0xFFFF;
+                    encrypted = encrypted ^ (finalKey & 0xFF);
+
+                    result += (char)encrypted;
+                    count--;
+                    count2++;
+                }
+
+                return result;
+                //offset += 4 + count2;
+            }
+        }
+
+        public static byte[] FFXIVLoginStringEncode(uint key, string text)
+        {
+            key = key & 0xFFFF;
+
+            uint count = 0;
+            byte[] asciiBytes = Encoding.ASCII.GetBytes(text);
+            byte[] result = new byte[4 + text.Length];
+            for (count = 0; count < text.Length; count++)
+            {
+                result[result.Length - count - 1] = (byte)(asciiBytes[asciiBytes.Length - count - 1] ^ (key & 0xFF));
+                key += 0x22AF;
+                key &= 0xFFFF;
+                key = RotateLeft(key, 1);
+                key &= 0xFFFF;
+            }
+
+            count = count ^ key;
+            result[3] = (byte)(count & 0xFF);
+
+            key += 0x22AF;
+            key &= 0xFFFF;
+            key = RotateLeft(key, 1); 
+            key &= 0xFFFF;
+
+            result[2] = (byte)(key & 0xFF);
+
+            key += 0x22AF;
+            key &= 0xFFFF;
+            key = RotateLeft(key, 1);
+            key &= 0xFFFF;
+
+            result[1] = (byte)(key & 0xFF);
+            result[0] = (byte)((key >> 8) & 0xFF);
+
+            return result;
+        }
+
+        public static uint RotateLeft(uint value, int bits)
+        {
+            return (value << bits) | (value >> (16 - bits));
+        }
+
+        public static uint RotateRight(uint value, int bits)
+        {
+            return (value >> bits) | (value << (16 - bits));
+        }
+
+    }
+}
diff --git a/Launcher Editor/Properties/AssemblyInfo.cs b/Launcher Editor/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..bed36e48
--- /dev/null
+++ b/Launcher Editor/Properties/AssemblyInfo.cs	
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Launcher Editor")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Launcher Editor")]
+[assembly: AssemblyCopyright("Copyright ©  2017")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("0ffa9d2f-41c6-443c-99b7-665702cf548f")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]