Skocz do zawartości
  • 👋 Witaj na MPCForum!

    Przeglądasz forum jako gość, co oznacza, że wiele świetnych funkcji jest jeszcze przed Tobą! 😎

    • Pełny dostęp do działów i ukrytych treści
    • Możliwość pisania i odpowiadania w tematach
    • System prywatnych wiadomości
    • Zbieranie reputacji i rozwijanie swojego profilu
    • Członkostwo w jednej z największych społeczności graczy

    👉 Dołączenie zajmie Ci mniej niż minutę – a zyskasz znacznie więcej!

    Zarejestruj się teraz

Jak stworzyć własnego bota, C#


bleblable

Rekomendowane odpowiedzi

Opublikowano

MADE BY DAJBUZI [ [email protected] ]

 

Potrzebne narzędzia:
    - MS Visual Studio 2013 [ http://www.visualstudio.com/pl-pl/downloads/download-visual-studio-vs.aspx ]
    bądź inne IDE C# [ http://pl.wikipedia.org/wiki/Zintegrowane_%C5%9Brodowisko_programistyczne ]
    - Adresy pamięci [ można wyciągnąć z klienta bądź innego bota ]
    - http://google.pl/ oraz http://msdn.microsoft.com/pl-pl/library/618ayhy6.aspx
    - odrobina kreatywności, mózgu i cierpliwości.
    
NOTKA : Ten poradnik przeprowadzę korzystając z MSVS 2013 Express z uwagi na ogólnodostępność oraz to że niektóre funkcje w wersji PROFESSIONAL/ULTIMATE mogą nie być dostępne w wersji EXPRESS [darmowej].

1. Wprowadzenie do IDE [ MS Visual Studio 2013 ].

    Po zainstalowaniu i zarejestrowaniu produktu powinien przywitać nas ekran startowy, zawierający informacje o aktualizacjach naszego IDE oraz innych produktów z rodziny Microsoft'u.
Ekran ten podzielony jest na kilka sekcji, nas interesuje ta najbardziej wysunięta na lewo, gdzie klikamy przycisk "New Project...".
W nowym oknie wybieramy to co jest przedstawione na obrazku poniżej:
2130214171149871285262.png
Nadajemy nazwę dla naszego programu i solucji. Dla tego przykładu nadam mu nazwę "MPC_FORUM_BOT". Po kliknięciu przycisku "OK" nasze IDE przekształci się i naszym oczom uzaże się puste okienko stworzone w Windowsowym stylu.
To jest edytor wizualny naszego programu [w tym wypadku raczej bota], przy designie którego spędzimy [w kolejnych odsłonach poradnika] ładnych kilka[naście] godzin.
Na sam początek, stwórzmy sobię debugger dla naszego bota, abyśmy mogli sprawdzać różne informacje. Aby to zrobić najeżdzamy myszką na zakładkę "TOOLBOX" z lewej strony.
Wyskoczy nam panel boczny zawierający predefiniowane kontrolki windowsowe. Szukamy tam czegoś o nazwie "RICH TEXT BOX", przeciągamy do naszego okienka i rozciągamy na całą wysokość oraz szerokość okna.
1173514171149871285262.png
9429914171149871285262.png
Teraz nadamy tytuł naszemu okienku, aby to zrobić przechodzimy do panelu z prawej strony ["SULOTION EXPLORER"] i zaznaczamy "FORM1.CS". Następnie klikamy przycisk F2, nadajemy nową nazwę [ w moim przypadku "MPC_FORUM_BOT" ] a następnie potwierdzamy nasze zmiany.
Zaznaczamy nasz FORM1 [ okienko bota ], przechodzimy na prawą stronę [ okienko PROPERTIES ] i szukamy tam nazwy okienka [oznaczone jako TEXT]. Zmieniamy wartość z "Form1" na "MPC_FORUM_BOT". Nasze IDE powinno prezentować się tak:
4851714171149871285262.png
Teraz stworzymy sobię prosty system debugowania i wyszukiwania klienta gry. Aby to zrobić klikamy prawym przyciskiem myszki w środku okna "SOLUTION EXPLORER", wybieramy Add.. -> Class.. lub klikamy SHIFT+ALT+C. W nowym oknie wpisujemy nazwę klasy, dla tego przykładu użyję nazwy "MPC_DEBUG" i potwierdzamy.
Visual powinien nas przenieść do trybu edycji kodu źródłowego nowo powstałego pliku, który powinien wyglądać następująco:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MPC_FORUM_BOT
{
    class MPC_DEBUG
    {
    }
}

Pierwsze co potrzebujemy zrobić to usunąć wszystkie linie początkowe i zastąpić je "using System;" oraz "using System.Windows.Forms", następnie ustawiamy nasz obiekt na statyczny i publiczny: "public static class MPC_DEBUUG".
Nasz pliczek powinien teraz wyglądać tak:

using System;
using System.Windows.Forms;

namespace MPC_FORUM_BOT
{
    public static class MPC_DEBUG
    {
    }
}

Teraz w środku stworzymy sobie jedno pole, właściwość i dwie metody. Prywatne pole typu "RichTextBox" o nazwie m_logSpace, właściwość typu "RichTextBox" o nazwie LogSpace z publicznym odczytem i prywatnym zapisem, metodę bezzwrotną o nazwię Log, która przyjmie jeden parametr typu "string" o nazwie msg oraz metodę bezzwrotną o nazwie "SetLogSpace" z jednym parametrem typu "RichTextBox" o nazwie lSpace.
Metodę "Log(string msg)" uzupełniamy dodając jedną linijkę:

m_logSpace.Text += DateTime.Now + msg + "\n";

Metodę "SetLogSpace(RichTextBox lSpace)" usupełniamy dodając:

m_logSpace = lSpace;

Nasz obiekt powinien wyglądać tak:

using System;
using System.Windows.Forms;

namespace MPC_FORUM_BOT
{
    public static class MPC_DEBUG
    {
        private static RichTextBox m_logSpace;
        public static RichTextBox LogSpace
        {
            get { return m_logSpace; }
            private set { m_logSpace = value; }
        }

        public static void Log(string msg)
        {
            m_logSpace.Text += DateTime.Now + " :: " + msg + "\n";
        }
        
        public static void SetLogSpace(RichTextBox lSpace)
        {
            m_logSpace = lSpace;
        }
    }
}

Teraz zedytujemy obiekt "startowy"/"wejściowy".
Rozwijamy "MPC_FORUM_BOT.CS" i klikamy na "MPC_FORUM_BOT" [żółta/pomarańczowa ikonka], który powinien wyglądać tak:
2497514171149871285262.png
Poniżej "InitializeComponents();" dopisujemy "MPC_DEBUG.SetLogSpace(this.richTextBox1);". Następnie do nagłówka dodajemy "using System.Diagnostics;", pod linijką "MPC_DEBUG.SetLogSpace(this.richTextBox1);" dodajemy:

foreach (Process p in Process.GetProcessesByName("tibia"))
    MPC_DEBUG.Log(p.Id.ToString());

Klikamy CTRL+SHIFT+S [iDE może zlagować na chwilkę] a następnie F5. Jeżeli mamy otwartego klienta gry powinniśmy zobaczyć taki oto screen:
2907114171149871285262.png
Tutaj zakończymy część pierwszą poradnika, jeżeli zgubiłeś się gdziekolwiek, tutaj masz pełny kod źródłowy 2 plików:
"MPC_FORUM_BOT":

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace MPC_FORUM_BOT
{
    public partial class MPC_FORUM_BOT : Form
    {
        public MPC_FORUM_BOT()
        {
            InitializeComponent();
            MPC_DEBUG.SetLogSpace(this.richTextBox1);
            foreach (Process p in Process.GetProcessesByName("tibia"))
                MPC_DEBUG.Log(p.Id.ToString());
        }
    }
}

"MPC_DEBUG":

using System;
using System.Windows.Forms;

namespace MPC_FORUM_BOT
{
    public static class MPC_DEBUG
    {
        private static RichTextBox m_logSpace;
        public static RichTextBox LogSpace
        {
            get { return m_logSpace; }
            private set { m_logSpace = value; }
        }

        public static void Log(string msg)
        {
            m_logSpace.Text += DateTime.Now + " :: " + msg + "\n";
        }

        public static void SetLogSpace(RichTextBox lSpace)
        {
            m_logSpace = lSpace;
        }
    }
}

2. Podpięcie do processu

    W poprzedniej części przygotowaliśmy sobie "DEBUGGER" dla naszego bota i wylistowaliśmy wszystkie otwarte klienty gry, teraz podepniemy się pod proces.
Aby to zrobić potrzebujemy zmodyfikować wygląd naszego bota, dodając ListBox oraz dwa razy Button.
Nasz bot powinien wyglądać następująco:
4634114171149881285262.png
Klikamy dwa razy na "Button1", Visual powinien przenieść nas do nowo powstałej metody [eventa] gdzie możemy wpisać co chcemy zrobić gdy ten przycisk zostanie naciśnięty.
Narazie nie mamy co tam wpisywać więc pominiemy ten krok i zrobimy to samo z przyciskiem "Button2".
Powinniśmy mieć dwie [prawie identyczne metody], które zostaną wykonane w momencie kliknięcia odpowiedniego przycisku.
Jeżeli tak to tworzymy nowy obiekt [sHIFT+ALT+C] i nadajemy mu nazwę "MPC_CLIENT_INJECT". Odrazu zmieniamy dostęp do naszego obiektu na publiczny, a następnie tworzymy trzy pola, trzy właściwości oraz konstruktor:

public class MPC_CLIENT_INJECT
{
    private IntPtr m_cHandle;
    private IntPtr m_baseAddress;
    private IntPtr m_cHWND;

    public IntPtr cHandle { get { return m_cHandle; } }
    public IntPtr baseAddress { get { return m_baseAddress; } }
    public IntPtr cHWND { get { return m_cHWND; } }

    public MPC_CLIENT_INJECT(Process proc)
    {
        this.m_cHandle = proc.Handle;
        this.m_baseAddress = proc.MainModule.BaseAddress;
        this.m_cHWND = proc.MainWindowHandle;
    }
}

Teraz przejdźmy do głównego obiektu [MPC_FORUM_BOT] i dodajmy tam nowe pole typu MPC_CLIENT_INJECT o nazwie m_client.

MPC_CLIENT_INJECT m_client;

Teraz wycinamy kod znajdujący się pod "MPC_DEBUG.SetLogSpace(this.richTextBox1);" i wklejamy go do miejsca naszego pierwszego przycisku.
Następnie modyfikujemy go:

private void button1_Click(object sender, EventArgs e)
{
    listBox1.Items.Clear();
    foreach (Process p in Process.GetProcessesByName("tibia"))
    {
        listBox1.Items.Add(p.MainWindowTitle);
    }
}

Przejdźmy teraz do drugiego przycisku gdzie wklejamy ten kod:

private void button2_Click(object sender, EventArgs e)
{
    if (listBox1.SelectedIndex < 0 && listBox1.SelectedIndex >= Process.GetProcessesByName("tibia").Length)
        return;

    m_client = new MPC_CLIENT_INJECT(Process.GetProcessesByName("tibia")[listBox1.SelectedIndex]);
    MPC_DEBUG.Log("Injected into :: " + m_client.cHandle.ToString());
}

Jeżeli zrobiłeś wszystko poprawnie to plik MPC_FORUM_BOT powinien wyglądać tak:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace MPC_FORUM_BOT
{
    public partial class MPC_FORUM_BOT : Form
    {
        MPC_CLIENT_INJECT m_client;

        public MPC_FORUM_BOT()
        {
            InitializeComponent();
            MPC_DEBUG.SetLogSpace(this.richTextBox1);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            listBox1.Items.Clear();
            foreach (Process p in Process.GetProcessesByName("tibia"))
            {
                listBox1.Items.Add(p.MainWindowTitle);
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            if (listBox1.SelectedIndex < 0 && listBox1.SelectedIndex >= Process.GetProcessesByName("tibia").Length)
                return;

            m_client = new MPC_CLIENT_INJECT(Process.GetProcessesByName("tibia")[listBox1.SelectedIndex]);
            MPC_DEBUG.Log("Injected into :: " + m_client.cHandle.ToString());
        }
    }
}

A plik MPC_CLIENT_INJECT tak:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MPC_FORUM_BOT
{
    public class MPC_CLIENT_INJECT
    {
        private IntPtr m_cHandle;
        private IntPtr m_baseAddress;
        private IntPtr m_cHWND;

        public IntPtr cHandle { get { return m_cHandle; } }
        public IntPtr baseAddress { get { return m_baseAddress; } }
        public IntPtr cHWND { get { return m_cHWND; } }

        public MPC_CLIENT_INJECT(Process proc)
        {
            this.m_cHandle = proc.Handle;
            this.m_baseAddress = proc.MainModule.BaseAddress;
            this.m_cHWND = proc.MainWindowHandle;
        }
    }
}

Klikamy SHIFT+CTRL+S [może być lekki lag] a następnie F5;
Klikamy przycisk odpowiedzialny za wywolanie metody:

private void button1_Click(object sender, EventArgs e)
{
    listBox1.Items.Clear();
    foreach (Process p in Process.GetProcessesByName("tibia"))
    {
        listBox1.Items.Add(p.MainWindowTitle);
    }
}

Następnie zaznaczamy klienta i klikamy na przysick odpowiedzialny za wywołanie :

private void button2_Click(object sender, EventArgs e)
{
    if (listBox1.SelectedIndex < 0 && listBox1.SelectedIndex >= Process.GetProcessesByName("tibia").Length)
        return;

    m_client = new MPC_CLIENT_INJECT(Process.GetProcessesByName("tibia")[listBox1.SelectedIndex]);
    MPC_DEBUG.Log("Injected into :: " + m_client.cHandle.ToString());
}

Jeżeli wszystko poszło w porządku powinniśmy otrzymać taki wynik:
4826814171149881285262.png
Gratulacje! Właśnie podpiąłeś swojego bota pod klienta gry!

Koniec części 2. Jeżeli zgubiłeś się w gdziekolwiek lub chcesz poprostu zobaczyć cały kod żródłowy to :
"MPC_CLIENT_INJECT"

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MPC_FORUM_BOT
{
    public class MPC_CLIENT_INJECT
    {
        private IntPtr m_cHandle;
        private IntPtr m_baseAddress;
        private IntPtr m_cHWND;

        public IntPtr cHandle { get { return m_cHandle; } }
        public IntPtr baseAddress { get { return m_baseAddress; } }
        public IntPtr cHWND { get { return m_cHWND; } }

        public MPC_CLIENT_INJECT(Process proc)
        {
            this.m_cHandle = proc.Handle;
            this.m_baseAddress = proc.MainModule.BaseAddress;
            this.m_cHWND = proc.MainWindowHandle;
        }
    }
}

MPC_FORUM_BOT
 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace MPC_FORUM_BOT
{
    public partial class MPC_FORUM_BOT : Form
    {
        MPC_CLIENT_INJECT m_client;

        public MPC_FORUM_BOT()
        {
            InitializeComponent();
            MPC_DEBUG.SetLogSpace(this.richTextBox1);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            listBox1.Items.Clear();
            foreach (Process p in Process.GetProcessesByName("tibia"))
            {
                listBox1.Items.Add(p.MainWindowTitle);
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            if (listBox1.SelectedIndex < 0 && listBox1.SelectedIndex >= Process.GetProcessesByName("tibia").Length)
                return;

            m_client = new MPC_CLIENT_INJECT(Process.GetProcessesByName("tibia")[listBox1.SelectedIndex]);
            MPC_DEBUG.Log("Injected into :: " + m_client.cHandle.ToString());
        }
    }
}

3. Odczyt punktów życia i many

Tworzymy nowy obiekt [klasę] o nazwię MPC_ADDRESSES i usuwamy z niej wszystko poza "namespace MPC_FORUM_BOT". Tworzymy wewnątrz namespace'a enum o nazwie ADDRESSES typu int:

namespace MPC_FORUM_BOT
{
    public enum ADDRESSES : int
    {
        XOR                              = 0x432BB0,
        MANA_POINTS                      = 0x432C04,
        MAX_MANA_POINTS                   = XOR + 0x4,
        HEALTH_POINTS                    = 0x5CF000,
        MAX_HEALTH_POINTS                = 0x5CF02C
    }
}

Zapisujemy i tworzymy kolejny obiekt o nazwie MPC_MEMORY_READER. W nagłówku tego obiektu dopisujemy "using System.Runtime.InteropServices;" [potrzebne by zaimplementować bibliotekę "krenel32"].
Następnie zmieniamy accessor na publiczny i wklejamy do naszego obiektu ten kodzik:

[DllImport("kernel32.dll")]
private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, int dwSize, ref int lpNumberOfBytesRead);

private byte[] ReadBytes(IntPtr pHandle, IntPtr address, int bytesToRead)
{
    int bytesRead = 0;
    byte[] buffer = new byte[bytesToRead];
    ReadProcessMemory(pHandle, address, buffer, bytesToRead, ref bytesRead);
    return buffer;
}

Od teraz możemy odczytywać bajty zapisane w pamięci operacyjnej. My narazie skupiamy się na HP/MP MAXHP/MAXMP więc potrzebujemy odczytać wartość int.
int jak możemy to zauważyć poprzez "sizeof(int)" ma wielkość 4 bajtów. a więc musimy stworzyć metodę GetInt32 gdzie wyciągniemy interesujące nas dane.


public int GetInt32(IntPtr pHandle, Int32 address) { return BitConverter.ToInt32(ReadBytes(pHandle, new IntPtr(address), 4), 0); }

Skoro możemy pobrać wartość Int32 to pobierzmy odrazu ilość punktów życia naszej postaci:

public int GetHealth(IntPtr pHandle, Int32 address) { return GetInt32(pHandle, address + (int)ADDRESSES.HEALTH_POINTS) ^ GetInt32(pHandle, address + (int)ADDRESSES.XOR); }

Robimy to samo dla MAX_HEALTH_POINTS, MANA_POINTS, MAX_MANA_POINTS podstawiając odpowiednie adresy i przechodzimy do Designera [edycji okienka bota]
Z toolboxa wybieramy timer i klikamy na niego dwa razy. Powinien on zostać dodany, na dole okna designera. Zaznaczamy go i w oknie Properties zmieniamy wartość Enabled na false oraz interval na 100.
Powinno to wyglądać tak:
3641714171195631285262.png
Wchodzimy w edycję kodu MPC_FORUM_BOT i zamieniamy to:

private void button2_Click(object sender, EventArgs e)
{
    if (listBox1.SelectedIndex < 0 && listBox1.SelectedIndex >= Process.GetProcessesByName("tibia").Length)
        return;

    m_client = new MPC_CLIENT_INJECT(Process.GetProcessesByName("tibia")[listBox1.SelectedIndex]);
    MPC_DEBUG.Log("Injected into :: " + m_client.cHandle.ToString());
}

na to:

private void button2_Click(object sender, EventArgs e)
{
    if (listBox1.SelectedIndex < 0 && listBox1.SelectedIndex >= Process.GetProcessesByName("tibia").Length)
        return;

    m_client = new MPC_CLIENT_INJECT(Process.GetProcessesByName("tibia")[listBox1.SelectedIndex]);
    timer1.Enabled = true;
    timer1.Tick += new EventHandler(onBotRefresh);
}

Teraz tworzymy metodę onBotRefresh(object sender, EventArgs e) i wklejamy do niej:

int hp = m_memoryReader.GetHealth(m_client.cHandle, (Int32)m_client.baseAddress);
int mp = m_memoryReader.GetMana(m_client.cHandle, (Int32)m_client.baseAddress);
int hp_max = m_memoryReader.GetMaxHealth(m_client.cHandle, (Int32)m_client.baseAddress);
int mp_max = m_memoryReader.GetMaxMana(m_client.cHandle, (Int32)m_client.baseAddress);

MPC_DEBUG.Log(hp.ToString());
MPC_DEBUG.Log(mp.ToString());
MPC_DEBUG.Log(hp_max.ToString());
MPC_DEBUG.Log(mp_max.ToString());

Oczywiście pole m_memoryReader musimy stworzyć więc.. na samej górze tworzymy pole:

MPC_MEMORY_READER m_memoryReader;

Następnie pod "MPC_DEBUG.SetLogSpace(this.richTextBox1);" dopisujemy :

m_memoryReader = new MPC_MEMORY_READER();

Zapisujemy otwarte pliki [sHIFT+CTRL+S] i odpalamy programik [F5]. Kilkamy w nasze magiczne przyciski [pamiętając o kolejności] i powinniśmy otrzymać taki o to wynik:
9969414171195631285262.png
Właśnie stworzyliśmy odczyt punktów życia oraz many. Tak oto kończymy część 3, w następnej części przedstawię jak ustawić auto healer.
HINT: Zmieniając interval timera będziemy dostawali dokładniejsze dane.
Dla leniwych lub zagubionych SOURCE CODE:
MPC_FORUM_BOT

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace MPC_FORUM_BOT
{
    public partial class MPC_FORUM_BOT : Form
    {
        MPC_CLIENT_INJECT m_client;
        MPC_MEMORY_READER m_memoryReader;

        public MPC_FORUM_BOT()
        {
            InitializeComponent();
            MPC_DEBUG.SetLogSpace(this.richTextBox1);
            m_memoryReader = new MPC_MEMORY_READER();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            listBox1.Items.Clear();
            foreach (Process p in Process.GetProcessesByName("tibia"))
            {
                listBox1.Items.Add(p.MainWindowTitle);
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            if (listBox1.SelectedIndex < 0 && listBox1.SelectedIndex >= Process.GetProcessesByName("tibia").Length)
                return;

            m_client = new MPC_CLIENT_INJECT(Process.GetProcessesByName("tibia")[listBox1.SelectedIndex]);
            timer1.Enabled = true;
            timer1.Tick += new EventHandler(onBotRefresh);
        }

        private void onBotRefresh(object sender, EventArgs e)
        {
            int hp = m_memoryReader.GetHealth(m_client.cHandle, (Int32)m_client.baseAddress);
            int mp = m_memoryReader.GetMana(m_client.cHandle, (Int32)m_client.baseAddress);
            int hp_max = m_memoryReader.GetMaxHealth(m_client.cHandle, (Int32)m_client.baseAddress);
            int mp_max = m_memoryReader.GetMaxMana(m_client.cHandle, (Int32)m_client.baseAddress);

            MPC_DEBUG.Log(hp.ToString());
            MPC_DEBUG.Log(mp.ToString());
            MPC_DEBUG.Log(hp_max.ToString());
            MPC_DEBUG.Log(mp_max.ToString());
        }
    }
}

MPC_MEMORY_READER

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace MPC_FORUM_BOT
{
    public class MPC_MEMORY_READER
    {
        [DllImport("kernel32.dll")]
        private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, int dwSize, ref int lpNumberOfBytesRead);

        private byte[] ReadBytes(IntPtr pHandle, IntPtr address, int bytesToRead)
        {
            int bytesRead = 0;
            byte[] buffer = new byte[bytesToRead];
            ReadProcessMemory(pHandle, address, buffer, bytesToRead, ref bytesRead);
            return buffer;
        }
        
        public int GetInt32(IntPtr pHandle, Int32 address) { return BitConverter.ToInt32(ReadBytes(pHandle, new IntPtr(address), 4), 0); }
        public int GetHealth(IntPtr pHandle, Int32 address) { return GetInt32(pHandle, address + (int)ADDRESSES.HEALTH_POINTS) ^ GetInt32(pHandle, address + (int)ADDRESSES.XOR); }
        public int GetMaxHealth(IntPtr pHandle, Int32 address) { return GetInt32(pHandle, address + (int)ADDRESSES.MAX_HEALTH_POINTS) ^ GetInt32(pHandle, address + (int)ADDRESSES.XOR); }
        public int GetMana(IntPtr pHandle, Int32 address) { return GetInt32(pHandle, address + (int)ADDRESSES.MANA_POINTS) ^ GetInt32(pHandle, address + (int)ADDRESSES.XOR); }
        public int GetMaxMana(IntPtr pHandle, Int32 address) { return GetInt32(pHandle, address + (int)ADDRESSES.MAX_MANA_POINTS) ^ GetInt32(pHandle, address + (int)ADDRESSES.XOR); }
    }
}

ADDRESSES

namespace MPC_FORUM_BOT
{
    public enum ADDRESSES : int
    {
        XOR                              = 0x432BB0,
        MANA_POINTS                      = 0x432C04,
        MAX_MANA_POINTS                   = XOR + 0x4, //MAX_MANA_POINTS                   = XOR + sizeof(int),
        HEALTH_POINTS                    = 0x5CF000,
        MAX_HEALTH_POINTS                = 0x5CF02C
    }
}

4. Auto healer [user32.dll]

    Zaczniemy od stworzenia nowego obiektu [klasy], nazwiemy go "MPC_INPUT_MANAGER". Dopisujemy "using System.Runtime.InteropServices;" w nagłówku, zmieniamy accesor obiektu na publiczny i dopisujemy :

[DllImport("user32.dll")]
private static extern IntPtr PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

Tuż po rozpoczęiu bloku naszego obiektu, a pod spodem dopisujemy:

public IntPtr SendKeystroke(IntPtr hWnd, Keys k)
{
    return PostMessage(hWnd, 0x100, (IntPtr)k, (IntPtr)0);
}

Teraz wchodzimy do designera i modyfikujemy interfejs. Potrzebujemy 2 TextBox, 2 ComboBox [oraz opcjonalnie CheckBox].
Wysztko powinno wyglądać tak:
3902614171912991285262.png
Teraz zaznaczamy Checkbox i zmieniamy w properties wartość Text na "Enable Healer". Przechodzimy teraz do naszego MPC_FORUM_BOT i tworzymy nową metodę o nazwie "healthChecker(int _hp)", po czym wklejamy do niej ten kod:

int _hpBar1;
int _hpBar2;
if(!int.TryParse(textBox1.Text, out _hpBar1))
    _hpBar1 = int.MaxValue;

if(!int.TryParse(textBox2.Text, out _hpBar2))
    _hpBar2 = int.MaxValue;

if (_hp <= _hpBar1 && _hp > _hpBar2)
    m_input.SendKeystroke(m_client.cHWND, (Keys)comboBox1.SelectedItem);
else if (_hp <= _hpBar2 && _hp > 0)
    m_input.SendKeystroke(m_client.cHWND, (Keys)comboBox2.SelectedItem);

Teraz na samej górze tworzymy pole typu MPC_INPUT_MANAGER o nazwie m_input, i pod "m_memoryReader = new MPC_MEMORY_READER();" dopisujemy :

m_input = new MPC_INPUT_MANAGER();
Keys[] _ks = new Keys[] { Keys.F1, Keys.F2, Keys.F3, Keys.F4, Keys.F5, Keys.F6, Keys.F7, Keys.F8, Keys.F9, Keys.F10, Keys.F11, Keys.F12 };
foreach(Keys _k in _ks)
{
    comboBox1.Items.Add(_k);
    comboBox2.Items.Add(_k);
}
_ks = null;

Klikamy CTRL+SHIFT+S, a następnie F5. Powinniśmy otrzymać [+/-] taki wynik:
6577514171912991285262.png
Teraz zajmiemy się implementacją naszego "CheckBoxa". W obiekcie "MPC_FORUM_BOT" odnajdujemy metodę "onBotRefresh" i modyfikujemy ją:

richTextBox1.Text = string.Empty;

int hp = m_memoryReader.GetHealth(m_client.cHandle, (Int32)m_client.baseAddress);
int mp = m_memoryReader.GetMana(m_client.cHandle, (Int32)m_client.baseAddress);
int hp_max = m_memoryReader.GetMaxHealth(m_client.cHandle, (Int32)m_client.baseAddress);
int mp_max = m_memoryReader.GetMaxMana(m_client.cHandle, (Int32)m_client.baseAddress);

if (checkBox1.Checked)
    healthChecker(hp);

MPC_DEBUG.Log(hp.ToString());
MPC_DEBUG.Log(mp.ToString());
MPC_DEBUG.Log(hp_max.ToString());
MPC_DEBUG.Log(mp_max.ToString());

Zapisujemy wszystko [CTRL+SHIFT+S], odpalamy nasz programik [F5], podpinamy go pod klienta i ustawiamy "healera".
Jeżeli wszystko zrobiłeś poprawnie to efekt powinien wyglądać następująco:
5292714171913001285262.png

Tutaj skończymy część 4, oraz jak zwykle dla zagubionych [leniwych] cały kodzik bota:
MPC_FORUM_BOT:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace MPC_FORUM_BOT
{
    public partial class MPC_FORUM_BOT : Form
    {
        MPC_CLIENT_INJECT m_client;
        MPC_MEMORY_READER m_memoryReader;
        MPC_INPUT_MANAGER m_input;

        public MPC_FORUM_BOT()
        {
            InitializeComponent();
            MPC_DEBUG.SetLogSpace(this.richTextBox1);
            m_memoryReader = new MPC_MEMORY_READER();
            m_input = new MPC_INPUT_MANAGER();
            Keys[] _ks = new Keys[] { Keys.F1, Keys.F2, Keys.F3, Keys.F4, Keys.F5, Keys.F6, Keys.F7, Keys.F8, Keys.F9, Keys.F10, Keys.F11, Keys.F12 };
            foreach(Keys _k in _ks)
            {
                comboBox1.Items.Add(_k);
                comboBox2.Items.Add(_k);
            }
            _ks = null;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            listBox1.Items.Clear();
            foreach (Process p in Process.GetProcessesByName("tibia"))
            {
                listBox1.Items.Add(p.MainWindowTitle);
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            if (listBox1.SelectedIndex < 0 && listBox1.SelectedIndex >= Process.GetProcessesByName("tibia").Length)
                return;

            m_client = new MPC_CLIENT_INJECT(Process.GetProcessesByName("tibia")[listBox1.SelectedIndex]);
            timer1.Enabled = true;
            timer1.Tick += new EventHandler(onBotRefresh);
        }

        private void onBotRefresh(object sender, EventArgs e)
        {
            richTextBox1.Text = string.Empty;

            int hp = m_memoryReader.GetHealth(m_client.cHandle, (Int32)m_client.baseAddress);
            int mp = m_memoryReader.GetMana(m_client.cHandle, (Int32)m_client.baseAddress);
            int hp_max = m_memoryReader.GetMaxHealth(m_client.cHandle, (Int32)m_client.baseAddress);
            int mp_max = m_memoryReader.GetMaxMana(m_client.cHandle, (Int32)m_client.baseAddress);

            if(checkBox1.Checked)
                healthChecker(hp);

            MPC_DEBUG.Log(hp.ToString());
            MPC_DEBUG.Log(mp.ToString());
            MPC_DEBUG.Log(hp_max.ToString());
            MPC_DEBUG.Log(mp_max.ToString());
        }

        private void healthChecker(int _hp)
        {
            int _hpBar1;
            int _hpBar2;
            if(!int.TryParse(textBox1.Text, out _hpBar1))
                _hpBar1 = int.MaxValue;

            if(!int.TryParse(textBox2.Text, out _hpBar2))
                _hpBar2 = int.MaxValue;

            if (_hp <= _hpBar1 && _hp > _hpBar2)
                m_input.SendKeystroke(m_client.cHWND, (Keys)comboBox1.SelectedItem);
            else if (_hp <= _hpBar2 && _hp > 0)
                m_input.SendKeystroke(m_client.cHWND, (Keys)comboBox2.SelectedItem);
        }
    }
}

MPC_INPUT_MANAGER

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace MPC_FORUM_BOT
{
    public class MPC_INPUT_MANAGER
    {
        [DllImport("user32.dll")]
        private static extern IntPtr PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

        public IntPtr SendKeystroke(IntPtr hWnd, Keys k)
        {
            return PostMessage(hWnd, 0x100, (IntPtr)k, (IntPtr)0);
        }
    }
}

EDIT & FUTURE INFO:

1. Prace nad projektem bota zostały przerwane z powodu braku czasu.

2. Ten poradnik postanowiłem zakończyć ze względu na rozbierzność języków i technik programowania, których używam obecnie.

3. Poradnik C/C++/Assembler zostanie tutaj umieszczony na przełomie lipec/sierpień i składać się będzie z 21 części.

4. Wszystkich zainteresowanych tworzeniem/rozwojem bota lub nauką programowania zapraszam na PW. Projekt w momencie wypuszczenia poradnika trafi na githuba gdzie [mam nadzieje] ktoś będzie go dalej prowadził.

 

PS. Nigdzie nie widziałem podobnego poradnika, mam nadzieję że ten chociaż troszeczkę przybliży wam jak skonstruować swojego bota. Może nawet zbierzemy ekipę do zbudowania oficjalnego bota MPC :) jeżeli ten poradnik się przyjmie to pokażę także jak stworzyć bota w C++.

 

note: kopiowanie, rozpowszechnianie oraz modyfikowanie zawartości bez zgody autora jest pogwałceniem prawa własności intelektualnej (IP).

Efekty jednego dnia wolnego od pracy :

lWxix4K.png

Chcesz wspomóc produkcję tego bota? Masz doświadczenie w programowaniu modułów, tworzeniu GUI czy skryptowaniu [C#]?

napisz na pw : http://www.mpcforum.pl/user/1285262-bleblable/

Opublikowano

+ za inicjatywę, jednak takie boty były i wszystko niewypały które nie wytrzymały długo (w tym 1 mój), poza tym mało kto będzie dalej się uczyć języka C#.

Tutaj jest także poradnik @Arkeusa:

http://www.mpcforum.pl/topic/1118422-tut-czytanie-pamieci-programow-na-przykladzie-tibii/

 

PS. Widzę, że masz wykupiony pakiet programu Visual Studio, zazdroszczę  :D.

 

Czy na szybko to nie wiem, arkeus tworzył swojego bota (astrabot) około pół roku ^,^.

PS. Tutaj nikt nie umie programować i nie zapowiada się na to by nagle wszyscy zaczęli się uczyć.

8LTfBGw.jpg

Opublikowano

+ za inicjatywę, jednak takie boty były i wszystko niewypały które nie wytrzymały długo (w tym 1 mój), poza tym mało kto będzie dalej się uczyć języka C#.

Tutaj jest także poradnik @Arkeusa:

http://www.mpcforum.pl/topic/1118422-tut-czytanie-pamieci-programow-na-przykladzie-tibii/

 

PS. Widzę, że masz wykupiony pakiet programu Visual Studio, zazdroszczę  :D.

Nie wypały bo robi zazwyczaj jedna osoba [przeważnie na szybko], ale jak by się zebrać do kupy to można całkiem ciekawego bota stworzyć.

 

Co do licencji, to powiedzmy że jest moja... :P Mam licencję z firmy więc, najprawdopodobniej jak stracę pracę to i licencję też ;D

 

EDIT: Ja swojego stworzyłem w tydzień, jak narazie nie dostałem bana ale w sumie mało na nim boce [ciężki interfejs i dużo poprawek]

Efekty jednego dnia wolnego od pracy :

lWxix4K.png

Chcesz wspomóc produkcję tego bota? Masz doświadczenie w programowaniu modułów, tworzeniu GUI czy skryptowaniu [C#]?

napisz na pw : http://www.mpcforum.pl/user/1285262-bleblable/

Opublikowano
PS. Nigdzie nie widziałem podobnego poradnika, mam nadzieję że ten chociaż troszeczkę przybliży wam jak skonstruować swojego bota. Może nawet zbierzemy ekipę do zbudowania oficjalnego bota MPC 

 

 

To jest dużo trudniejsze niż zwykłe odczytywanie pamięci.

Na rynku jest zbyt dużo dobrych, wypromowanych botów z community.

Poziom extreme(zależy dla kogo w sumie) zaczyna się dopiero na czytaniu mapy, analizie jej i ustawianiu path'a + największe utrudnienie to uciekanie przed monsterami na keep distance przy jednoczesnej analizie mapy.

 

No bota pisałem rzeczywiście długo bo same funkcje do skryptera zajeły mi ponad 2 tygodnie, teraz mógłbym go napisać w jakieś 2 tygodnie na szybko, miesiąc jeśli pisał bym dokładnie.

 

Poradnik spoko, używaj tylko zamiast richtextboxa lepiej fastcoloredtextbox, ma dynamiczne kolorowanie i kilkadziesiąt funkcji przydatnych łącznie z spoilerami itp a ogólnie to najlepiej WPF

No i brakuję wątków zamiast timerów, chyba, że to tylko na potrzeby tutorialu robiłeś :)

 

Ps.

 

318631417134217443950.jpg

Opublikowano

To jest dużo trudniejsze niż zwykłe odczytywanie pamięci.

Na rynku jest zbyt dużo dobrych, wypromowanych botów z community.

Poziom extreme(zależy dla kogo w sumie) zaczyna się dopiero na czytaniu mapy, analizie jej i ustawianiu path'a + największe utrudnienie to uciekanie przed monsterami na keep distance przy jednoczesnej analizie mapy.

 

No bota pisałem rzeczywiście długo bo same funkcje do skryptera zajeły mi ponad 2 tygodnie, teraz mógłbym go napisać w jakieś 2 tygodnie na szybko, miesiąc jeśli pisał bym dokładnie.

 

Poradnik spoko, używaj tylko zamiast richtextboxa lepiej fastcoloredtextbox, ma dynamiczne kolorowanie i kilkadziesiąt funkcji przydatnych łącznie z spoilerami itp a ogólnie to najlepiej WPF

No i brakuję wątków zamiast timerów, chyba, że to tylko na potrzeby tutorialu robiłeś :)

Pathfinding, keeo distance to jest pikuś, najtrudniejsze było by wprowadzenie inteligentneg systemu coś w stylu "humanReactionTime" aby nie wpisywać w bocie odstępu czasu między gotHit -> Heal tylko aby bot miał swój własny czas reakcji bazując na 30 minutowym huncie [jestem w trakcie tworzenia tego].

Co do richtextboxa to na początku miałem to zrobić jako aplikację konsolową, ale stwierdziłem że jednak zmienie na WF. WPF tak jest prostszy, przyjemniejszy w obsłudze ale na sam początek dobrze jest zacząć od WF.

Kwestia timerów, tylko po to że to co tutaj  jest przedstawione to poprostu... słabizna [nikt takiego czegoś nie wypuści], do prawdziwego bota trzeba by było wrzucić jakiś renderer (openGL, SDL, DX), stworzyć pętlę i dopiero wtedy kombinować z wątkami. Oczywiście trzeba by było stworzyć klasy bazowe [np. module ] z której wychodziły by moduły bota [hud, healer etc.] następnie aby bot byłpraktyczny trzeba było by dodać możliwość edycji [runtime c# compiler].

Takie tylko moje założenia.

 

EDIT: Ewentualnie zamast renderera można by wyciągnąć asm i zedytować klienta [coś na styl Xenobot'a], wtedy można by stworzyć naprawdę ciekawy i prosty interfejs. Bez konieczności pisania pathfindingu. I tak wszystko opierało by się głównie na callbackach / eventach gdzie główny wątek nie musiał by rozbijać wszystkiego na wątki a tylko dokładać [w zależności od potrzeb] jeden lub dwa pomocnicze.

Efekty jednego dnia wolnego od pracy :

lWxix4K.png

Chcesz wspomóc produkcję tego bota? Masz doświadczenie w programowaniu modułów, tworzeniu GUI czy skryptowaniu [C#]?

napisz na pw : http://www.mpcforum.pl/user/1285262-bleblable/

Opublikowano

Dokładniej ?

Dokładniej to polega na tym samym co anti cheat, zbierasz dane. W tym przypadku chodzi o to żeby bot reagował tak jak człowiek w przypadku leczenia. przykład:

double __thDropped = -1

List<double> mDelta

if(health < HealthToExura)
	__thDropped = ToSec(Time.Now);

while(__thDropped != -1)
{
	if(health > HealthToExura)
	{
		mDelta.Add(ToSec(Time.Now - __thDropped);
		__thDropped = -1;
	}
}

Teraz należało by zbierać takie dane przez X czasu a następnie wyciągnąć minimalną, maksymalną i pośrednią wartość delty. Ustawć opóźnienie między otrzymaniem obrażeń a wysłaniem odpowiedniego klawisza.

Efekty jednego dnia wolnego od pracy :

lWxix4K.png

Chcesz wspomóc produkcję tego bota? Masz doświadczenie w programowaniu modułów, tworzeniu GUI czy skryptowaniu [C#]?

napisz na pw : http://www.mpcforum.pl/user/1285262-bleblable/

Opublikowano

Poco takie głupoty robić, przecież random załatwi sprawę, to na 99,99% nic Ci nie da.

A i jeszcze trzeba dorobić obsługę cooldownów i tak dalej więc to nie ma zastosowania.

Opublikowano

Poco takie głupoty robić, przecież random załatwi sprawę, to na 99,99% nic Ci nie da.

A i jeszcze trzeba dorobić obsługę cooldownów i tak dalej więc to nie ma zastosowania.

To ma właśnie ogromne zastosowanie, jeżeli robisz bota, który ma się zachowywać jak "człowiek" a nie jak [tłumaczony cytat DarkStara] "5 letni dzieciak smashujący losowe klawisze" to jest to już teraz ogromny krok na przód [biorąc pod uwagę resztę botów]. Mój projekt opiera się na prostocie, optymalizacji i niezawodności, nie chcę żeby użytkownik wpisywał zbędne "pierdoły" do bota takie jak :

- delay między spellami,

- ilość hp/mp potrzebnych do leczenia,

- supplies'y,

- gdzie są schody a gdzie inne "pierdoły"

etc. To wszystko może [a nawet musi] być ogarniane przez bota. Wszystkie obecne boty działają na tej samej zasadzie i bardziej wypadało by je nazwać "macro spammer" niż bot ( http://pl.wikipedia.org/wiki/Bot_%28program%29 ).

Efekty jednego dnia wolnego od pracy :

lWxix4K.png

Chcesz wspomóc produkcję tego bota? Masz doświadczenie w programowaniu modułów, tworzeniu GUI czy skryptowaniu [C#]?

napisz na pw : http://www.mpcforum.pl/user/1285262-bleblable/

  • 4 tygodnie później...
Opublikowano

takie pytanie techniczne: boty (nie tylko do Tibii) łatwiej pisać w C# czy C++? Różnica w składni pomiędzy tymi językami nie jest chyba aż tak duża, więc migracja na C# w przyszłości raczej nie robiłaby mi problemu.

Opublikowano

takie pytanie techniczne: boty (nie tylko do Tibii) łatwiej pisać w C# czy C++? Różnica w składni pomiędzy tymi językami nie jest chyba aż tak duża, więc migracja na C# w przyszłości raczej nie robiłaby mi problemu.

C++<C# - jeżeli chodzi o prostote.

C++ jest jak łacina - wszystkie języki mają podobne rzeczy jak c++.

8LTfBGw.jpg

Opublikowano

Dziękuje za odpowiedź. Jeszcze jedno pytanie na temat programowania (przepraszam za ten lekki offtop): jeśli mam problemy z logicznym myśleniem to czy programując nauczę się logicznie myśleć czy już przed rozpoczęciem nauki programowania powinienem posiadać taką umiejętność?

Pozdrawiam

Opublikowano

@dratewka

Logiczne myślenie każdy posiada swoje na pewnym poziomie. Zależy to od różnych aspektów, są niby jakieś ćwiczenia, które poprawiają logiczne myślenie, ale czy to działa to nie jestem w stanie Ci tego powiedzieć, bo nigdy tego nie sprawdzałem i myślę, że rzadko kto to testował. Czy się nauczysz logicznego myślenia podczas programowania? Nie wiem czy mogę to nazwać nauką po prostu jeżeli będziesz popełniał błędy i próbował je rozwiązać na pewno z czasem będziesz dostrzegał te problemy łatwiej, w inny sposób będziesz patrzył na każdy kod, będziesz wyciągał inne wnioski niż na początku.

66j32w.jpg
 
Sprawdź mój tutorial na temat demonbuddy!

Nie odpowiadam na wiadomości prywatne.

Opublikowano

Dziękuje za odpowiedź. Jeszcze jedno pytanie na temat programowania (przepraszam za ten lekki offtop): jeśli mam problemy z logicznym myśleniem to czy programując nauczę się logicznie myśleć czy już przed rozpoczęciem nauki programowania powinienem posiadać taką umiejętność?

Pozdrawiam

Jeżeli masz zapał (nie na parę tygodni lecz miesięcy lub nawet lat) i nie będzie Ci się nudzić 24/7 szukać odpowiedzi w google/stackoverflow lub 4programmers to czemu nie, zapewne trochę się nauczysz, ale czy dużo? Tego niestety nie jestem Ci powiedzieć. W programowaniu właśnie to jest najlepsze, że każdy zaczyna od takiego samego poziomu i tylko praca, praca i jeszcze raz praca może go czegoś nauczyć, w tej dziedzinie nie ma czegoś takiego jak talent - jest tylko logiczne myślenie, bo programowanie polega na znajdywaniu błędów.

8LTfBGw.jpg

Opublikowano

Na pewno zauważyłem ostatnio różnicę w myśleniu, haha :D

Czekam na poradnik do C++, chciałbym napisać własnego bota, który będzie auto-healerem.

  • 7 miesięcy temu...
Opublikowano
if (listBox1.SelectedIndex < 0 && listBox1.SelectedIndex >= Process.GetProcessesByName("tibia").Length)
return;

Powinno być || zamiast && (pundpunkt 2) - kod wywala błąd o nieobsłużonym wyjątku

Zarchiwizowany

Ten temat przebywa obecnie w archiwum. Dodawanie nowych odpowiedzi zostało zablokowane.

×
×
  • Dodaj nową pozycję...