Hi các bác, Sau khi hoàn thành tool editor cho RTK XI (English-PC), tôi có một số kinh nghiệm về debug và phát triển tool editor cho thể loại này. Có thể các kiến thức này kô mới, nhưng hy vọng giúp các bác mới làm quen với debug có thêm kinh nghiệm. Hy vọng các bác yêu thích RTK + lập trình có thể phát triển tool editor cho riêng mình. Thanks all, dungsi3t www.TruBatGioi.net Download Full (Bài viết + Source) ============================ Bài 1: Khởi động Yêu cầu: 1) RTK XI bản English for PC (yêu cầu bắt buộc :devil:) 2) Cheat Engine (CE) (hoặc Art Money ...), trong bài này mình sẽ hướng dẫn về CE để debug. 3) Sử dụng VC++ để phát triển Tool. Mong nhận được sự góp ý và hỗ trợ của các bác yêu thích. Sẵn sàng chia sẻ kinh nghiệm và giúp đỡ các bác bước đầu làm quen với việc debug và phát triển tool editor.
Bài 2: Sử dụng Cheat Engine (CE) để debug và edit Bài này chỉ cung cấp các bước cần thiết cho việc debug và edit bằng CE. Các bác có thể tìm hiểu thêm thông tin trên internet. Step 1: Khởi động game RTK XI Step 2: Run Cheat Engine, tôi đang sử dụng version 5.3 Step 3: Chọn game RTK XI để debug và edit Step 4: New Scan và Next Scan Khi muốn scan một giá trì nào đó, các bác phải xác định Scan Type và Value Type. Lần đầu scan, các bác chọn New Scan --> sẽ cho kết quả là danh sách scan được. Sau đó các bác vào game làm cho giá trị "đã scan trước đó" thay đổi, và tiếp tục Next Scan với giá trị mới. Ví dụ 1: scan giá trị với Type: Exact Value và Type: 4 bytes. Ví dụ 2: scan giá trị với Type: Search for Text và Type: Text. ------------ Lấy một ví dụ cụ thể: scan thông tin của City An Ding Step 1: hiện tại Food là 42261 và tôi New Scan được danh sách sau Step 2: tôi vào game làm cho giá trị Food thay đổi thành 42561. Và tôi chọn Next Scan với giá trị mới (42561) sẽ được kết quả Và bây giờ chỉ còn một address (0x071A1098) thôi, nên tôi biết đó là chỉ số Food của An Ding. Nếu danh sách của các bác còn dài, các bác có thể tiếp tục lặp lại bước này cho đến khi danh sách tối ưu nhất. Nếu danh sách vẫn còn dài, các bác sẽ phải chọn từng address mà ... "đoán". Step 3: add address vừa tìm được list của CE và có thể trace thêm một số thông tin khác. Khi các bác right-click vào dòng trong list, chọn Browse this memory region sẽ xuất hiện window Memory Viewer, scroll lên trên một tí các bác sẽ thấy chữ An Ding (cửa sổ này rất quan trọng, sẽ đề cập trong bài sau). Step 4: muốn edit chỉ số Food hiện tại, các bác có thể double click vào cột Value tương ứng và edit. Các bác có thể tiếp tục với các chỉ số tiếp theo (Gold, Troops, Spears, ...).
Bài 3: Cách tổ chức thông tin trong Mem của RTK XI Step 1: Sau khi scan một số thông tin về Troop, Food, Gold ... của City, các bác sẽ tiếp tục. Ví dụ đây là kết quả tôi scan với Chen Liu Và khi View Memory các bác sẽ thấy một số điều thú vị sau. 1) Bên dưới Chen Liu sẽ thấy Xu Chang với Base_Addr như nhau (78 5E 76 00) và cách nhau 0x0244 bytes. 2) Name = Base_Addr + 0x04 3) Troop = Base_Addr + 0x3C 4) Gold = Base_Addr + 0x40 5) Và tương tự với các thông số khác ... Step 2: Tiếp tục dò lên trên các vùng mem "tương tự" (chú ý "78 5E 76 00") sẽ thấy được City đầu tiên là Xiang Ling. Mỗi City cách nhau là 0x0244 bytes. Step 3: Vậy muốn tìm thông tin của một City bất kì? Đầu tiên, phải biết index (CITY_ID) của City đó trong vùng Mem. Tạm thời các bác sử dụng số index trong Tool Editor nhé (sẽ hướng dẫn các lấy nó sau). Và công thức tính Base_Addr của City bất kì sẽ là = CITY_BASE_ADDR + index * CITY_DATA_SIZE Tương tự như thế với Gate và Port các bác sẽ hiểu cách tổ chức Mem. Step 4: scan các define của City (sẽ sử dụng nó trong phần lập trình). Mã: #define CITY_BASE_ADDR 0x0719E548 #define CITY_DATA_SIZE 0x0244 #define CITY_NAME 0x04 #define CITY_PREFECT 0x30 #define CITY_TROOPS 0x3C #define CITY_GOLD 0x40 #define CITY_FOOD 0x44 #define CITY_SPEARS 0x4C #define CITY_PIKES 0x50 #define CITY_BOWS 0x54 #define CITY_HORSES 0x58 ========================= Bài 4: Sử dụng VC++ để viết tool editor cho RTK XI Step 1: Về phần thiết kế giao diện và ngôn ngữ lập trình trên VC++ tôi kô đề cập nhiều (cái này các bác phải tự tìm hiểu). Lấy ví dụ tool editor đơn giản với City, Gate, Port thôi. Step 2: Làm quen một số hàm cần thiết (cần thêm thông tin các bác search trên Google dùm nhé). 1) Find RTK window: tìm handle của RTK window Mã: int CRTKWnd::FindRTKWindows() { ... EnumWindows(EnumWindowCallBack, NULL); ... } BOOL CALLBACK CRTKWnd::EnumWindowCallBack(HWND hwnd, LPARAM lParam) { TCHAR szClassName[256]; GetClassName(hwnd, szClassName, 256); if (_tcscmp(szClassName,_T("KOEI_SAN_11_WINDOW")) == 0) { ...; } return true; } 2) Sử dụng Read/WriteProcessMemory để read/write Mem + ReadProcessMemory copies the data in the specified address range from the address space of the specified process into the specified buffer of the current process. Any process that has a handle with PROCESS_VM_READ access can call the function. Typically but not always, the process with address space that is being written to is being debugged. http://msdn.microsoft.com/en-us/library/ms680553(VS.85).aspx +WriteProcessMemory copies the data from the specified buffer in the current process to the address range of the specified process. Any process that has a handle with PROCESS_VM_WRITE and PROCESS_VM_OPERATION access to the process to be written to can call the function. Typically but not always, the process with address space that is being written to is being debugged. http://msdn.microsoft.com/en-us/library/ms681674(VS.85).aspx Step 3: Lấy danh sách City Các define của City: Mã: #define CITY_BASE_ADDR 0x0719E548 #define CITY_DATA_SIZE 0x0244 #define CITY_NAME 0x04 #define CITY_TROOPS 0x3C #define CITY_GOLD 0x40 #define CITY_FOOD 0x44 #define CITY_SPEARS 0x4C #define CITY_PIKES 0x50 #define CITY_BOWS 0x54 #define CITY_HORSES 0x58 #define CITY_WILL 0x80 #define CITY_ORDER 0x81 class RTKCity { public: int m_city_id; CString m_city_name; int m_city_troops; int m_city_gold; int m_city_food; int m_city_spears; int m_city_pikes; int m_city_bows; int m_city_horses; int m_city_order; byte m_city_will; void init() { m_city_id = -1; m_city_name = _T(""); m_city_troops = 0; m_city_gold = 0; m_city_food = 0; m_city_spears = 0; m_city_pikes = 0; m_city_bows = 0; m_city_horses = 0; m_city_order = 0; m_city_will = 0; } }; Lấy danh sách City từ Mem rồi add vào combo box: Mã: void CRTKWnd::GetCityNameList() { CString strTmp = _T(""); cboName.ResetContent(); for (int i = 0; i < MAX_CITY; i++) { CString name = GetCity(i); if (name.IsEmpty()) { name = _T(""); } strTmp.Format(_T("%d"), i); cboName.AddString(name + _T("(") + strTmp + _T(")")); } return; } CString CRTKWnd::GetCity(int idx) { HWND hWin = GetWin(m_curIdx); if (!IsWindow(hWin)) { return _T(""); } DWORD dwProcessID; ::GetWindowThreadProcessId(hWin, &dwProcessID); HANDLE hProcess = OpenProcess(PROCESS_VM_READ, FALSE, dwProcessID); if (!hProcess) { return _T(""); } LPBYTE lpBaseAdd = (LPBYTE) (CITY_BASE_ADDR + idx * CITY_DATA_SIZE); char szName[32]; ReadProcessMemory(hProcess, (LPBYTE) (lpBaseAdd + CITY_NAME), (LPVOID) szName, sizeof(szName), NULL); CloseHandle(hProcess); return CString(szName); } Lấy thông tin của City: Mã: RTKCity CRTKWnd::GetCityInfo(int idx) { HWND hWin = GetWin(m_curIdx); RTKCity city; city.init(); if (!IsWindow(hWin)) { return city; } DWORD dwProcessID; ::GetWindowThreadProcessId(hWin, &dwProcessID); HANDLE hProcess = OpenProcess(PROCESS_VM_READ, FALSE, dwProcessID); if (!hProcess) { return city; } LPBYTE lpBaseAdd = (LPBYTE) (CITY_BASE_ADDR + idx * CITY_DATA_SIZE); city.m_city_id = idx; char szName[32]; ReadProcessMemory(hProcess, (LPBYTE) (lpBaseAdd + CITY_NAME), (LPVOID) szName, sizeof(szName), NULL); city.m_city_name = szName; int troops; ReadProcessMemory(hProcess, (LPBYTE) (lpBaseAdd + CITY_TROOPS), (LPVOID) &troops, 4, NULL); city.m_city_troops = troops; int gold; ReadProcessMemory(hProcess, (LPBYTE) (lpBaseAdd + CITY_GOLD), (LPVOID) &gold, 4, NULL); city.m_city_gold = gold; int food; ReadProcessMemory(hProcess, (LPBYTE) (lpBaseAdd + CITY_FOOD), (LPVOID) &food, 4, NULL); city.m_city_food = food; int spears; ReadProcessMemory(hProcess, (LPBYTE) (lpBaseAdd + CITY_SPEARS), (LPVOID) &spears, 4, NULL); city.m_city_spears = spears; int pikes; ReadProcessMemory(hProcess, (LPBYTE) (lpBaseAdd + CITY_PIKES), (LPVOID) &pikes, 4, NULL); city.m_city_pikes = pikes; int bows; ReadProcessMemory(hProcess, (LPBYTE) (lpBaseAdd + CITY_BOWS), (LPVOID) &bows, 4, NULL); city.m_city_bows = bows; int horses; ReadProcessMemory(hProcess, (LPBYTE) (lpBaseAdd + CITY_HORSES), (LPVOID) &horses, 4, NULL); city.m_city_horses = horses; byte will; ReadProcessMemory(hProcess, (LPBYTE) (lpBaseAdd + CITY_WILL), (LPVOID) &will, 1, NULL); city.m_city_will = will & 0xFF; byte order; ReadProcessMemory(hProcess, (LPBYTE) (lpBaseAdd + CITY_ORDER), (LPVOID) &order, 1, NULL); city.m_city_order = order & 0xFF; CloseHandle(hProcess); return city; } Step 4: edit thông tin của City (phải biết index của City), ví dụ như Troops Mã: void CRTKWnd::EditTroops(int idx, int nValue) { HWND hWin = GetWin(m_curIdx); if (!IsWindow(hWin)) { return; } DWORD dwProcessID; ::GetWindowThreadProcessId(hWin, &dwProcessID); HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessID); if (!hProcess) { return; } LPBYTE lpBaseAdd; byte buffer[4]; buffer[0] = (byte)(nValue & 0xFF); buffer[1] = (byte)((nValue >> 8) & 0xFF); buffer[2] = (byte)((nValue >> 16) & 0xFF); buffer[3] = (byte)((nValue >> 24) & 0xFF); lpBaseAdd = (LPBYTE) (CITY_BASE_ADDR + idx * CITY_DATA_SIZE); WriteProcessMemory(hProcess, (LPVOID) (lpBaseAdd + CITY_TROOPS), (LPVOID) buffer, 4, NULL); CloseHandle(hProcess); return; } Step 5: Cuối cùng, sẽ upload lên source (RTKEditorLite) của ví dụ này để các bác tham khảo (source sử dụng VC++ 2008) (xem file đính kèm) Thanks all. dungsi3t
Cảm ơn bác dungsi3t nhiều lắm. Bài viết này của bác vô cùng giá trị :Rose: Nhớ lúc đầu em học lt, thì cái C++ là cái học đầu tiên...Sau này toàn làm việc với code của C# thành ra C++ quên sạch:'> Cách đây vài tháng, lúc em cần viết cái tool cho TSonline...viết bằng C#, mún kiếm một cái turtorial kiểu như bài của bác thế này để viết cho nhanh mà lết từ codeproject đến csharpcorner...đỏ mắt cũng hẻm thấy. Cho nên lúc đó ngồi mò từng tí một, rất là vất vả, mãi mới hoàn thành xong cái tool nhỏ như con kiến. Có điều viết bằng C# thì cần framework mới run được, rất khó chịu. Giá lúc đó em gặp cái bài này thì khỏe rồi. Cảm ơn bác 1 lần nữa:'>
Mấy bác cứ nghiên cứu, cần thêm thông tin gì tôi sẽ post lên và thảo luận. Các bác thử tìm Base_Addr của Officer (hoặc Forces, District ...) xem sao?
Cám ơn bác dungsi3t nghen ... hong hiểu chắc ghé nhà bác chỉ dùm em wá .... rỏ ràng wá ... chắc bi giờ mở sách C++ mò từng chử wá
bác dungsi3t có cách nào sửa số ngày của 1 turn không? 1 turn là 10 ngày nhanh quá. Chưa thống nhất được mà tướng đã chết tùm lum hết Có cách nào thay 1 turn = 1 ngày không vậy bác? :hug:
Vấn đề này chắc có nhiều hướng giải quyết: 1) Edit Lifespan hoặc Death của Officer 2) Edit lại current day của game --> có thể làm được 3) Hook vào game để xử lý cái turn ... cho nó khỏi tăng ngày luôn :hug: Ý tưởng là vậy ... bác nào rãnh làm thử xem
Vậy nếu xét theo khía cạnh thực tế 30 ngày = 30 turn mới có 1k vàng 90 turn mới có 20k food Thế thì thành ko sập thì quân tướng cũng chết đói cả
Yes, thực tế là thế. Nhưng xét về khía cạnh lập trình ... có thể hook vào game để làm cho mọi thứ như bình thường (Gold, Food tăng normal), nhưng ngày trôi qua là ... 1 ngày hoặc kô trôi :o Bàn bạc và làm cho vui thôi ... chứ can thiệp như thế game mất vui rồi, vì ngày kô tăng thì mất rất nhiều Event hay.
Đấy là em ví dụ 1 turn = 1 ngày. Phần mềm có thể cho người chơi tùy ý lựa chọn 1 turn = 1 , 2 , 3 ,5 , 6...(ước số của 30) ngày mà? Lương thực cứ 9 turn là thu hoạch / tiền cứ 3 turn là thu.... có được không bác?
Mới ngồi ôn lại c++ nên cho pawn hỏi ngoài lề tí nha bác::), Sao dungsi3t không dùng MFC của visual C++ 6.0? mà lại dùng cái MFC sử dụng ở dạng Static library trong bộ visual studio 2008, như vậy thì file thực thi hơi bị nhớn? mà không biết dạo này bác còn hay vào box không hay bị cô nào gọi hồn rùi:p
Uh, trước kia cũng sử dụng VC++ 6.0. Nhưng đợt rồi lỡ nâng cấp lên VS 2008 rồi ... nên code luôn cho các ứng dụng về sau (lười code lại mà :devil:) Bác có thể build lại với VC++ 6.0 cho mình, vì thực ra cũng chỉ sử dụng Read/WriteMemoryProcess thôi. Bác code thử ứng dụng nho nhỏ cho vui, cần thêm Address nào thì tôi sẽ post lên thêm.
theo ý hiểu của tui ( tui không chơi game này nên không rõ ) thì tool của bạn cho phép người sử dụng nhập các thông tin cần thay đổi vào file hack game,sau đó nhờ vào địa chỉ cố định của các thông tin như Gold,food... bạn sử dụng hàm WriteProcessMemory để thay đổi thông tin trong game,nếu vậy thì mình thấy game này còn dễ,chứ như game World of Warcraft thì địa chỉ nó cứ thay đổi lung tung,mỗi lần load cheat Engine lên là lại 1 địa chỉ,vì vậy rất khó để thay đổi được thông tin của nó