diff --git a/Tibia IP Changer.sln b/Tibia IP Changer.sln
new file mode 100644
index 0000000..13e36d1
--- /dev/null
+++ b/Tibia IP Changer.sln
@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 14
+VisualStudioVersion = 14.0.25420.1
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tibia IP Changer", "Tibia IP Changer\Tibia IP Changer.csproj", "{8500F172-B5EF-4B06-90B0-CCA0CD101F5C}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {8500F172-B5EF-4B06-90B0-CCA0CD101F5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8500F172-B5EF-4B06-90B0-CCA0CD101F5C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8500F172-B5EF-4B06-90B0-CCA0CD101F5C}.Debug|x86.ActiveCfg = Debug|x86
+ {8500F172-B5EF-4B06-90B0-CCA0CD101F5C}.Debug|x86.Build.0 = Debug|x86
+ {8500F172-B5EF-4B06-90B0-CCA0CD101F5C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8500F172-B5EF-4B06-90B0-CCA0CD101F5C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8500F172-B5EF-4B06-90B0-CCA0CD101F5C}.Release|x86.ActiveCfg = Release|x86
+ {8500F172-B5EF-4B06-90B0-CCA0CD101F5C}.Release|x86.Build.0 = Release|x86
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/Tibia IP Changer/App.xaml b/Tibia IP Changer/App.xaml
new file mode 100644
index 0000000..683611e
--- /dev/null
+++ b/Tibia IP Changer/App.xaml
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/Tibia IP Changer/App.xaml.cs b/Tibia IP Changer/App.xaml.cs
new file mode 100644
index 0000000..0687488
--- /dev/null
+++ b/Tibia IP Changer/App.xaml.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Data;
+using System.Linq;
+using System.Windows;
+
+namespace Tibia_IP_Changer
+{
+ ///
+ /// Interaction logic for App.xaml
+ ///
+ public partial class App : Application
+ {
+ }
+}
diff --git a/Tibia IP Changer/MainWindow.xaml b/Tibia IP Changer/MainWindow.xaml
new file mode 100644
index 0000000..04af056
--- /dev/null
+++ b/Tibia IP Changer/MainWindow.xaml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Tibia IP Changer/MainWindow.xaml.cs b/Tibia IP Changer/MainWindow.xaml.cs
new file mode 100644
index 0000000..457c64f
--- /dev/null
+++ b/Tibia IP Changer/MainWindow.xaml.cs
@@ -0,0 +1,217 @@
+using System;
+using System.Diagnostics;
+using System.Net;
+using System.Threading;
+using System.Windows;
+using Tibia.Utilities;
+
+namespace Tibia
+{
+ ///
+ /// Interaction logic for MainWindow.xaml
+ ///
+ public partial class MainWindow : Window
+ {
+ public MainWindow()
+ {
+ InitializeComponent();
+
+ uxClientPath.Text = Constants.DefaultClientPath;
+ }
+
+ private void uxBrowse_Click(object sender, RoutedEventArgs e)
+ {
+ var openFileDialog = new System.Windows.Forms.OpenFileDialog() { Filter = "Tibia Client (*.exe)|*.exe" };
+ openFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86);
+
+ if (openFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
+ {
+ uxClientPath.Text = openFileDialog.FileName;
+ }
+ }
+
+ private void uxApply_Click(object sender, RoutedEventArgs e)
+ {
+ try
+ {
+ if (uxClientPath.Text == string.Empty || !uxClientPath.Text.Contains(".exe"))
+ {
+ MessageBox.Show("Client path is not valid.");
+ return;
+ }
+
+ if (uxIP.Text.Equals(string.Empty))
+ {
+ MessageBox.Show("IP is not valid.");
+ return;
+ }
+
+ ushort port;
+ if (uxPort.Text.Equals(string.Empty) || !ushort.TryParse(uxPort.Text, out port))
+ {
+ MessageBox.Show("Port is not valid.");
+ return;
+ }
+
+ Environment.CurrentDirectory = uxClientPath.Text.Replace("Tibia.exe", "");
+ Process process = Process.Start(uxClientPath.Text);
+
+ process.WaitForInputIdle();
+ while (process.MainWindowHandle == IntPtr.Zero)
+ {
+ process.Refresh();
+ Thread.Sleep(5);
+ }
+
+ var version = FileVersionInfo.GetVersionInfo(uxClientPath.Text).FileVersion;
+ if (version == "1, 0, 0, 1")
+ {
+ version = "7.0.0";
+ }
+
+ var versionNumber = int.Parse(version.Replace(".", ""));
+ var baseAddress = (uint)process.MainModule.BaseAddress.ToInt32();
+ var processHandle = WinAPI.OpenProcess((WinAPI.PROCESS_VM_READ | WinAPI.PROCESS_VM_WRITE | WinAPI.PROCESS_VM_OPERATION), 0, (uint)process.Id);
+ var buffer = Memory.ReadBytes(processHandle, baseAddress, (uint)process.MainModule.ModuleMemorySize);
+
+ uint loginServerStart = 0;
+ if (versionNumber >= 10110)
+ {
+ loginServerStart = Memory.ScanBytes(buffer, Constants.LoginServerArrayCurrent) + baseAddress;
+ loginServerStart = Memory.ReadUInt32(processHandle, loginServerStart - Constants.LoginServerStartOffsetCurrent) - baseAddress;
+ }
+ else if (versionNumber >= 800)
+ {
+ loginServerStart = Memory.ScanBytes(buffer, Constants.LoginServerArrayPre10110) + baseAddress;
+ loginServerStart = Memory.ReadUInt32(processHandle, loginServerStart + Constants.LoginServerStartOffsetPre10110) - baseAddress;
+ }
+ else
+ {
+ loginServerStart = Memory.ScanBytes(buffer, Constants.LoginServerArrayPre8000) + baseAddress;
+ loginServerStart = Memory.ReadUInt32(processHandle, loginServerStart + Constants.LoginServerStartOffsetPre8000) - baseAddress;
+ }
+
+ uint loginServerEnd = 0;
+ uint loginServerStep = 0;
+ uint loginServerHostnamePtrOffset = 0;
+ uint loginServerIpPtrOffset = 0;
+ uint loginServerPortOffset = 0;
+ uint loginServerCount = 0;
+ if (versionNumber >= 10500)
+ {
+ loginServerEnd = loginServerStart + 0x04;
+ loginServerStep = 0x30;
+ loginServerHostnamePtrOffset = 0x04;
+ loginServerIpPtrOffset = 0x1C;
+ loginServerPortOffset = 0x28;
+ }
+ else if (versionNumber >= 10110)
+ {
+ loginServerEnd = loginServerStart + 0x04;
+ loginServerStep = 0x38;
+ loginServerHostnamePtrOffset = 0x04;
+ loginServerIpPtrOffset = 0x20;
+ loginServerPortOffset = 0x30;
+ loginServerCount = 0x0A;
+ }
+ else if (versionNumber >= 800)
+ {
+ loginServerStep = 0x70;
+ loginServerPortOffset = 0x64;
+ loginServerCount = 0x0A;
+ }
+ else
+ {
+ loginServerStep = 0x70;
+ loginServerPortOffset = 0x64;
+ loginServerCount = 0x04;
+ }
+
+ uint rsaKey = 0;
+ if (versionNumber >= 861)
+ {
+ rsaKey = Memory.ScanString(buffer, Constants.RsaKeyCurrent);
+ }
+ else if (versionNumber >= 772)
+ {
+ rsaKey = Memory.ScanString(buffer, Constants.RsaKeyOld);
+ }
+
+ process.Kill();
+
+ var pi = new WinAPI.PROCESS_INFORMATION();
+ var si = new WinAPI.STARTUPINFO();
+
+ if (!WinAPI.CreateProcess(uxClientPath.Text, " ", IntPtr.Zero, IntPtr.Zero, false, WinAPI.CREATE_SUSPENDED, IntPtr.Zero, System.IO.Path.GetDirectoryName(uxClientPath.Text), ref si, out pi))
+ {
+ return;
+ }
+
+ processHandle = pi.hProcess;
+ process = Process.GetProcessById(Convert.ToInt32(pi.dwProcessId));
+ baseAddress = (uint)WinAPI.GetBaseAddress(processHandle).ToInt32();
+
+ WinAPI.ResumeThread(pi.hThread);
+ process.WaitForInputIdle();
+ WinAPI.CloseHandle(pi.hThread);
+
+ while (process.MainWindowHandle == IntPtr.Zero)
+ {
+ process.Refresh();
+ Thread.Sleep(5);
+ }
+
+ var resolvedIp = uxIP.Text;
+ IPAddress ipa;
+ if (!IPAddress.TryParse(uxIP.Text, out ipa))
+ {
+ IPAddress[] addressList = Dns.GetHostEntry(uxIP.Text).AddressList;
+
+ if (addressList.Length > 0)
+ {
+ resolvedIp = addressList[0].ToString();
+ }
+ }
+
+ if (versionNumber >= 10110)
+ {
+ uint loginStart = Memory.ReadUInt32(processHandle, loginServerStart + baseAddress);
+ uint loginEnd = Memory.ReadUInt32(processHandle, loginServerEnd + baseAddress);
+
+ for (uint loginServer = loginStart; loginServer < loginEnd; loginServer += loginServerStep)
+ {
+ uint ipAddress = Memory.ReadUInt32(processHandle, loginServer + loginServerIpPtrOffset);
+ Memory.WriteInt32(processHandle, ipAddress, 0);
+
+ uint hostAddress = Memory.ReadUInt32(processHandle, loginServer + loginServerHostnamePtrOffset);
+ Memory.WriteString(processHandle, hostAddress, resolvedIp);
+
+ uint portAddress = loginServer + loginServerPortOffset;
+ var portValue = BitConverter.ToUInt16(Memory.ReadBytes(processHandle, portAddress, 2), 0);
+ Memory.WriteUInt16(processHandle, portAddress, port);
+ }
+ }
+ else
+ {
+ uint loginServer = loginServerStart + baseAddress;
+
+ for (int i = 0; i < loginServerCount; ++i)
+ {
+ Memory.WriteString(processHandle, loginServer, resolvedIp);
+ Memory.WriteUInt16(processHandle, loginServer + loginServerPortOffset, port);
+ loginServer += loginServerStep;
+ }
+ }
+
+ if (versionNumber >= 772)
+ {
+ Memory.WriteRsa(processHandle, (rsaKey + baseAddress), Constants.RsaKeyOpenTibia);
+ }
+ }
+ catch (Exception ex)
+ {
+ throw ex;
+ }
+ }
+ }
+}
diff --git a/Tibia IP Changer/Properties/AssemblyInfo.cs b/Tibia IP Changer/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..7d1f0fb
--- /dev/null
+++ b/Tibia IP Changer/Properties/AssemblyInfo.cs
@@ -0,0 +1,55 @@
+using System.Reflection;
+using System.Resources;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Windows;
+
+// 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("Tibia IP Changer")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Tibia IP Changer")]
+[assembly: AssemblyCopyright("Copyright © 2016")]
+[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)]
+
+//In order to begin building localizable applications, set
+//CultureYouAreCodingWith in your .csproj file
+//inside a . For example, if you are using US english
+//in your source files, set the to en-US. Then uncomment
+//the NeutralResourceLanguage attribute below. Update the "en-US" in
+//the line below to match the UICulture setting in the project file.
+
+//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
+
+
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
+
+
+// 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")]
diff --git a/Tibia IP Changer/Properties/Resources.Designer.cs b/Tibia IP Changer/Properties/Resources.Designer.cs
new file mode 100644
index 0000000..1f5f882
--- /dev/null
+++ b/Tibia IP Changer/Properties/Resources.Designer.cs
@@ -0,0 +1,63 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace Tibia.Properties {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Tibia.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff --git a/Tibia IP Changer/Properties/Resources.resx b/Tibia IP Changer/Properties/Resources.resx
new file mode 100644
index 0000000..af7dbeb
--- /dev/null
+++ b/Tibia IP Changer/Properties/Resources.resx
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/Tibia IP Changer/Properties/Settings.Designer.cs b/Tibia IP Changer/Properties/Settings.Designer.cs
new file mode 100644
index 0000000..7aaea78
--- /dev/null
+++ b/Tibia IP Changer/Properties/Settings.Designer.cs
@@ -0,0 +1,26 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace Tibia.Properties {
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default {
+ get {
+ return defaultInstance;
+ }
+ }
+ }
+}
diff --git a/Tibia IP Changer/Properties/Settings.settings b/Tibia IP Changer/Properties/Settings.settings
new file mode 100644
index 0000000..033d7a5
--- /dev/null
+++ b/Tibia IP Changer/Properties/Settings.settings
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Tibia IP Changer/Tibia IP Changer.csproj b/Tibia IP Changer/Tibia IP Changer.csproj
new file mode 100644
index 0000000..55b954e
--- /dev/null
+++ b/Tibia IP Changer/Tibia IP Changer.csproj
@@ -0,0 +1,124 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {8500F172-B5EF-4B06-90B0-CCA0CD101F5C}
+ WinExe
+ Properties
+ Tibia
+ Tibia IP Changer
+ v4.0
+ 512
+ {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ 4
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE
+ full
+ x86
+ prompt
+ MinimumRecommendedRules.ruleset
+
+
+ bin\x86\Release\
+ TRACE
+ true
+ pdbonly
+ x86
+ prompt
+ MinimumRecommendedRules.ruleset
+
+
+
+
+
+
+
+
+
+
+
+ 4.0
+
+
+
+
+
+
+
+ MSBuild:Compile
+ Designer
+
+
+
+
+
+ MSBuild:Compile
+ Designer
+
+
+ App.xaml
+ Code
+
+
+ MainWindow.xaml
+ Code
+
+
+
+
+ Code
+
+
+ True
+ True
+ Resources.resx
+
+
+ True
+ Settings.settings
+ True
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+
+
+ SettingsSingleFileGenerator
+ Settings.Designer.cs
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Tibia IP Changer/Utilities/Constants.cs b/Tibia IP Changer/Utilities/Constants.cs
new file mode 100644
index 0000000..2bd610e
--- /dev/null
+++ b/Tibia IP Changer/Utilities/Constants.cs
@@ -0,0 +1,21 @@
+using System;
+using System.IO;
+
+namespace Tibia.Utilities
+{
+ public static class Constants
+ {
+ public static string DefaultClientPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "Tibia\\Tibia.exe");
+
+ public const string RsaKeyOld = "124710459426827943004376449897985582167801707960697037164044904862948569380850421396904597686953877022394604239428185498284169068581802277612081027966724336319448537811441719076484340922854929273517308661370727105382899118999403808045846444647284499123164879035103627004668521005328367415259939915284902061793";
+ public const string RsaKeyCurrent = "132127743205872284062295099082293384952776326496165507967876361843343953435544496682053323833394351797728954155097012103928360786959821132214473291575712138800495033169914814069637740318278150290733684032524174782740134357629699062987023311132821016569775488792221429527047321331896351555606801473202394175817";
+ public const string RsaKeyOpenTibia = "109120132967399429278860960508995541528237502902798129123468757937266291492576446330739696001110603907230888610072655818825358503429057592827629436413108566029093628212635953836686562675849720620786279431090218017681061521755056710823876476444260558147179707119674283982419152118103759076030616683978566631413";
+
+ public static byte[] LoginServerArrayPre8000 = new byte[5] { 0x57, 0x33, 0xC0, 0xB9, 0x70 };
+ public static byte[] LoginServerArrayPre10110 = new byte[5] { 0x6B, 0xF6, 0x70, 0x8D, 0x96 };
+ public static byte[] LoginServerArrayCurrent = new byte[12] { 0xB8, 0xAB, 0xAA, 0xAA, 0x2A, 0xF7, 0xEE, 0xBE, 0x55, 0x55, 0x55, 0x05 };
+ public static byte LoginServerStartOffsetPre8000 = 0x09;
+ public static byte LoginServerStartOffsetPre10110 = 0x05;
+ public static byte LoginServerStartOffsetCurrent = 0x04;
+ }
+}
diff --git a/Tibia IP Changer/Utilities/Memory.cs b/Tibia IP Changer/Utilities/Memory.cs
new file mode 100644
index 0000000..308584a
--- /dev/null
+++ b/Tibia IP Changer/Utilities/Memory.cs
@@ -0,0 +1,96 @@
+using System;
+using System.Text;
+
+namespace Tibia.Utilities
+{
+ public static class Memory
+ {
+ public static uint ScanBytes(byte[] buffer, byte[] value)
+ {
+ var len = value.Length;
+ var end = buffer.Length - len;
+
+ for (int i = 0; i < end; ++i)
+ {
+ int j = 0;
+
+ for (; j < len && buffer[i + j] == value[j]; ++j) ;
+
+ if (j == len)
+ {
+ return (uint)i;
+ }
+ }
+
+ return 0;
+ }
+
+ public static uint ScanString(byte[] buffer, string value)
+ {
+ var bytes = Encoding.ASCII.GetBytes(value);
+ return ScanBytes(buffer, bytes);
+ }
+
+ public static byte[] ReadBytes(IntPtr processHandle, long address, uint bytesToRead)
+ {
+ IntPtr ptrBytesRead;
+ var buffer = new byte[bytesToRead];
+ WinAPI.ReadProcessMemory(processHandle, new IntPtr(address), buffer, bytesToRead, out ptrBytesRead);
+ return buffer;
+ }
+
+ public static uint ReadUInt32(IntPtr processHandle, long address)
+ {
+ return BitConverter.ToUInt32(ReadBytes(processHandle, address, 4), 0);
+ }
+
+ public static string ReadString(IntPtr processHandle, long address)
+ {
+ var s = string.Empty;
+ var temp = ReadBytes(processHandle, address++, 1)[0];
+ while (temp != 0)
+ {
+ s += (char)temp;
+ temp = ReadBytes(processHandle, address++, 1)[0];
+ }
+
+ return s;
+ }
+
+ public static bool WriteBytes(IntPtr processHandle, long address, byte[] bytes, uint length)
+ {
+ IntPtr bytesWritten;
+ var result = WinAPI.WriteProcessMemory(processHandle, new IntPtr(address), bytes, length, out bytesWritten);
+ return result != 0;
+ }
+
+ public static bool WriteUInt16(IntPtr processHandle, long address, ushort value)
+ {
+ return WriteBytes(processHandle, address, BitConverter.GetBytes(value), 2);
+ }
+
+ public static bool WriteInt32(IntPtr processHandle, long address, int value)
+ {
+ return WriteBytes(processHandle, address, BitConverter.GetBytes(value), 4);
+ }
+
+ public static bool WriteString(IntPtr processHandle, long address, string str)
+ {
+ str += "\0";
+ byte[] bytes = Encoding.ASCII.GetBytes(str);
+ return WriteBytes(processHandle, address, bytes, (uint)bytes.Length);
+ }
+
+ public static bool WriteRsa(IntPtr processHandle, long address, string value)
+ {
+ IntPtr bytesWritten;
+ WinAPI.MemoryProtection oldProtection = 0;
+ var enc = new ASCIIEncoding();
+ var bytes = enc.GetBytes(value);
+ WinAPI.VirtualProtectEx(processHandle, new IntPtr(address), new IntPtr(bytes.Length), WinAPI.MemoryProtection.ExecuteReadWrite, ref oldProtection);
+ var result = WinAPI.WriteProcessMemory(processHandle, new IntPtr(address), bytes, (uint)bytes.Length, out bytesWritten);
+ WinAPI.VirtualProtectEx(processHandle, new IntPtr(address), new IntPtr(bytes.Length), oldProtection, ref oldProtection);
+ return (result != 0);
+ }
+ }
+}
diff --git a/Tibia IP Changer/Utilities/WinAPI.cs b/Tibia IP Changer/Utilities/WinAPI.cs
new file mode 100644
index 0000000..c356db3
--- /dev/null
+++ b/Tibia IP Changer/Utilities/WinAPI.cs
@@ -0,0 +1,200 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace Tibia.Utilities
+{
+ public static class WinAPI
+ {
+ public const uint CREATE_SUSPENDED = 0x00000004;
+ public const uint PROCESS_VM_OPERATION = 0x0008;
+ public const uint PROCESS_VM_READ = 0x0010;
+ public const uint PROCESS_VM_WRITE = 0x0020;
+
+ [Flags]
+ public enum MemoryProtection
+ {
+ Execute = 0x10,
+ ExecuteRead = 0x20,
+ ExecuteReadWrite = 0x40,
+ ExecuteWriteCopy = 0x80,
+ NoAccess = 0x01,
+ ReadOnly = 0x02,
+ ReadWrite = 0x04,
+ WriteCopy = 0x08,
+ GuardModifierflag = 0x100,
+ NoCacheModifierflag = 0x200,
+ WriteCombineModifierflag = 0x400
+ }
+
+ public struct IMAGE_DOS_HEADER
+ {
+ public ushort e_magic;
+ public ushort e_cblp;
+ public ushort e_cp;
+ public ushort e_crlc;
+ public ushort e_cparhdr;
+ public ushort e_minalloc;
+ public ushort e_maxalloc;
+ public ushort e_ss;
+ public ushort e_sp;
+ public ushort e_csum;
+ public ushort e_ip;
+ public ushort e_cs;
+ public ushort e_lfarlc;
+ public ushort e_ovno;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
+ public ushort[] e_res1;
+ public ushort e_oemid;
+ public ushort e_oeminfo;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
+ public ushort[] e_res2;
+ public int e_lfanew;
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct IMAGE_FILE_HEADER
+ {
+ public ushort Machine;
+ public ushort NumberOfSections;
+ public uint TimeDateStamp;
+ public uint PointerToSymbolTable;
+ public uint NumberOfSymbols;
+ public ushort SizeOfOptionalHeader;
+ public ushort Characteristics;
+ }
+
+ public struct MEMORY_BASIC_INFORMATION
+ {
+ public IntPtr BaseAddress;
+ public IntPtr AllocationBase;
+ public uint AllocationProtect;
+ public IntPtr RegionSize;
+ public uint State;
+ public uint Protect;
+ public uint Type;
+ }
+
+ public struct PROCESS_INFORMATION
+ {
+ public IntPtr hProcess;
+ public IntPtr hThread;
+ public uint dwProcessId;
+ public uint dwThreadId;
+ }
+
+ public struct STARTUPINFO
+ {
+ public uint cb;
+ public string lpReserved;
+ public string lpDesktop;
+ public string lpTitle;
+ public uint dwX;
+ public uint dwY;
+ public uint dwXSize;
+ public uint dwYSize;
+ public uint dwXCountChars;
+ public uint dwYCountChars;
+ public uint dwFillAttribute;
+ public uint dwFlags;
+ public short wShowWindow;
+ public short cbReserved2;
+ public IntPtr lpReserved2;
+ public IntPtr hStdInput;
+ public IntPtr hStdOutput;
+ public IntPtr hStdError;
+ }
+
+ public struct SYSTEM_INFO
+ {
+ public ushort processorArchitecture;
+ private ushort reserved;
+ public uint dwPageSize;
+ public IntPtr lpMinimumApplicationAddress;
+ public IntPtr lpMaximumApplicationAddress;
+ public IntPtr dwActiveProcessorMask;
+ public uint dwNumberOfProcessors;
+ public uint dwProcessorType;
+ public uint dwAllocationGranularity;
+ public ushort dwProcessorLevel;
+ public ushort dwProcessorRevision;
+ }
+
+ [DllImport("kernel32.dll")]
+ public static extern int CloseHandle(IntPtr hObject);
+
+ [DllImport("kernel32.dll")]
+ public static extern bool CreateProcess(string imageName, string cmdLine, IntPtr lpProcessAttributes, IntPtr lpThreadAttributes, bool boolInheritHandles, uint dwCreationFlags, IntPtr lpEnvironment, string lpszCurrentDir, ref STARTUPINFO si, out PROCESS_INFORMATION pi);
+
+ [DllImport("user32.dll")]
+ public static extern int GetClassName(IntPtr hWnd, System.Text.StringBuilder className, int maxCharCount);
+
+ [DllImport("kernel32.dll")]
+ public static extern void GetSystemInfo([MarshalAs(UnmanagedType.Struct)] out SYSTEM_INFO lpSystemInfo);
+
+ [DllImport("kernel32.dll")]
+ public static extern IntPtr OpenProcess(uint dwDesiredAccess, int bInheritHandle, uint dwProcessId);
+
+ [DllImport("kernel32.dll")]
+ public static extern int ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [In, Out] byte[] buffer, uint size, out IntPtr lpNumberOfBytesRead);
+
+ [DllImport("kernel32.dll")]
+ public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, UIntPtr nSize, IntPtr lpNumberOfBytesRead);
+
+ [DllImport("kernel32.dll")]
+ public static extern uint ResumeThread(IntPtr hThread);
+
+ [DllImport("kernel32.dll")]
+ public static extern bool VirtualProtectEx(IntPtr hProcess, IntPtr lpAddress, IntPtr dwSize, MemoryProtection flNewProtect, ref MemoryProtection lpflOldProtect);
+
+ [DllImport("kernel32.dll")]
+ public static extern bool VirtualQueryEx(IntPtr hProcess, IntPtr lpAddress, out MEMORY_BASIC_INFORMATION lpBuffer, uint dwLength);
+
+ [DllImport("kernel32.dll")]
+ public static extern int WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [In, Out] byte[] buffer, uint size, out IntPtr lpNumberOfBytesWritten);
+
+ public static T ReadUnmanagedStructure(IntPtr hProcess, IntPtr lpAddr)
+ {
+ var array = new byte[Marshal.SizeOf(typeof(T))];
+ ReadProcessMemory(hProcess, lpAddr, array, new UIntPtr((uint)array.Length), IntPtr.Zero);
+ var gCHandle = GCHandle.Alloc(array, GCHandleType.Pinned);
+ var result = (T)((object)Marshal.PtrToStructure(gCHandle.AddrOfPinnedObject(), typeof(T)));
+ gCHandle.Free();
+ return result;
+ }
+
+ public static IntPtr GetBaseAddress(IntPtr hProcess)
+ {
+ SYSTEM_INFO sYSTEM_INFO;
+ GetSystemInfo(out sYSTEM_INFO);
+
+ var lpMinimumApplicationAddress = sYSTEM_INFO.lpMinimumApplicationAddress;
+ var mEMORY_BASIC_INFORMATION = default(MEMORY_BASIC_INFORMATION);
+ var dwLength = (uint)Marshal.SizeOf(mEMORY_BASIC_INFORMATION);
+
+ while (lpMinimumApplicationAddress.ToInt64() < sYSTEM_INFO.lpMaximumApplicationAddress.ToInt64())
+ {
+ if (!VirtualQueryEx(hProcess, lpMinimumApplicationAddress, out mEMORY_BASIC_INFORMATION, dwLength))
+ {
+ return IntPtr.Zero;
+ }
+
+ if (mEMORY_BASIC_INFORMATION.Type == 16777216u && mEMORY_BASIC_INFORMATION.BaseAddress == mEMORY_BASIC_INFORMATION.AllocationBase && (mEMORY_BASIC_INFORMATION.Protect & 256u) != 256u)
+ {
+ var iMAGE_DOS_HEADER = ReadUnmanagedStructure(hProcess, lpMinimumApplicationAddress);
+ if (iMAGE_DOS_HEADER.e_magic == 23117)
+ {
+ var lpAddr = new IntPtr(lpMinimumApplicationAddress.ToInt64() + (long)(iMAGE_DOS_HEADER.e_lfanew + 4));
+ if ((ReadUnmanagedStructure(hProcess, lpAddr).Characteristics & 2) == 2)
+ {
+ return lpMinimumApplicationAddress;
+ }
+ }
+ }
+
+ lpMinimumApplicationAddress = new IntPtr(mEMORY_BASIC_INFORMATION.BaseAddress.ToInt64() + mEMORY_BASIC_INFORMATION.RegionSize.ToInt64());
+ }
+
+ return lpMinimumApplicationAddress;
+ }
+ }
+}