Tiếp tục phần 3 Lập Trình Auto Game với C#
đầu tiên tạo 1 listview và bố trí lại Gui theo như hình dưới
Danh sách list view chứa ID là pid của game, và Tên nhân vật trong game.
Để đọc được tên nhân vật, các chỉ số trong game chúng ta cần tìm chính xác địa chỉ của nó, hay còn gọi là Base adress(tìm trong cheat Engine). chỉ cần tìm được adress màu xanh lục và các offset, thì mỗi khi loadgame thì sẽ luôn đọc được tên nhân vật.
1: vd tìm tên nhân vật
Tải CHEAT ENGINE TẠI ĐÂY
mở Cheat Engine lên mở game, ở đây mình chọn game đao kiếm 2
Sau đó ở khung Value: gõ tên nhân vật vào và chọn theo như hình dưới, vì tên nhân vật là kiểu String và chọn Utf-16 để có thể tìm base bằng tiếng việt có dấu.
với mỗi địa chỉ tìm được sau khi load game sẽ bị thay đổi vì mỗi game chứa 1 bộ địa chỉ được phân bố riêng. để giải quyết vấn đề trên chúng ta cần tìm được địa chỉ xanh(địa chỉ không bị thay đổi) hoặc tìm các offset khác của nó để khi load game nó luôn trỏ đúng địa chỉ cần lấy.
Sau khi Scan sẽ ra các địa chỉ và giá trị cần tìm , chúng ta chỉ chú ý những base adress và offset có giá trị lặp lại nhiều lần.
Tạo 1 ListView |
Thiết lập các thuộc tính cho Listview |
1: vd tìm tên nhân vật
Tải CHEAT ENGINE TẠI ĐÂY
mở Cheat Engine lên mở game, ở đây mình chọn game đao kiếm 2
Chọn game DK2 |
Dùng cheat để tìm base adress |
Thêm các địa chỉ tìm được vào khung 3 |
Vì có nhiều giá trị giống nhau nên ta lần lượt chọn tất cả các base và đổi type sang text với độ dài chuỗi là 255 để xem kết quả chính xác nhất
Sau khi ra các kết quả thì ta lần lượt đổi tên từng địa chỉ, nếu tên nhân vật trong game cũng thay đổi thì ta đã tìm ra được địa chỉ ban đầu.với mỗi địa chỉ tìm được sau khi load game sẽ bị thay đổi vì mỗi game chứa 1 bộ địa chỉ được phân bố riêng. để giải quyết vấn đề trên chúng ta cần tìm được địa chỉ xanh(địa chỉ không bị thay đổi) hoặc tìm các offset khác của nó để khi load game nó luôn trỏ đúng địa chỉ cần lấy.
Đổi tên giá trị để tìm base adress ban đầu. |
Sử dụng Pointer Scan để tìm địa chỉ không bị thay đổi bao gồm offset
Pointer Scan |
Để cho chắc ăn giá trị đó không thay đổi thì mình sẽ dùng 1 nick game khác để check, nếu như khi dùng cheat enigine mở game thứ 2 mà giá trị nào trong bảng Pointer Scan không thay đổi và vẫn giữ nguyên giá trị thì đó chính xác là chúng ta đã tìm được địa chỉ chứa tên nhân vật.
CODE CHỨC NĂNG ĐỌC TÊN NHÂN VẬT
quay trở lại với visual Studio mở source Auto đã làm ở bài 2 ra và tạo 1 Class với tên MemoryDK2
nội dung class MemoryDK2 có chứa các hàm hỗ trợ đọc bộ nhớ game
với hàm ReadInt32(); để đọc các địa chỉ kiểu int
vd : int Ptr1 = MemoryDk2.ReadInt32((int)Address_name + Base, 4, handle);
CODE CHỨC NĂNG ĐỌC TÊN NHÂN VẬT
quay trở lại với visual Studio mở source Auto đã làm ở bài 2 ra và tạo 1 Class với tên MemoryDK2
Tạo class MemoryDK2 |
với hàm ReadInt32(); để đọc các địa chỉ kiểu int
vd : int Ptr1 = MemoryDk2.ReadInt32((int)Address_name + Base, 4, handle);
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; namespace AutoControlAppPC { public class MemoryDK2 { [DllImport("kernel32.dll")] public static extern Int32 ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [In, Out] byte[] buffer, UInt32 size, out IntPtr lpNumberOfBytesRead); public static byte[] ReadBytes(IntPtr Handle, Int64 Address, uint BytesToRead) { IntPtr ptrBytesRead; byte[] buffer = new byte[BytesToRead]; ReadProcessMemory(Handle, new IntPtr(Address), buffer, BytesToRead, out ptrBytesRead); return buffer; } public static int ReadInt32(long Address, uint length = 4, IntPtr? Handle = null) { return BitConverter.ToInt32(ReadBytes((IntPtr)Handle, Address, length), 0); } public static string ReadString(long Address, uint length = 32, IntPtr? Handle = null) { string temp3 = Encoding.Unicode.GetString(ReadBytes((IntPtr)Handle, Address, length)); string[] temp3str = temp3.Split('\0'); return temp3str[0]; } } }
vd mình tìm được địa chỉ là :
Địa chỉ kèm offset tìm được |
Sau đó trong form2 mình sẽ viết 1 hàm để đọc địa chỉ trên.
Mỗi địa chỉ và offset đi kèm ký tự 0x ở phía trước.
Việc còn lại chỉ là gọi hàm GetNameChar kèm truyền vào base ,handle của game là có thể lấy được tên nhân vật.
public static string GetNameChar(int Base, IntPtr handle){int Address_name = 0x94B6CC;int Ptr1 = MemoryDK2.ReadInt32((int)Address_name + Base, 4, handle);int Ptr2 = MemoryDK2.ReadInt32((int)Ptr1 + 0X108, 4, handle);int Ptr3 = MemoryDK2.ReadInt32((int)Ptr2 + 0XC8, 4, handle);int Ptr4 = Ptr3 + 0X0;string PtrRead = MemoryDK2.ReadString(Ptr4, 255, handle);return PtrRead;}
Sau đó tạo thêm 1 mảng ListViewItem[] lv1;
trong hàm CheckLoadGame bây giờ sẽ như sau :
trong hàm CheckLoadGame bây giờ sẽ như sau :
public void CheckLoadGame(string name) { if (IsGameAvailable(name)) { try { Process[] processlist = Process.GetProcessesByName(name); // Console.WriteLine(processlist.ToString()); foreach (Process process in processlist) // 2 { label1.Text = "Loa Game Thành Công"; //Lấy base game int Base = (int)process.MainModule.BaseAddress.ToInt32(); //lấy tên nhân vật dựa vào hàm GetNameChar cùng 2 tham số ở dưới string tennv = GetNameChar(Base, process.Handle); //lấy pid của game string Pid = process.Id.ToString(); //Thêm pid và tên nhân vật vào Listview ListViewItem lv1 = new ListViewItem() { Text = Pid.ToString() }; lv1.SubItems.Add(new ListViewItem.ListViewSubItem() { Text = tennv }); listView1.Items.Add(lv1); } } catch (Exception) { label1.Text = "Loa Game Thất Bại"; } } else { label1.Text = "Không tìm thấy Game"; } } #endregion
F5 để build và thưởng thức thành quả
|
F5 chạy chương trình |
Full code :
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Diagnostics; using KAutoHelper; using System.Threading; using System.Threading.Tasks; namespace AutoControlAppPC { public partial class Form2 : Form { public Process[] myProcess; ListViewItem[] lv1; public Form2() { InitializeComponent(); } #region CheckLoadGame public bool IsGameAvailable(string name) { myProcess = Process.GetProcessesByName(name); if (myProcess.Length != 0) { return true; } else { return false; } } public void CheckLoadGame(string name) { if (IsGameAvailable(name)) { try { Process[] processlist = Process.GetProcessesByName(name); // Console.WriteLine(processlist.ToString()); foreach (Process process in processlist) // 2 { label1.Text = "Loa Game Thành Công"; //Lấy base game int Base = (int)process.MainModule.BaseAddress.ToInt32(); //lấy tên nhân vật dựa vào hàm GetNameChar cùng 2 tham số ở dưới string tennv = GetNameChar(Base, process.Handle); //lấy pid của game string Pid = process.Id.ToString(); //Thêm pid và tên nhân vật vào Listview ListViewItem lv1 = new ListViewItem() { Text = Pid.ToString() }; lv1.SubItems.Add(new ListViewItem.ListViewSubItem() { Text = tennv }); listView1.Items.Add(lv1); } } catch (Exception) { label1.Text = "Loa Game Thất Bại"; } } else { label1.Text = "Không tìm thấy Game"; } } #endregion private void Form2_Load(object sender, EventArgs e) { CheckLoadGame("dj2"); } //Hàm chính của chúng ta để click ẩn. void ControlClick(int pid, int x, int y) { if (checkBox1.Checked) { IntPtr hWnd = IntPtr.Zero; hWnd = Process.GetProcessById(pid).MainWindowHandle; AutoControl.BringToFront(hWnd); AutoControl.SendClickOnPosition(hWnd, x, y); } else { IntPtr hWnd = IntPtr.Zero; hWnd = Process.GetProcessById(pid).MainWindowHandle; AutoControl.SendClickOnPosition(hWnd, x, y); } } private void button1_Click(object sender, EventArgs e) { ControlClick(5968, 538, 579); } private void button2_Click(object sender, EventArgs e) { Task.Run(() => GetMail(5968)); } private void checkBox2_CheckedChanged(object sender, EventArgs e) { if (checkBox1.Checked) { this.TopMost = true; label2.Text = "Kích hoạt OnTop"; } else { this.TopMost = false; label2.Text = "Hủy kích hoạt OnTop"; } } public void Sleep(double delay) { double delayTime = 0; while (delayTime < delay) { Thread.Sleep(TimeSpan.FromSeconds(1)); delayTime++; } } void GetMail(int Pid) { ControlClick(Pid, 784, 527); //1 Sleep(0.1); ControlClick(Pid, 260, 195);//2 int num = 12;//12 dòng int Posy = 195;//tọa độ y for (int i = 0; i < num; i++) { Posy = Posy + 20; //sau mỗi lần y sẽ + thêm 20 ControlClick(Pid, 260, Posy); //2 ControlClick(Pid, 543, 413); //3 } Sleep(0.1); ControlClick(Pid, 260, 453); //4 Sleep(0.1); ControlClick(Pid, 324, 453); //5 Sleep(0.1); ControlClick(Pid, 784, 527);//6 } public string GetNameChar(int Base, IntPtr handle) { int Address_name = 0x94B6CC; int Ptr1 = MemoryDK2.ReadInt32((int)Address_name + Base, 4, handle); int Ptr2 = MemoryDK2.ReadInt32((int)Ptr1 + 0X108, 4, handle); int Ptr3 = MemoryDK2.ReadInt32((int)Ptr2 + 0XC8, 4, handle); int Ptr4 = Ptr3 + 0X0; string PtrRead = MemoryDK2.ReadString(Ptr4, 255, handle); return PtrRead; } } }Nếu thấy hay hay click vào quảng cáo giúp mình nhé