Chào mừng đến với Diễn đàn lập trình - Cộng đồng lập trình.
Trang 1 của 18 12311 ... CuốiCuối
Kết quả 1 đến 10 của 176
  1. #1
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Chap 3 : Vô hạn lượt đổi (unlimited continue)


    Cũng như lần trước nhưng có 1 vài thay đổi,
    đó là tôi biết địa chỉ của biến điểm là 004B6088
    vậy tôi sẽ khoanh vùng lại tìm kiếm cho nhanh (theo kinh nghiệm thì 1 biến ở đó thì biến còn lại cũng chỉ ở gần gần đó thôi, ko đi xa đâu) nên tôi tìm như sau (lần này tôi tìm cả integer 4byte nữa) như trong hình sau


    Thật tuyệt vời, chỉ tìm 1 lần là ra luôn, nó là 1 số nguyên 4byte và có địa chỉ là 004B60AA
    vậy tôi demo luôn, cách thức cũng ko khác lần trước là mấy
    Mã nguồn PHP:
    #include <windows.h> void SetContinueTo999() { HWND hwnd =FindWindow(L"ThunderRT6FormDC", L"³s³s¬Ý2"); if (!hwnd) { MessageBox(HWND_DESKTOP,L"Bạn phải bật pikachu lên chơi trước đã",L"Thông báo",MB_OK); } else { DWORD pid; int temp=0; GetWindowThreadProcessId(hwnd,&pid); HANDLE handle=OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_OPERATION|PROCESS_VM_WRITE,FALSE,pid); int *address=(int*)0x4B60AA; WriteProcessMemory(handle,address,&temp,sizeof(temp),0); MessageBox(HWND_DESKTOP,L"Đã add thành công",L"Thông báo",MB_OK); } } int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd) { SetContinueTo999(); return EXIT_SUCCESS; }  
    và code chạy trên DEV-C :
    Mã nguồn PHP:
    #include <windows.h> void SetContinueTo999() { HWND hwnd =FindWindow("ThunderRT6FormDC", "³s³s¬Ý2"); if (!hwnd) { MessageBox(HWND_DESKTOP,"Ban phai bat pikachu len choi truoc da","Thông báo",MB_OK); } else { DWORD pid; int temp=0; GetWindowThreadProcessId(hwnd,&pid); HANDLE handle=OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_OPERATION|PROCESS_VM_WRITE,FALSE,pid); int *address=(int*)0x4B60AA; WriteProcessMemory(handle,address,&temp,sizeof(temp),0); MessageBox(HWND_DESKTOP,"Ðã add thành công","Thông báo",MB_OK); } } int main() { SetContinueTo999(); return 1; }  

  2. #2
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Chap 4 : infinite time
    Đây là chap tương đổi khó, để infinite time chúng ta phải đảm bảo được 2 điều
    + Tìm ra điạ chỉ của biến time
    + Tư tưởng đóng băng nó


    I. Tìm ra địa chỉ của biến time :</font>
    Cách 1 : Tôi dò dưới chế độ Unknown value :
    đầu tiên


    Bước 2
    Nghỉ tầm 1s để thanh time bar tụt đi 1 tí rồi tôi làm như này

    sau đó cứ lặp lại bước 2 cho đến khi tìm thấy thì thôi
    (Tốn khá nhiều time để bạn tìm thấy nó đấy)



    Cách 2
    : Cách 1 khá công phu và loằng ngoằng, nên theo kinh nghiệm, tôi ko làm như vậy, vào artmoney

    xem vùng nhớ ở gần cái biến điểm tôi thấy có 1 vùng cứ nhẩy giá trị liên tằng tằng theo thời gian, tôi đoán đó là biến time

    vô artmoney thử đóng băng cái giá trị đó tôi thấy thanh time bar nhúc nhíc quanh 1 điểm chứ ko tụt đi, vậy chính là nó
    là 1 số thực 4byte (float) có địa chỉ là 004B6084 (Vậy là nó đứng ngay cạnh, đằng trước biến điểm)


    II. Code đóng băng nó

    thật ra cái biến time này nó là 1 biến float nhưng khi memory map tớ còn phát hiện ra như sau :
    giả sử 4 byte của biến float đó là abcd
    bỏ qua 2 byte a,b quan tâm đến c d tớ thấy
    + c chạy từ 0 đến 1 giá trị max rồi lại trở về 0 chạy tiếp, theo nhịp của trò chơi,
    + d càng nhỏ thì c chạy càng nhanh, khi d bằng 69 thì bắt đầu chạy từ từ, khi d cao đến gần 80 thì c chạy chậm hẳn
    + d=0 thì c chạy cực nhanh, cỡ mini dây, vụt 1 phát, d thành 69 luôn và c bắt đầu chạy từ từ với tộc dộ chậm dần
    và vì vậy :
    + nếu set d thành số nhỏ hơn 69 thì ngay lập tức trở về bình thường
    + nếu set d thành -1 thì có nghĩa d chính là 255 (vì nó là 8bit mà) sẽ overflow ngay
    + nếu set cả biến float 4byte này thành 1 số âm thì theo cách tớ vừa mô tả ở trên d sẽ rất nhanh chóng phục hồi lại thành 69 và ko có tác dụng
    + nếu set cả biến float 4byte này thành 1 số lớn hơn mức cực đại thì sẽ kết thúc trận đấu luôn

    ==> thay đổi biến time này ko có hiệu quả
    nhưng suy ra 1 cách đó là ta làm đóng băng giống như các cheat engine đóng băng : cứ 100ms thì lại set d=0 một lần, như thế thanh time bar vẫn max, time vẫn vô cùng




    Tôi mất khá nhiều time để nghĩ và tìm ra cách đóng băng nó hay hơn
    + đầu tiên, đơn giản nhất, tôi nghĩ ra là sét giá trị cho nó 1 cách liên tục,
    demo
    Mã nguồn PHP:
    while (..){ set max time() sleep(100)}  
    nhưng như thế ko hay cho lắm, vậy cái hack tool và tôi viết ra lúc nào cũng phải chạy thì mới đóng băng được time, ko hay

    + tiếp theo : trong cái code decompile ra được, tôi thấy có 1 hàm sử lí TIMER, vậy tôi định kill timer của process này, nhưng còn loằng ngoằng hơn ..... và tôi chưa tìm được định danh của cái bộ timer này nên ..... lực bất tòng tâm


    + Cuối cùng, bực mình, sáng suốt tôi quyết định tìm ra nguyên nhân tay đổi nó.
    ví dụ trong process có 1 đoạn là time=10+time/60 (ví dụ thế) .
    Tôi quyết định dùng các kinh nghiệm đã có để tìm ra đoạn mã gán giá trị cho biến time này, rồi tôi thay đổi luôn đoạn mã này đi, thế là ok ? Đúng ko bạn

    Bắt đầu nghĩ tôi thấy, time là 1 biến thực 4 byte, vậy với asm32 - float processing thì đoạn mã tôi cần tìm sẽ có dạng như sau

    Mã nguồn PHP:
    fld real4 ptr [004B6084].....................fstp real4 ptr [004B6084]  
    fld viết tắt của float load
    fstp viết tắt của float store point
    tạm dịch sang ngôn ngữ nói nó là
    Mã nguồn PHP:
    fload time.... xử lí linh tinh....fsave time  
    Đến đây tôi có 2 cách :
    Cách 1 đơn giản nhất mang tính tình huống, tôi mở VB Decompiler Pro với quyền admin, rồi decompile upikachu (xem chap1) , sau đó vào File vào Save all in one module file Được 1 file .bas . Mở file này bằng notepad rồi ấn Ctrl + F tìm kiếm chuỗi 004B6084, tìm đúng chỗ nào sử dụng toán tử fld với tham số là 004B6084 ta được
    Mã nguồn PHP:
    004B02C4: fld real4 ptr [004B6084h] ; 004B02CA: fadd real8 ptr var_80 004B02CD: fild dword ptr var_14 004B02D0: mov var_14, ebx 004B02D3: fstp real8 ptr var_88 004B02D9: fsub real8 ptr var_88 004B02DF: fstp real4 ptr [004B6084h] ;  
    Cách 2 phức tạp hơn 1 tí : load Upokemon.exe bằng Ollydbg (Download tại đây) . Chú ý load file mà ta đã unpack rồi, sẽ dễ dàng hơn trong việc tìm kiếm
    -> vào Ollybdb vào View vào Memory
    -> Đúp chuột vào section .text
    -> ra 1 cửa sổ dump, ta chuột phải, vào copy, vào select all
    -> chuột phải lần nữa vào copy vào to file
    -> được 1 file txt
    -> tìm kiếm trên file này
    chú ý : theo luật little-endian by order 004B6084 thì trong máy nó được tổ chức là 84 60 4B 00, nên chuỗi tìm kiếm của ta trong cách này phaỉ là 84604B00
    tìm và thu được kết quả như sau
    Mã nguồn PHP:
    004B02C4 D905 84604B00 FLD DWORD PTR [>004B02CA DC45 80 FADD QWORD PTR >004B02CD DB45 EC FILD DWORD PTR >004B02D0 895D EC MOV [EBP-14],EB>004B02D3 DD9D 78FFFFFF FSTP QWORD PTR >004B02D9 DCA5 78FFFFFF FSUB QWORD PTR >004B02DF D91D 84604B00 FSTP DWORD PTR >  
    III. Xử lý kết quả thu được như thế nào
    Ta đã có đoạn mã và địa chỉ của đoạn mã này trong bộ nhớ rồi, ta phải làm thế nào bây giờ ?
    Tôi nghĩ ra 1 cách , đó là tôi lái cái fld ra 1 chỗ khác, tôi cho nó fload sang ô điểm, hờ hờ hờ (như thế câu lệnh này sẽ trở thành)
    Mã nguồn PHP:
    fload điểm.... xử lí linh tinh....fsave time  
    như thế này rõ ràng là chả có biến nào bị thay đổi cả rồi, hờ hờ hờ hờ (vì thằng điểm được load nhưng ko được save, thằng time được save nhưng bên trên đó lại chưa load, đâm ra chả có gì thay đổi cả)
    ở đây , tại ô nhớ 004B02C4 câu lệnh fld real4 ptr [004B6084h] ; dài 6 byte 2 byte đầu chính là mã của toán tử fld(0x5D9) (Tôi biết là 6byte vì câu lệnh tiếp theo có địa chỉ 004B02CA), 4byte sau chính là tham số của toán tử này 004B6084h.


    ==> chung quy lại tôi sẽ viết 1 chương trình đổi giá trị tại địa chỉ 004B02C6 từ giá trị ban đầu là 004B6084 thành 004B6088

    Code
    Mã nguồn PHP:
    #include <windows.h>void SetInfiniteTime(){ HWND hwnd =FindWindow(L"ThunderRT6FormDC", L"³s³s¬Ý2"); if (!hwnd) { MessageBox(HWND_DESKTOP,L"Bạn phải bật pikachu lên chơi trước đã",L"Thông báo",MB_OK); } else { DWORD pid; int temp=0x4B6088; GetWindowThreadProcessId(hwnd,&pid); HANDLE handle=OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_OPERATION|PROCESS_VM_WRITE,FALSE,pid); int *address=(int*)0x4B02C6; WriteProcessMemory(handle,address,&temp,sizeof(temp),0); MessageBox(HWND_DESKTOP,L"Đã set thành công",L"Thông báo",MB_OK); }}void UnSetInfiniteTime(){ HWND hwnd =FindWindow(L"ThunderRT6FormDC", L"³s³s¬Ý2"); if (hwnd) { DWORD pid; int temp=0x4B6084; GetWindowThreadProcessId(hwnd,&pid); HANDLE handle=OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_OPERATION|PROCESS_VM_WRITE,FALSE,pid); int *address=(int*)0x4B02C6; WriteProcessMemory(handle,address,&temp,sizeof(temp),0); MessageBox(HWND_DESKTOP,L"Đã unset thành công",L"Thông báo",MB_OK); }}int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd){ SetInfiniteTime(); return EXIT_SUCCESS;}  
    Code cho Dev-C
    Mã nguồn PHP:
    #include <windows.h>void SetInfiniteTime(){ HWND hwnd =FindWindow("ThunderRT6FormDC", "³s³s¬Ý2"); if (!hwnd) { MessageBox(HWND_DESKTOP,"Ban phai bat pikachu lon choi truoc do","Thung boo",MB_OK); } else { DWORD pid; int temp=0x4B6088; GetWindowThreadProcessId(hwnd,&pid); HANDLE handle=OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_OPERATION|PROCESS_VM_WRITE,FALSE,pid); int *address=(int*)0x4B02C6; WriteProcessMemory(handle,address,&temp,sizeof(temp),0); MessageBox(HWND_DESKTOP,"Do set thanh cong","Thong bao",MB_OK); }}void UnSetInfiniteTime(){ HWND hwnd =FindWindow("ThunderRT6FormDC", "³s³s¬Ý2"); if (hwnd) { DWORD pid; int temp=0x4B6084; GetWindowThreadProcessId(hwnd,&pid); HANDLE handle=OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_OPERATION|PROCESS_VM_WRITE,FALSE,pid); int *address=(int*)0x4B02C6; WriteProcessMemory(handle,address,&temp,sizeof(temp),0); MessageBox(HWND_DESKTOP,"Do unset thanh cong","Thong bao",MB_OK); }}int main(){ SetInfiniteTime(); return 1;}  
    Kết quả thành công hơn cả mong đợi, sau khi set 1 lần (Set lúc nào cũng được, kể cả chưa vào game)thanh time bar sẽ đứng im luôn, ko dịch chuyển nữa, luôn ở trạng thái max, cho dù new game nhiều lần vẫn ko ảnh hưởng.

    Kết luận : Với tất cả 4 chap trên, bạn hoàn toàn có thể viết 1 cái hack tool cho pikachu rồi đấy, nếu ko có kinh nghiệm tạo các ứng dụng trên windows, các bạn hoàn toàn có thể dùng DEV-C để viết lên 1 chương trình có menu như bình thường, nhập 1 để add point, 2 để hack mạng .......... Chúc các bạn thành công và vui vẻ với loạt tut này.






    Chap 5 : Cheat mode
    hôm nay ko rảnh rảnh nhưng vẫn ngồi viết tiếp phần mở đầu cho chap 5
    I. Fix lại lỗi bị dis khi chơi :
    khi chúng ta chơi pikachu, chúng ta thấy game bị dis mỗi khi bài hát hết, bực mình thật đó,
    ko biết làm sao cả, tôi lại phân tích thế này
    sau khi unpack và dùng reshack tôi phát hiện ra trong source dùng midi làm nhạc nền cho app, có 3 bài nhạc nền
    vậy là đầu tiên chúng chơi 1 bài, sau đó đổi bài chơi bài tiếp
    vậy là lỗi khi đổi bài,

    xem tiếp source decompile 1 lúc, chưa thấm gì, dùng vbdecompiler 7.9 thì thấy nó decompiler ra cả source vb chứ ko phải là asm nữa,
    tôi thì chưa từng học vb bao giờ cả
    nhưng xem source vb này, sơ sơ tôi đánh giá được như này nè
    ở trong vb5.0 nó có thể play midi mà ko cần đến việc quan tâm tạo ra 1 player như trong C++ mà chỉ việc bắt play music còn lại thì msvbvm quyết định,
    sound play được nhúng vào từ wmmlib chỉ là để play các .wav thôi chứ lại ko play midi......
    tớ thấy là thế, các vb coder sai ở đâu thì giúp tớ chỉ bảo tớ nhé. cám ơn các bạn

    tớ bắt đầu tìm thêm code thấy là nó như này, nó dùng 1 sự kiện timer của form để bắt đầu đếm xem đã play được đến đâu rồi, nếu mà hết bài thì nó thực hiện đoạn mã đổi bài
    vụ này được nằm hết trong sự kiện timer của main form
    mở lại VB Decompiler Pro ta thấy được dòng như sau

    Mã nguồn PHP:
    Private Sub Timer_PlayMidi_Timer() '4B30D0  
    rất gợi mở phải ko nào

    Load pikachu với olldbg
    chuột phải vào dòng go to -> Expression
    nhập địa chỉ 4B30D0 để jump đển hàm đó
    chà, hàm này dài quá, loằng ngoằng nữa, tôi cũng hơi gà, ko biết đoạn lệnh nào là chuyển đổi bài hát cả,
    thôi mạo muội đổi đổi luôn cái hàm này thành hàm ko có gì [IMG]images/smilies/biggrin.png[/IMG]
    chỉ vào dòng có địa chỉ 4B30D0, ấn space 1 cái, đổi mã của hàm này thành
    Mã nguồn PHP:
    RET  
    (lúc ấn space xong, nó hiện ra 1 cái ô input nhỏ, cứ thể gõ RET vào rồi enter phát là được)
    tức là câu lệnh return trong C ấy mà, có mã là C3
    rồi ấn vào nút play ở trên menu (hoặc F9) để chạy thử cái, thấy ngon lành cành đào, đợi tiếp xem hết bài nhạc có dis ko, ko thấy dis, hì hì
    bây giờ ngon rồi,

    ==>> ta sẽ xóa bỏ tất cả các dòng còn còn lại trong hàm đó bằng các : bôi đen toàn bộ dòng code của hàm này, chuột phải
    vào edit binary
    chỉ vào ô hex ở trong cửa sổ edit, ấn ctrl + a
    rồi chuột phải tiếp vào set zero để toàn bộ vùng này có giá trị là 0 hết (0 là ko có gì )
    ==> ngon rồi, ta đã loại bỏ đi cái hàm thừa thãi ko cần thiết

    làm thế nào nhỉ để lấy được cái chương trình đã debug này?
    chuột phải, vào dòng dump debugged process rồi ấn dump là được
    hi hi
    tôi thấy lạ là tôi dùng windows7 dump thì được file chạy luôn
    ở trong xp dump thì phải dùng ImportREC để rebuild lại mới chạy được


    bây giờ được rồi, chạy hoài ko dis

    nhưng mà thế này rõ ràng là thừa 2 file midi trong resource rồi
    lại dùng reshack để del 2 bài midi thứ 2 và thứ 3 đi
    thế là dung lượng nhỏ đi bao nhiêu


    Mã:
    HWND FindGameWindow(){    HWND hwnd=FindWindow(L"ThunderRT6FormDC", L"³s³s¬Ý2");     if (!hwnd) hwnd=FindWindow(L"ThunderRT6FormDC", L"Pikachu");     if (!hwnd) hwnd=FindWindow(L"ThunderRT5Form", L"³s³s¬Ý2");     if (!hwnd) hwnd=FindWindow(L"ThunderRT5Form", L"Pikachu");     return hwnd;}void FixGameBug(){    HWND hwnd=FindGameWindow();    if (hwnd)    {        DWORD pid;        char temp=0xC3;        GetWindowThreadProcessId(hwnd,&pid);        HANDLE handle=OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_OPERATION|PROCESS_VM_WRITE,FALSE,pid);        int *address=(int*)0x4B30D0;        WriteProcessMemory(handle,address,&temp,sizeof(temp),0);        }}
    <font color="Red">II. Sửa đổi màu nền khi chơi

    trong quá trình tìm ra ma trận biểu diễn các con bài trên màn hình nền của form chính tôi phát hiện ra như sau :
    new game ở pikachu rồi , bật artmoney lên, tìm chế độ unknown value, interger 1 byte (để dò từng byte 1) trong khoảng dữ liệu tôi tính (lần trước thấy cả 3 biến cần thiết ở cái vùng đó, nên rõ ràng tôi vẫn khoanh vùng đó đề tìm kiếm rồi )
    lose game ở pikachu, new game mới rồi tìm lại các giá trị was changed
    lại lose game ở pikachu, new game mới rồi tìm lại các giá trị was changed
    lại lose game ở pikachu, new game mới rồi tìm lại các giá trị was changed
    .....
    ở lần thứ 3 tôi thấy cái ô này
    Mã nguồn PHP:
    004B6070  
    có giá trị thay đổi theo mỗi lượt chơi,
    thử thay đổi 1 phát
    thấy màu nền thay đổi luôn
    nghịch thêm tí thấy :
    ô này là ô màu nền, có giá trị từ 0 đến 5
    tương ứng với 6 màu khác nhau
    ==> code hack, tương tự như các code đã share ở trên thôi, chưa có gì đặc biệt cả



    Mã:
    HWND FindGameWindow(){    HWND hwnd=FindWindow(L"ThunderRT6FormDC", L"³s³s¬Ý2");     if (!hwnd) hwnd=FindWindow(L"ThunderRT6FormDC", L"Pikachu");     if (!hwnd) hwnd=FindWindow(L"ThunderRT5Form", L"³s³s¬Ý2");     if (!hwnd) hwnd=FindWindow(L"ThunderRT5Form", L"Pikachu");     return hwnd;}void SetGameBackground(int n){    HWND hwnd=FindGameWindow();    if (hwnd)    {        DWORD pid;        int temp=n%6;        GetWindowThreadProcessId(hwnd,&pid);        HANDLE handle=OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_OPERATION|PROCESS_VM_WRITE,FALSE,pid);        int *address=(int*)0x4B6070;        WriteProcessMemory(handle,address,&temp,sizeof(temp),0);        }}void ChangeGameBackground(){    HWND hwnd=FindGameWindow();    if (hwnd)    {        DWORD pid;        int temp=0;        GetWindowThreadProcessId(hwnd,&pid);        HANDLE handle=OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE,FALSE,pid);        int *address=(int*)0x4B6070;        ReadProcessMemory(handle,address,&temp,sizeof(temp),0);        temp+=1;        temp%=6;        WriteProcessMemory(handle,address,&temp,sizeof(temp),0);        }}

  3. #3
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Chap 6: Trainer Pikachu(Tổng hợp 5 chap-langman + Auto Pikachu-puss)</font></font>

    Những thứ chúng ta cần:
    0. Đã đọc và hiểu kỹ 5 chap do langman viết.
    1. Tạo 1 giao diện thuận tiện cho việc sử dụng.
    2. Địa chỉ biến thời gian: pTime ->Code đóng băng thời gian
    3. Địa chỉ biến điểm: pPoint ->Code tăng 100 điểm / 1 lần ăn
    4. Địa chỉ biến lượt đổi: pLife ->Code Vô hạn lượt đổi
    5. Địa chỉ số lượng con quái còn trên màn hình: pNumber -> Code Ăn 1 con win luôn trong màn hiện tại
    6. Địa chỉ số lượng quái vật khi vào màn chơi mới sẽ gán: pNumberConst ->Code Ăn 1 con win luôn vẫn có tác dụng trong các cửa tiếp theo
    7. Địa chỉ ma trận lưu các thông tin trạng thái về các con quái: pMap -> Code Ăn 2 con khác nhau
    8. Thuật toán tìm 2 con ăn được trên ma trận bản đồ -> Code tìm 2 con ăn
    9. Mở rộng thêm 1 chút phần 7 để viết 1 auto tự chơi pikachu theo lựa chọn Single/All (auto 1 màn / auto đến màn cuối).


    Những thứ chúng ta đã có (ai chưa hiểu đề nghị đọc lại kỹ 5 chap của langman):
    2. Địa chỉ biến thời gian: pTime=0x004B6084; ->Code đóng băng thời gian
    3. Địa chỉ biến điểm: pPoint=0x004B6088; ->Code tăng 100 điểm / 1 lần ăn
    4. Địa chỉ biến lượt đổi: pLife=0x004B60AA; ->Code Vô hạn lượt đổi

    Ok, bắt đầu thôi!

    Phần 0. Đã đọc và hiểu kỹ 5 chap do langman viết
    Cái này bạn nào chưa hiểu kỹ thì đọc lại nhé, rất quan trọng đấy.

    Phần 1. Tạo giao diện:


    Nhìn chung giao diện sẽ thế này:

    Ghi chú: 4 chức năng đầu tiên khi bấm sẽ thêm dấu * ở cuối tức là chức năng tương ứng đã được kích hoạt, bấm 1 lần nữa dấu * sẽ biến mất và chức năng tương ứng sẽ bị tắt


    Code giao diện:
    Mã:
    #include <windows.h>
    #include <string.h>
    
    #define BTN_FROZENTIME            1
    #define BTN_POINTEAT            2
    #define BTN_ULTIMATELIFE        3
    #define BTN_WIN                    4
    #define BTN_SAME                5
    #define BTN_CHEAT                6
    #define BTN_AUTO                7
    #define RAD_STATUSAUTOSINGLE    8
    #define RAD_STATUSAUTOALL        9
    
    
    //Khai bao ham
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    //Sau này sẽ viết thêm code khai báo hàm vào chỗ này
    
    //Khai bao dia chi cac pointer
    //Sau này sẽ viết thêm code khai báo pointer vào chỗ này
    
    
    //Khai bao cac bien
    //Sau này sẽ viết thêm code khai bao biến vào chỗ này
    
    
    //Cac thong tin ve cua so Pikachu
    static HWND hwin;
    static HANDLE hProcess;
    static DWORD pid;
    //Sau này sẽ viết thêm code khai báo thông tin cửa sổ pikachu vào chỗ này
    
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, PSTR szCmdLine, int iCmdShow)
    {
        static TCHAR szAppName[]=TEXT("Pikachu Trainer");
        HWND hwnd;
        MSG msg;
        WNDCLASS wndclass;
        
        wndclass.style=CS_HREDRAW|CS_VREDRAW;
        wndclass.lpfnWndProc=WndProc;
        wndclass.cbClsExtra=0;
        wndclass.cbWndExtra=0;
        wndclass.hInstance=hInstance;
        wndclass.hIcon=LoadIcon(NULL, IDI_APPLICATION);
        wndclass.hCursor=LoadCursor(NULL, IDC_ARROW);
        wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
        wndclass.lpszMenuName=NULL;
        wndclass.lpszClassName=szAppName;
        
        if (!RegisterClass(&wndclass))
        {
            MessageBox(NULL, TEXT("This program requires Windows NT"), szAppName, MB_ICONERROR);
            return 0;
        }
        
        
        hwnd=CreateWindow(szAppName, TEXT("Pikachu Trainer"),
                        WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU,
                        CW_USEDEFAULT,
                        CW_USEDEFAULT,
                        198,
                        350,
                        NULL,
                        NULL,
                        hInstance,
                        NULL);
                        
        ShowWindow(hwnd, iCmdShow);
        UpdateWindow(hwnd);
        
        while (GetMessage(&msg, NULL, 0, 0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        
        return msg.wParam;
    }
    
    
    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        HDC hdc;
        PAINTSTRUCT ps;
        
        static int cxChar, cyChar;
        
        static HWND hwndBtnFrozenTime, hwndBtnPointEat, hwndBtnUltimateLife, hwndBtnWin, hwndBtnCheat,
                     hwndBtnSame, hwndRadStatusAutoSingle, hwndRadStatusAutoAll, hwndBtnAuto;
        
        static char cPointEatStatus, cFrozenTimeStatus, cUltimateLifeStatus, cWinStatus, cAutoStatus;
        
        TCHAR t[100];
        
        HWND h;
        
    
        switch(message)
        {
            case WM_CREATE:
                cxChar = LOWORD (GetDialogBaseUnits ()) ;
                cyChar = HIWORD (GetDialogBaseUnits ()) ;
                
    
                cFrozenTimeStatus=0;
                hwndBtnFrozenTime = CreateWindow (TEXT("button"), 
                                       TEXT("Dong bang thoi gian"),
                                       WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
                                       cxChar, cyChar*1,
                                       22 * cxChar, 7 * cyChar / 4,
                                       hwnd, (HMENU) BTN_FROZENTIME,
                                       ((LPCREATESTRUCT) lParam)->hInstance, NULL);
                
                 
                 cPointEatStatus=0;
                 hwndBtnPointEat = CreateWindow (TEXT("button"), 
                                       TEXT("100 diem/1 lan an"),
                                       WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
                                       cxChar, cyChar*3,
                                       22 * cxChar, 7 * cyChar / 4,
                                       hwnd, (HMENU) BTN_POINTEAT,
                                       ((LPCREATESTRUCT) lParam)->hInstance, NULL);
                      
                      
                cUltimateLifeStatus=0;
                hwndBtnUltimateLife = CreateWindow (TEXT("button"), 
                                       TEXT("Vo han luot doi"),
                                       WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
                                       cxChar, cyChar*5,
                                       22 * cxChar, 7 * cyChar / 4,
                                       hwnd, (HMENU) BTN_ULTIMATELIFE,
                                       ((LPCREATESTRUCT) lParam)->hInstance, NULL);
                 
                cWinStatus=0;                   
                 hwndBtnWin = CreateWindow (TEXT("button"), 
                                       TEXT("An 1 con Win luon"),
                                       WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
                                       cxChar, cyChar*7,
                                       22 * cxChar, 7 * cyChar / 4,
                                       hwnd, (HMENU) BTN_WIN,
                                       ((LPCREATESTRUCT) lParam)->hInstance, NULL);
                                       
                 hwndBtnSame = CreateWindow (TEXT("button"), 
                                       TEXT("An lung tung"),
                                       WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
                                       cxChar, cyChar*9,
                                       22 * cxChar, 7 * cyChar / 4,
                                       hwnd, (HMENU) BTN_SAME,
                                       ((LPCREATESTRUCT) lParam)->hInstance, NULL);
                     
    
                   hwndBtnCheat = CreateWindow (TEXT("button"), 
                                       TEXT("Tim 2 con an"),
                                       WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
                                       cxChar, cyChar*11,
                                       22 * cxChar, 7 * cyChar / 4,
                                       hwnd, (HMENU) BTN_CHEAT,
                                       ((LPCREATESTRUCT) lParam)->hInstance, NULL);
    
    
                hwndBtnAuto = CreateWindow (TEXT("button"), 
                                       TEXT("Auto Pikachu"),
                                       WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
                                       cxChar, cyChar*13,
                                       22 * cxChar, 7 * cyChar / 4,
                                       hwnd, (HMENU) BTN_AUTO,
                                       ((LPCREATESTRUCT) lParam)->hInstance, NULL);
                
                hwndRadStatusAutoSingle = CreateWindow (TEXT("button"), 
                                       TEXT("Single"),
                                       WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON,
                                       cxChar, cyChar*15,
                                       10* cxChar, 7* cyChar / 4,
                                       hwnd, (HMENU) RAD_STATUSAUTOSINGLE,
                                       ((LPCREATESTRUCT) lParam)->hInstance, NULL);
                 SendMessage(hwndRadStatusAutoSingle, BM_SETCHECK, 1, 0);
                 cAutoStatus=0;
                                       
                 hwndRadStatusAutoAll = CreateWindow (TEXT("button"), 
                                       TEXT("All"),
                                       WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON,
                                       12*cxChar, cyChar*15,
                                       10 * cxChar, 7 * cyChar / 4,
                                       hwnd, (HMENU) RAD_STATUSAUTOALL,
                                       ((LPCREATESTRUCT) lParam)->hInstance, NULL);
                
                //Find Window Pikachu            
                hwin=FindWindow(TEXT("ThunderRT5Form"), TEXT("³s³s¬Ý2"));
                if (hwin==NULL){
                    MessageBox(NULL, TEXT("Ban phai bat pikachu len da."), TEXT("Error"), 0);
                    SendMessage(hwnd, WM_CLOSE, 16, 1);
                    return 0;
                }
                
                //Open Process Pikachu
                GetWindowThreadProcessId(hwin, &pid);
                hProcess=OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
                            
                //Find Client
                //Sau này sẽ viết thêm code vào chỗ này
                
                
                //Init some value
                //Sau này sẽ viết thêm code khởi tạo 1 số giá trị vào chỗ này
                
                
                return 0;
            
            case WM_PAINT:
                hdc=BeginPaint(hwnd, &ps);
                
                
                wsprintf(t, TEXT("Made by langman, puss"));
                TextOut(hdc, cxChar, cyChar*18, t, wcslen(t));
                
                EndPaint(hwnd, &ps);
                return 0;
                
            case WM_COMMAND:
                switch(LOWORD(wParam)){
                    case BTN_FROZENTIME:
                        //Sau này sẽ viết thêm code đóng băng vào chỗ này
                        
                        break;
                    case BTN_POINTEAT:
                        //Sau này sẽ viết thêm code ăn 100 điểm / 1 lần vào chỗ này
                        
                        break;
                    case BTN_ULTIMATELIFE:
                        //Sau này sẽ viết thêm code vô hạn lượt đổi vào chỗ này
                    
                        break;
                        
                    case BTN_WIN:
                        //Sau này sẽ viết thêm code ăn 1 con win luôn vào chỗ này
                        
                        break;
                    
                    case BTN_SAME:
                        //Sau này sẽ viết thêm code ăn 2 con khác nhau vào chỗ này
                        
                        break;
                        
                    case BTN_CHEAT:
                        //Sau này sẽ viết thêm code tìm 2 con ăn vào chỗ này
                        
                        break;
                    case BTN_AUTO:
                        //Sau này sẽ viết thêm code auto chơi pikachu vào chỗ này
                        break;
                    case RAD_STATUSAUTOSINGLE:
                        cAutoStatus=0;
                        break;
                    case RAD_STATUSAUTOALL:
                        cAutoStatus=1;
                        break;
                }
                return 0;
            
            case WM_DESTROY:
                PostQuitMessage(0);
                return 0;
        }
        
        return DefWindowProc(hwnd, message, wParam, lParam);
    }
    Ok, vậy là xong phần giao diện.

    Phần 2. Đóng băng thời gian:

    Trong chap đóng băng thời gian, bạn langman đã thay đổi như sau:
    Mã:
    fld điểm
        xử lý linh tinh
    fsave time
    như thế này rõ ràng là chả có biến nào bị thay đổi cả rồi, hờ hờ hờ hờ (vì thằng điểm được load nhưng ko được save, thằng time được save nhưng bên trên đó lại chưa load, đâm ra chả có gì thay đổi cả)
    Mình xin đính chính lại 1 chút.
    Thật ra là biến time vẫn bị thay đổi.
    Nguyên nhân thay đổi biến thời gian có thể tưởng tượng như sau:
    time=MAX_TIME-time*x;
    Làm theo cách của bạn langman thì sau khi sửa biểu thức trên sẽ thành:
    time=MAX_TIME-điểm*x; tức là nó fld điểm thay vào chỗ của time
    vì biến time tính theo giây, kiểu float lên sau vài giây sẽ to rất nhanh.
    Lúc mới chơi điểm thấp nên bạn hầu như không có cảm giác vạch thời gian chạy,
    nếu khi bạn chơi điểm cao cao 1 chút thì để ý thấy vạch thời gian có tụt đi 1 tí, đó là vì time vẫn bị trừ.

    Giải quyết trọn vẹn vấn đề này thế nào?
    1 cách rất đơn giản, ta sẽ sửa lại biểu thức thay đổi time thành:
    y=MAX_TIME-time*x; (y là 1 biến nào đấy)
    như vậy thì time chẳng bao giờ bị thay đổi cả, chỉ có biến y nào đó bị thay đổi thôi.
    Hơn nữa nếu làm theo cách này, code đóng băng sẽ đẹp hơn. Khi bạn đóng băng ở chỗ nào thì vạch thời gian sẽ dừng ngay tại chỗ đó.
    Và khi bạn tắt đóng băng thì thời gian sẽ chạy tiếp ở chỗ đã dừng.
    Vấn đề nan giải ở chỗ phải chọn ai là kẻ "đóng thế" cho time? Chọn lung tung có thể gay crash chương trình ấy chứ.


    Mở onllydbg ra nào, Ctrl+G tới địa chỉ mà langman đã tìm thấy là: 4B02C4 xem kiếm được gì không?
    Bạn sẽ thấy thế này:


    FLD DWORD PTR DS: [4B6084]
    FADD QWORD PTR SS: [EBP-80]
    FILD DWORD PTR SS:[EBP-14]
    MOV DWORD PTR SS:[EBP-14],EBX
    FSTP QWORD PTR SS:[EBP-88]
    FSUB QWORD PTR SS:[EBP-88]
    FSTP DWORD PTR DS:[4B6084]

    Hô hô, bạn thấy "diễn viên đóng thế" chúng ta cần tìm rồi chứ?
    Bạn để ý chỗ này nhé:
    FSTP QWORD PTR SS:[EBP-88]
    FSUB QWORD PTR SS:[EBP-88]
    FSTP DWORD PTR DS:[4B6084] //lưu điểm


    bạn còn nhớ cái biểu thức làm thay đổi thời gian phía trên không?
    time=MAX_TIME-time*x
    địa chỉ [EBP-88] có thể coi chính là thằng x trong biểu thức trên.
    vậy thì ta chỉ cần sửa lại thế này:
    FSTP DWORD PTR DS:[4B6084] thành FSTP DWORD PTR SS:[EBP-88]
    tức là biểu thức thay đổi thời gian sẽ thành:
    x=MAX_TIME-time*x;


    FSTP DWORD PTR DS:[4B6084] có mã hex là: D91D 84604B00
    FSTP DWORD PTR SS:[EBP-88] có mã hex là D99D 78FFFFFF


    Thời cơ tới rồi, mở code giao diện ra, tới phần Khai báo các pointer và khai báo địa chỉ chỗ đóng băng thời gian:
    Mã:
    const int pFrozenTime=0x004B02DF;
    Tiếp theo ta khai báo ngay 2 mảng 6 byte ở chỗ khai báo biến:
    Mã:
    static unsigned char arrUnFrozenTime[6]={0xd9, 0x1d, 0x84, 0x60, 0x4b, 0x00};
    static unsigned char arrFrozenTime[6]={0xd9, 0x9d, 0x78, 0xff, 0xff, 0xff};
    Tới chỗ "Sau này sẽ viết thêm code đóng băng vào chỗ này" và viết thôi!
    Mã:
    if (cFrozenTimeStatus==0){
        WriteProcessMemory(hProcess, (int *)pFrozenTime, arrFrozenTime, 6*sizeof(char), NULL);
        SetWindowText(hwndBtnFrozenTime, TEXT("Dong bang thoi gian *"));
    }
    else{
        WriteProcessMemory(hProcess, (int *)pFrozenTime, arrUnFrozenTime, 6*sizeof(char), NULL);
        SetWindowText(hwndBtnFrozenTime, TEXT("Dong bang thoi gian"));
    }
    cFrozenTimeStatus=1-cFrozenTimeStatus;
    Ok men, vậy là đã chạy ngon!


    Phần 3. 100 điểm/1 lần ăn:


    Theo chap hack điểm của langman, chúng ta đã có được địa chỉ của biến điểm là 1 số thức 4 byte
    Địa chỉ của biến điểm là: pPoint=0x004B6088;
    Làm thế nào để mỗi khi ăn ta được cộng thêm 100 điểm chứ không phải 20 điểm như bình thường?
    theo kinh nghiệm của bạn langman trong chương đóng băng thời gian, mình đoán đoạn code khi ăn điểm sẽ được tăng lên thế này:

    Mã:
    FLD điểm
        cộng thêm vào điểm 20
    FSTP điểm
    bắt tay vào tìm luôn, vào onllydbg, bấm nút home cho nó về đầu entry, bấm ctrl+b, chọn dòng HEX, gõ vào chuỗi 88604B00 chọn forward và Search


    Search khoảng 3~5 lần gì đó, bạn sẽ tới được chỗ này:


    Bạn có nhìn rõ cái gì kia không??? FLOAT -20.00000, 1 số thực có giá trị là -20.00000!!!!
    Haha, hóa ra là mỗi lần ta ăn 2 con, nó sẽ trừ vào số điểm của ta -20 điểm,
    chứ không phải cộng thêm 20 điểm như ta vẫn nghĩ.
    Xem kỹ dòng lệnh tại đây nào:
    Mã:
    004b0829    d825 5c104000    FSUB DWORD PTR DS:[40105C]    FLOAT -20.00000
    vậy có nghĩa là địa chỉ 40105c chính là nơi lưu con số -20.00000 yêu quí của chúng ta.

    Làm luôn xem sao?
    Mở code, tới phần khai báo pointer và thêm đoạn sau:
    Mã:
    const int pPointEat=0x0040105C;
    Tới phần khai báo biến và thêm đoạn này:
    Mã:
    static float fPointEat;
    Tới phần "Sau này sẽ viết thêm code ăn 100 điểm / 1 lần vào chỗ này" và viết
    Mã:
    if (cPointEatStatus==0){
        fPointEat=-100;
        SetWindowText(hwndBtnPointEat, TEXT("100 diem/1 lan an *"));
    }
    else{
        fPointEat=-20;
        SetWindowText(hwndBtnPointEat, TEXT("100 diem/1 lan an"));
    }
    
    cPointEatStatus=1-cPointEatStatus;
    WriteProcessMemory(hProcess, (int *)pPointEat, &fPointEat, sizeof(float), NULL);

    Phần 4. Vô hạn lượt đổi:


    Theo chap vô hạn lượt đổi của langman, ta có địa chỉ của biến lượt đổi là: pLife=0x004B60AA;
    Bạn langman đã set lại giá trị của ô lượt đổi để chúng ta có nhiều lượt đổi hơn.

    Hi, giờ mình sẽ nghĩ ra 1 trò chơi mới với cái ô địa chỉ điểm này.
    Mình sẽ làm cho mỗi khi không còn con nào ăn trên bản đồ, chương trình sẽ đổi sang bàn mới, nhưng không bị trừ lượt đổi nào cả.
    Hehe, làm thế này thì dù bạn chỉ còn 1 lượt đổi thì cũng chẳng bao giờ bị hết cả.
    Bắt tay vào làm nên hạnh phúc nào!

    Trước tiên tìm hiểu kỹ về "kẻ địch" một chút:
    địa chỉ ô lượt đổi là: pLife=0x004B60AA;
    giá trị tại ô lượt đổi là 1 số nguyên có dấu 2byte, vậy ta có thể set giá trị tối đa cho lượt đổi là 2^(16-1) = 32.768;
    Mỗi lần hết con ăn, chương trình sẽ chuyển sang bàn mới và trừ vào lượt đổi 1 lần.

    Tình hình đoạn code sẽ có dạng thế này:
    Mã:
    Hết con ăn, đổi sang bàn mới:
        Khởi tạo lại bản đồ mới
        Trừ 1 lần vào biến đổi
        ...
    Kết thúc
    Vào onnlydbg, bấm nút home về đầu, ctrl+b, vào ô hex và gõ: AA604B00, chọn forward, Search
    Lần này có vẻ vất vả quá, bấm Search tận 9 lần mình mới thấy chỗ này:


    Mã:
    MOV AX,WORD PTR DS:[4B60AA]    //Nó sẽ chuyển giá trị của biến lượt đổi vào thanh ghi AX (vì lượt đổi chỉ có 2 byte)
    XOR ECX,ECX
    PUSH EBX
    DEC AX        //Trừ thanh ghi AX đi 1
    .....
    MOV WORD PTR DS:[4B60AA],AX //Lưu lại giá trị thanh ghi AX vào địa chỉ 4B60AA
    Hihi, các bạn biết chúng ta phải làm gì rồi chứ?
    Ở chỗ DEC AX, chúng ta sẽ sửa lại thành NOP, NOP hết (tức là chương trình sẽ chẳng làm gì hết).
    Vậy là chẳng có cái gì bị thay đổi cả hehe.

    Mã:
    DEC AX có mã hex là 0x4866
    NOP NOP có mã hex là 0x9090
    Start Code:
    Tới phần khai báo các pointer và thêm dòng này:
    Mã:
    const int pLifeSub=0x004B0FB8;
    Tới phần khai báo biến:
    Mã:
    static unsigned short int vFirst=0x4866;
    static unsigned short int vChange=0x9090;
    Tới phần "Sau này sẽ viết thêm code vô hạn lượt đổi vào chỗ này":
    Mã:
    if (cUltimateLifeStatus==0){
        WriteProcessMemory(hProcess, (int *)pLifeSub, &vChange, sizeof(vChange), NULL);
        SetWindowText(hwndBtnUltimateLife, TEXT("Vo han luot doi *"));
    }
    else{
        WriteProcessMemory(hProcess, (int *)pLifeSub, &vFirst, sizeof(vFirst), NULL);
        SetWindowText(hwndBtnFrozenTime, TEXT("Vo han luot doi"));
    }
    cUltimateLifeStatus=1-cUltimateLifeStatus;
    Xong, phần tiếp theo...

    <font size="4">Phần 5. Ăn 1 con win luôn (chỉ có tác dụng trong 1 cửa):


    Mở pikachu lên, các bạn thấy ngay pikachu có một bản đồ gồm 9 hàng và 16 cột.
    Suy ra tổng cộng có tất cả 9*16=144 hình quái vật.
    Suy ra biến lưu số lượng quái vật có khả năng sẽ là byte.
    Mở artMoney lên, Search kiểu 1 byte giá trị 144.
    Vào pikachu ăn 2 con, rồi ra ArtMoney scan 142.
    Tiếp theo ăn 2 con nữa, rồi ra ArtMoney scan 140.
    ....
    Làm 2~3 lần các bạn sẽ có được địa chỉ số lượng con quái còn trên màn hình: pNumber=0x004B6078;
    Tới đây các bạn chỉ cần set giá trị tại ô nhớ pNumber thành 2, rồi ăn 1 con nữa là sẽ Win luôn.
    Nhưng làm như thế này, nó sẽ chỉ có tác dụng trong 1 màn đang chơi.
    Nếu đổi sang màn sau, lại phải chỉnh giá trị tại pNumber thành 2 thì mới có tác dụng.
    Mình muốn khi nào tắt đi thì nó mới hết cơ...

    Cần phải tìm ra gốc rễ của vấn đề thôi.

    <font color="Red">Phần 6. Ăn 1 con win luôn (khi nào tắt thì mới hết):



    Khi vào 1 màn chơi mới hoặc khi bạn qua cửa, giá trị tại địa chỉ pNumber sẽ được gán bằng 144.
    Vậy ta cần phải tìm ra nơi chứa con số 144 đó, và sửa nó lại thành số 2.
    Vậy là bất cứ khi nào ta bắt đầu trò chơi mới, hoặc khi qua cửa thì giá trị tại địa chỉ
    pNumber sẽ tự được gán bằng 2, và ta chỉ cần ăn 1 con là Win luôn.

    Vào OnllyDbg, Home, Ctrl+B, gõ vào ô Hex: 78604B00, Search.
    Ối dời ơi, mới Search có 1 phát đã thấy luôn cái này:


    Mã:
    MOV WORD PTR DS:[4B6078],90
    90 trọng hệ 16 đổi sang hệ 10 vừa bằng 144
    quá đẹp, ta chỉ cẩn sửa con số 90 này thành số 2 là ok!

    Bắt tay vào viết code Ăn 1 con win luôn!

    Thêm cái này vào chỗ khai báo pointer:
    Mã:
    const int pNumber=0x004B6078;
    const int pNumberConst=0x004A8866;
    Thêm cái này vào chỗ khai báo biến:
    Mã:
    static unsigned char cNumber;
    static unsigned char cNumberConst;
    Tới chỗ: "Sau này sẽ viết thêm code ăn 1 con win luôn vào chỗ này"
    Mã:
    if (cWinStatus==0){
        cNumber=2;
        WriteProcessMemory(hProcess, (int *)(pNumber), &cNumber, 1, NULL);
        cNumberConst=2;
        WriteProcessMemory(hProcess, (int *)(pNumberConst+7), &cNumberConst, 1, NULL);
        SetWindowText(hwndBtnWin, TEXT("An 1 con Win luon *"));
    }
    else{
        cNumberConst=144;
        WriteProcessMemory(hProcess, (int *)(pNumberConst+7), &cNumberConst, 1, NULL);
        SetWindowText(hwndBtnWin, TEXT("An 1 con Win luon"));
    }
    cWinStatus=1-cWinStatus;
    Vậy là hôm nay mình đã hướng dẫn các bạn làm 6 phần đầu tiên của Tut Trainer Pikachu.
    Còn 3 phần nữa khá dài và khó hơn 6 phần đầu 1 chút nên mấy hôm nữa rảnh mình sẽ post tiếp.
    Chúc các bạn vui vẻ!

    Upload luôn file code, nhé.


    Mã nguồn PHP:
    #include <windows.h>#include <string.h>#define BTN_FROZENTIME 1#define BTN_POINTEAT 2#define BTN_ULTIMATELIFE 3#define BTN_WIN 4#define BTN_SAME 5#define BTN_CHEAT 6#define BTN_AUTO 7#define RAD_STATUSAUTOSINGLE 8#define RAD_STATUSAUTOALL 9//Khai bao hamLRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);//Sau này s? vi?t thêm code khai báo hàm vào ch? này//Khai bao dia chi cac pointerconst int pFrozenTime=0x004B02DF;const int pPointEat=0x0040105C;const int pLifeSub=0x004B0FB8;//Sau này s? vi?t thêm code khai báo pointer vào ch? này//Gia tri tai cac pointer//Sau này s? vi?t thêm code khai báo giá tr? pointer vào ch? này//Khai bao cac bienstatic unsigned char arrUnFrozenTime[6]={0xd9, 0x1d, 0x84, 0x60, 0x4b, 0x00};static unsigned char arrFrozenTime[6]={0xd9, 0x9d, 0x78, 0xff, 0xff, 0xff};static float fPointEat;static unsigned short int vFirst=0x4866;static unsigned short int vChange=0x9090;//Sau này s? vi?t thêm code khai bao bi?n vào ch? này//Cac thong tin ve cua so Pikachustatic HANDLE hwin, hProcess;static DWORD pid;//Sau này s? vi?t thêm code khai báo thông tin c?a s? pikachu vào ch? nàyint WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, PSTR szCmdLine, int iCmdShow){ static TCHAR szAppName[]=TEXT("Pikachu Trainer"); HWND hwnd; MSG msg; WNDCLASS wndclass; wndclass.style=CS_HREDRAW|CS_VREDRAW; wndclass.lpfnWndProc=WndProc; wndclass.cbClsExtra=0; wndclass.cbWndExtra=0; wndclass.hInstance=hInstance; wndclass.hIcon=LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor=LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName=NULL; wndclass.lpszClassName=szAppName; if (!RegisterClass(&wndclass)) { MessageBox(NULL, TEXT("This program requires Windows NT"), szAppName, MB_ICONERROR); return 0; } hwnd=CreateWindow(szAppName, TEXT("Pikachu Trainer"), WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU, CW_USEDEFAULT, CW_USEDEFAULT, 198, 350, NULL, NULL, hInstance, NULL); ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam;}LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){ HDC hdc; PAINTSTRUCT ps; static int cxChar, cyChar; static HWND hwndBtnFrozenTime, hwndBtnPointEat, hwndBtnUltimateLife, hwndBtnWin, hwndBtnCheat, hwndBtnSame, hwndRadStatusAutoSingle, hwndRadStatusAutoAll, hwndBtnAuto; static char cPointEatStatus, cFrozenTimeStatus, cUltimateLifeStatus, cWinStatus, cAutoStatus; TCHAR t[100]; HWND h; switch(message) { case WM_CREATE: cxChar = LOWORD (GetDialogBaseUnits ()) ; cyChar = HIWORD (GetDialogBaseUnits ()) ; cFrozenTimeStatus=0; hwndBtnFrozenTime = CreateWindow (TEXT("button"), TEXT("Dong bang thoi gian"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, cxChar, cyChar*1, 22 * cxChar, 7 * cyChar / 4, hwnd, (HMENU) BTN_FROZENTIME, ((LPCREATESTRUCT) lParam)->hInstance, NULL); cPointEatStatus=0; hwndBtnPointEat = CreateWindow (TEXT("button"), TEXT("100 diem/1 lan an"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, cxChar, cyChar*3, 22 * cxChar, 7 * cyChar / 4, hwnd, (HMENU) BTN_POINTEAT, ((LPCREATESTRUCT) lParam)->hInstance, NULL); cUltimateLifeStatus=0; hwndBtnUltimateLife = CreateWindow (TEXT("button"), TEXT("Vo han luot doi"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, cxChar, cyChar*5, 22 * cxChar, 7 * cyChar / 4, hwnd, (HMENU) BTN_ULTIMATELIFE, ((LPCREATESTRUCT) lParam)->hInstance, NULL); cWinStatus=0; hwndBtnWin = CreateWindow (TEXT("button"), TEXT("An 1 con Win luon"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, cxChar, cyChar*7, 22 * cxChar, 7 * cyChar / 4, hwnd, (HMENU) BTN_WIN, ((LPCREATESTRUCT) lParam)->hInstance, NULL); hwndBtnSame = CreateWindow (TEXT("button"), TEXT("An lung tung"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, cxChar, cyChar*9, 22 * cxChar, 7 * cyChar / 4, hwnd, (HMENU) BTN_SAME, ((LPCREATESTRUCT) lParam)->hInstance, NULL); hwndBtnCheat = CreateWindow (TEXT("button"), TEXT("Tim 2 con an"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, cxChar, cyChar*11, 22 * cxChar, 7 * cyChar / 4, hwnd, (HMENU) BTN_CHEAT, ((LPCREATESTRUCT) lParam)->hInstance, NULL); hwndBtnAuto = CreateWindow (TEXT("button"), TEXT("Auto Pikachu"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, cxChar, cyChar*13, 22 * cxChar, 7 * cyChar / 4, hwnd, (HMENU) BTN_AUTO, ((LPCREATESTRUCT) lParam)->hInstance, NULL); hwndRadStatusAutoSingle = CreateWindow (TEXT("button"), TEXT("Single"), WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON, cxChar, cyChar*15, 10* cxChar, 7* cyChar / 4, hwnd, (HMENU) RAD_STATUSAUTOSINGLE, ((LPCREATESTRUCT) lParam)->hInstance, NULL); SendMessage(hwndRadStatusAutoSingle, BM_SETCHECK, 1, 0); cAutoStatus=0; hwndRadStatusAutoAll = CreateWindow (TEXT("button"), TEXT("All"), WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON, 12*cxChar, cyChar*15, 10 * cxChar, 7 * cyChar / 4, hwnd, (HMENU) RAD_STATUSAUTOALL, ((LPCREATESTRUCT) lParam)->hInstance, NULL); //Find Window Pikachu hwin=FindWindow(TEXT("ThunderRT5Form"), TEXT("³s³s¬Ý2")); if (hwin==NULL){ MessageBox(NULL, TEXT("Ban phai bat pikachu len da."), TEXT("Error"), 0); SendMessage(hwnd, WM_CLOSE, 16, 1); return 0; } //Open Process Pikachu GetWindowThreadProcessId(hwin, &pid); hProcess=OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); //Find Client //Sau này s? vi?t thêm code vào ch? này //Init some value //Sau này s? vi?t thêm code kh?i t?o 1 s? giá tr? vào ch? này return 0; case WM_PAINT: hdc=BeginPaint(hwnd, &ps); wsprintf(t, TEXT("Made by langman, puss")); TextOut(hdc, cxChar, cyChar*18, t, wcslen(t)); EndPaint(hwnd, &ps); return 0; case WM_COMMAND: switch(LOWORD(wParam)){ case BTN_FROZENTIME: //Sau này s? vi?t thêm code dóng bang vào ch? này if (cFrozenTimeStatus==0){ WriteProcessMemory(hProcess, (int *)pFrozenTime, arrFrozenTime, 6*sizeof(char), NULL); SetWindowText(hwndBtnFrozenTime, TEXT("Dong bang thoi gian *")); } else{ WriteProcessMemory(hProcess, (int *)pFrozenTime, arrUnFrozenTime, 6*sizeof(char), NULL); SetWindowText(hwndBtnFrozenTime, TEXT("Dong bang thoi gian")); } cFrozenTimeStatus=1-cFrozenTimeStatus; break; case BTN_POINTEAT: //Sau này s? vi?t thêm code an 100 di?m / 1 l?n vào ch? này if (cPointEatStatus==0){ fPointEat=-100; SetWindowText(hwndBtnPointEat, TEXT("100 diem/1 lan an *")); } else{ fPointEat=-20; SetWindowText(hwndBtnPointEat, TEXT("100 diem/1 lan an")); } cPointEatStatus=1-cPointEatStatus; WriteProcessMemory(hProcess, (int *)pPointEat, &fPointEat, sizeof(float), NULL); break; case BTN_ULTIMATELIFE: //Sau này s? vi?t thêm code vô h?n lu?t d?i vào ch? này if (cUltimateLifeStatus==0){ WriteProcessMemory(hProcess, (int *)pLifeSub, &vChange, sizeof(vChange), NULL); SetWindowText(hwndBtnUltimateLife, TEXT("Vo han luot doi *")); } else{ WriteProcessMemory(hProcess, (int *)pLifeSub, &vFirst, sizeof(vFirst), NULL); SetWindowText(hwndBtnFrozenTime, TEXT("Vo han luot doi")); } cUltimateLifeStatus=1-cUltimateLifeStatus; break; case BTN_WIN: //Sau này s? vi?t thêm code an 1 con win luôn vào ch? này break; case BTN_SAME: //Sau này s? vi?t thêm code an 2 con khác nhau vào ch? này break; case BTN_CHEAT: //Sau này s? vi?t thêm code tìm 2 con an vào ch? này break; case BTN_AUTO: //Sau này s? vi?t thêm code auto choi pikachu vào ch? này break; case RAD_STATUSAUTOSINGLE: cAutoStatus=0; break; case RAD_STATUSAUTOALL: cAutoStatus=1; break; } return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam);}  

  4. #4
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    CHAP 6: Pikachu Trainer(Phần 7 tìm địa chỉ ma trận lưu các con quái)

    Công cụ: vào trang này http://www.cheatengine.org/ và download cheat engine về.
    Sau đó setup, mở cheat engine lên:
    Vào ô settings, chọn tab Extra, đánh dấu vào 2 ô:
    Query memory region routines
    Read/Write Process Memory (Will cause slower scans)

    Xong phần settings, giờ ta mở pikachu lên, vào màn chơi mới.
    Chúng ta sẽ cố gắng scan ra địa chỉ lưu con quái của ô đầu tiên bên trái.
    Bước 1:
    Vào Cheat Engine, mở process Pikachu và tiến hành scan như sau:
    Scan type: Unknown initial value
    Value type: Byte
    Sau đó chọn First Scan.


    Bước 2:
    Vào pikachu, chọn new game để pikachu load map khác.
    Nếu ô đầu tiên bên trái khác lần scan trước, ta chọn Scan type: Changed value
    Nếu ô đầu tiên bên trái giống lần scan trước, ta chọn Scan type: Unchanged value
    Nếu ô đầu tiên bên trái giống với lần scan đầu tiên ở bước 1, ta chọn Scan type: Same as first scan

    Bước 3:
    Lặp lại bước 2 cho tới khi nào chỉ còn 2~3 giá trị thì dừng.

    Xem ra khá vất vả để tìm được nó. Có lẽ phải scan tới cả trăm lần mất.
    Vì vậy mình sẽ cung cấp 1 vài kết quả do mình đã scan ra để giúp các bạn scan nhanh hơn.
    Sau đây là trị cụ thể của 1 vài con quái:


    Khi bạn thấy các hình vẽ này thì hãy chọn scan type: Extract Value
    và gõ vào giá trị tương ứng với hình vẽ.
    Sau vài lần scan, bạn sẽ tìm được 2 địa chỉ như này:

    Chú ý: Có thể địa chỉ 2 ô nhớ trên máy bạn sẽ khác trong hình vẽ vì đây là Dynamic Address.

    Chúng ta thử sửa đổi lại 1 chút xem ý nghĩa của từng địa chỉ này là gì?
    Bạn thay đổi giá trị thứ 1, hình vẽ trong pikachu cũng sẽ thay đổi theo. Bạn thay đổi thành hình giống hình bên cạnh, và ăn thử xem sao?
    Hic, không ăn được rồi! Suy ra đây chỉ là nơi lưu con quái hiển thị ra màn hình thôi. Với chúng ta thì không có ý nghĩa lắm.
    Tiếp theo, thay đổi giá trị thứ 2, bạn ko thấy pikachu có gì thay đổi cả. Nhưng nếu bạn đổi thành giá trị giống hình vẽ bên cạnh sẽ ăn được mặc dù hình vẽ hiển thị 2 con khác nhau.
    Suy ra đây là nơi lưu giá trị thật sự của con quái (đây mới là cái chúng ta cần).

    Nếu muốn bấm vào 2 con khác nhau nhưng vẫn ăn được, chúng ta chỉ cần đặt lại giá trị của tất cả con quái bằng 1 số là ok!
    Nhưng hãy tạm gác chuyện này sang 1 bên đã, chúng ta còn 1 số việc cần phải giải quyết trước.

    Chúng ta thử xem xung quanh địa chỉ này còn có gì hay ho nữa không?
    Chọn địa chỉ đầu tiên, click phải vào và chọn dòng: "Browse this memory region"


    Nó sẽ hiện thị ra 1 cửa sổ mới chứa memory xung quanh cái địa chỉ của chúng ta:


    Các bạn đễ ý kỹ mấy cái ô vuông màu đỏ mình tô đậm nhé:
    Mỗi ô vuông màu đỏ mình tô gồm 6 byte:
    FF FF 18 00 18 00

    Các bạn sẽ không mất nhiều thời gian để biết ý nghĩa của 6 byte này là gì, mình xin giải thích luôn:
    2 byte đầu: FF FF lưu ô hiện tại có hiển thị trên màn hình hay không? (FF FF là hiển thị, 00 00 là biến mất)
    2 byte tiếp theo: 18 00 lưu hình vẽ ra ngoài màn hình (chú ý đây chỉ là hình vẽ hiển thị thôi nhé)
    2 byte cuối cùng: 18 00 lưu mã số của con quái, 2 con chỉ ăn được khi có mã này giống nhau.
    Như vậy, mỗi con quái sẽ được lưu bởi 6 byte.

    Bản đồ bao trò chơi bao gồm 9 hàng và 16 cột, số con quái trên bản đồ là: 16*9=144 con
    Suy ra để lưu hết thông tin bản đồ, cần 1 ma trận như này: map[9][16].

    Chúng ta thử tính địa chỉ của con quái cuối cùng trong bản đồ xem có đúng không?
    địa chỉ con quái cuối cùng = địa chỉ con quái đầu tiên + 144*6
    địa chỉ con quái cuối cùng = địa chỉ con quái đầu tiên + 864

    vào Cheat Engine, bấm vào nút Add address manually:
    gõ vào địa chỉ con quái cuối cùng bạn vừa tính được, chọn Type: byte và Ok
    Bùm, ta có ô nhớ của con quái cuối cùng trên bản đồ.
    Thử thay đổi hình ảnh hiển thị xem nó có thay đổi không?
    Ồ, có cái gì đó không đúng lắm, cái thay đổi trong pikachu không phải là con quái cuối cùng.
    Mà là con quái đầu tiên ở hàng cuối cùng.
    Sao lại vậy nhỉ? Chúng ta đã tính sai ư?

    Cần phải nhìn nhận lại một chút. Theo những kinh nghiệm mình đã từng được biết, khi xử lý
    phần tử biên của ma trận, người ta rất hay dùng một kỹ thuật gọi là "lính canh".
    Tức là một ma trận map[9][16] phần tử thì họ thường khai báo thành map[9+2][16+2]
    Hai hàng và hai cột thừa sẽ dùng để ghi những giá trị đặc biệt, xác định đó là ngoài biên.
    Khi khai báo như vậy, việc xác định các phần tử ngoài biên rất đơn giản.
    Ok, chúng ta thử tính theo cách này xem sao?
    Như vậy công thức tính địa chỉ cuối cùng sẽ = địa chỉ con quái đầu tiên + (16+7*18+17)*6 (hàng đầu tiên còn 16 con, 7 hàng tiếp theo có 18 con, hàng cuối có 17 con)
    Địa chỉ con quái cuối cùng = địa chỉ con quái đầu tiên + 954

    Vào cheat engine và add address manually, thêm địa chỉ vừa tính được vào.
    Ta thử thay đổi xem thế nào? Oh hô hô, đã thành công!
    Vậy ta sẽ có một ma trận bản đồ là map[11][18] phần tử

    Kết thúc vấn đề về cách lưu trữ thông tin bản đồ trong trò pikachu.

    Bây giờ chúng ta sẽ giải quyết một vấn đề quan trọng nữa, đó là địa chỉ con quái đầu tiên chỉ là Dynamic Address
    Có nghĩa là nó sẽ bị thay đổi nếu ta tắt game đi và bật lại.
    Như này thật là không hay tí nào!
    Chúng ta cần phải tìm ra cái pointer của ma trận bản đồ này.

    Vào Cheat Engine, chọn địa chỉ lưu thông tin con quái đầu tiên, click phải và chọn dòng "Find out what accesses this address"
    Nó sẽ attach debugger vào, bạn chọn yes.
    Sau đó nó sẽ hiện ra 1 bảng như này:


    Bạn chọn lần lượt vào từng dòng kết quả, sau đó bấm nút More Information.
    Nếu thấy hiện lên dòng chữ: "The value of the pointer needed to find this address is probably..."


    Chú ý: Các con số trên hình vẽ có thể sẽ khác với máy của bạn.
    Tức là đây có khả năng là địa chỉ của pointer trỏ tới địa chỉ của bản đồ.

    Ok, bạn ghi lại mấy con số trong chỗ ...., sau đó Scan như sau:
    tick vào ô Hex, gõ mấy con số vừa ghi lại vào đây.
    Scan type: Extract Value
    Value Type: 4byte

    Ok, bạn sẽ tìm được 1 cái địa chỉ màu xanh lá cây, với address là: 004B6044 (xanh lá cây là địa chỉ static)
    Vào caculator, chọn hex và tính toán:
    lấy địa chỉ của ô nhớ đầu tiên trừ đi giá trị trong ô địa chỉ 004B6044, ta sẽ có offset.

    Và đây là kết quả tính toán của mình:
    Địa chỉ Mã của con quái đầu tiên = Giá trị tại ô nhớ 004B6044 + Offset=0x74
    Trạng thái của con quái đầu tiên = Giá trị tại ô nhớ 004B6044 + Offset=0x72

    Ok, đây chính là 2 thứ quan trọng nhất chúng ta cần.

    Chúng ta sẽ viết code ăn 2 con khác nhau nhé!
    Bắt tay vào viết code nào.

    Thêm cái này vào phần khai báo hàm:
    Mã:
    void Same();
    Vào vào phần khai báo pointer:
    Mã:
    const int ppMap=0x004B6044;
    static int pSame;
    static int pStatus;
    Vào vào phần khai báo biến:
    Mã:
    static unsigned char cSame=0;
    Tới chỗ "Sau này sẽ viết thêm code khởi tạo 1 số giá trị vào chỗ này"
    Mã:
    ReadProcessMemory(hProcess, (int *)ppMap, &pSame, sizeof(int), NULL);
    pSame+=0x74;
    ReadProcessMemory(hProcess, (int *)ppMap, &pStatus, sizeof(int), NULL);
    pStatus+=0x72;
    Tới phần "Sau này sẽ viết thêm code ăn 2 con khác nhau vào chỗ này":
    Mã:
    Same();
    SetWindowText(hwndBtnSame, TEXT("An lung tung *"));
    Xuống cuối file và viết thêm hàm
    Mã:
    void Same()
    {
        int i, j, k;
        
        k=0;
        for (i=0; i<9; i++)
        {
            for (j=0; j<16; j++)
            {
                WriteProcessMemory(hProcess, (int *)(pSame+(16*i+j+k)*6+2), &cSame, 1, NULL);
            }
            k+=2;
        }
    }
    Ok, vậy là xong phần ăn lung tung. Mấy hôm nữa rảnh mình sẽ post tiếp phần 8 và 9. Chúc mọi người 20/10 vui vẻ!

    Code đầy đủ cho tới giờ phút này:

    Mã nguồn PHP:
    #include <windows.h>#include <string.h>#define BTN_FROZENTIME 1#define BTN_POINTEAT 2#define BTN_ULTIMATELIFE 3#define BTN_WIN 4#define BTN_SAME 5#define BTN_CHEAT 6#define BTN_AUTO 7#define RAD_STATUSAUTOSINGLE 8#define RAD_STATUSAUTOALL 9//Khai bao hamLRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);void Same();//Sau này s? vi?t thêm code khai báo hàm vào ch? này//Khai bao dia chi cac pointerconst int pFrozenTime=0x004B02DF;const int pPointEat=0x0040105C;const int pLifeSub=0x004B0FB8;const int pNumber=0x004B6078;const int pNumberConst=0x004A8866;const int ppMap=0x004B6044;static int pSame;static int pStatus;//Sau này s? vi?t thêm code khai báo pointer vào ch? này//Khai bao cac bienstatic unsigned char arrUnFrozenTime[6]={0xd9, 0x1d, 0x84, 0x60, 0x4b, 0x00};static unsigned char arrFrozenTime[6]={0xd9, 0x9d, 0x78, 0xff, 0xff, 0xff};static float fPointEat;static unsigned short int vFirst=0x4866;static unsigned short int vChange=0x9090;static unsigned char cNumber;static unsigned char cNumberConst;static unsigned char cSame=0;//Sau này s? vi?t thêm code khai bao bi?n vào ch? này//Cac thong tin ve cua so Pikachustatic HANDLE hwin, hProcess;static DWORD pid;//Sau này s? vi?t thêm code khai báo thông tin c?a s? pikachu vào ch? nàyint WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, PSTR szCmdLine, int iCmdShow){ static TCHAR szAppName[]=TEXT("Pikachu Trainer"); HWND hwnd; MSG msg; WNDCLASS wndclass; wndclass.style=CS_HREDRAW|CS_VREDRAW; wndclass.lpfnWndProc=WndProc; wndclass.cbClsExtra=0; wndclass.cbWndExtra=0; wndclass.hInstance=hInstance; wndclass.hIcon=LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor=LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName=NULL; wndclass.lpszClassName=szAppName; if (!RegisterClass(&wndclass)) { MessageBox(NULL, TEXT("This program requires Windows NT"), szAppName, MB_ICONERROR); return 0; } hwnd=CreateWindow(szAppName, TEXT("Pikachu Trainer"), WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU, CW_USEDEFAULT, CW_USEDEFAULT, 198, 350, NULL, NULL, hInstance, NULL); ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam;}LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){ HDC hdc; PAINTSTRUCT ps; static int cxChar, cyChar; static HWND hwndBtnFrozenTime, hwndBtnPointEat, hwndBtnUltimateLife, hwndBtnWin, hwndBtnCheat, hwndBtnSame, hwndRadStatusAutoSingle, hwndRadStatusAutoAll, hwndBtnAuto; static char cPointEatStatus, cFrozenTimeStatus, cUltimateLifeStatus, cWinStatus, cAutoStatus; TCHAR t[100]; HWND h; switch(message) { case WM_CREATE: cxChar = LOWORD (GetDialogBaseUnits ()) ; cyChar = HIWORD (GetDialogBaseUnits ()) ; cFrozenTimeStatus=0; hwndBtnFrozenTime = CreateWindow (TEXT("button"), TEXT("Dong bang thoi gian"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, cxChar, cyChar*1, 22 * cxChar, 7 * cyChar / 4, hwnd, (HMENU) BTN_FROZENTIME, ((LPCREATESTRUCT) lParam)->hInstance, NULL); cPointEatStatus=0; hwndBtnPointEat = CreateWindow (TEXT("button"), TEXT("100 diem/1 lan an"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, cxChar, cyChar*3, 22 * cxChar, 7 * cyChar / 4, hwnd, (HMENU) BTN_POINTEAT, ((LPCREATESTRUCT) lParam)->hInstance, NULL); cUltimateLifeStatus=0; hwndBtnUltimateLife = CreateWindow (TEXT("button"), TEXT("Vo han luot doi"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, cxChar, cyChar*5, 22 * cxChar, 7 * cyChar / 4, hwnd, (HMENU) BTN_ULTIMATELIFE, ((LPCREATESTRUCT) lParam)->hInstance, NULL); cWinStatus=0; hwndBtnWin = CreateWindow (TEXT("button"), TEXT("An 1 con Win luon"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, cxChar, cyChar*7, 22 * cxChar, 7 * cyChar / 4, hwnd, (HMENU) BTN_WIN, ((LPCREATESTRUCT) lParam)->hInstance, NULL); hwndBtnSame = CreateWindow (TEXT("button"), TEXT("An lung tung"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, cxChar, cyChar*9, 22 * cxChar, 7 * cyChar / 4, hwnd, (HMENU) BTN_SAME, ((LPCREATESTRUCT) lParam)->hInstance, NULL); hwndBtnCheat = CreateWindow (TEXT("button"), TEXT("Tim 2 con an"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, cxChar, cyChar*11, 22 * cxChar, 7 * cyChar / 4, hwnd, (HMENU) BTN_CHEAT, ((LPCREATESTRUCT) lParam)->hInstance, NULL); hwndBtnAuto = CreateWindow (TEXT("button"), TEXT("Auto Pikachu"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, cxChar, cyChar*13, 22 * cxChar, 7 * cyChar / 4, hwnd, (HMENU) BTN_AUTO, ((LPCREATESTRUCT) lParam)->hInstance, NULL); hwndRadStatusAutoSingle = CreateWindow (TEXT("button"), TEXT("Single"), WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON, cxChar, cyChar*15, 10* cxChar, 7* cyChar / 4, hwnd, (HMENU) RAD_STATUSAUTOSINGLE, ((LPCREATESTRUCT) lParam)->hInstance, NULL); SendMessage(hwndRadStatusAutoSingle, BM_SETCHECK, 1, 0); cAutoStatus=0; hwndRadStatusAutoAll = CreateWindow (TEXT("button"), TEXT("All"), WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON, 12*cxChar, cyChar*15, 10 * cxChar, 7 * cyChar / 4, hwnd, (HMENU) RAD_STATUSAUTOALL, ((LPCREATESTRUCT) lParam)->hInstance, NULL); //Find Window Pikachu hwin=FindWindow(TEXT("ThunderRT5Form"), TEXT("³s³s¬Ý2")); if (hwin==NULL){ MessageBox(NULL, TEXT("Ban phai bat pikachu len da."), TEXT("Error"), 0); SendMessage(hwnd, WM_CLOSE, 16, 1); return 0; } //Open Process Pikachu GetWindowThreadProcessId(hwin, &pid); hProcess=OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); //Find Client //Sau này s? vi?t thêm code vào ch? này //Init some value //Sau này s? vi?t thêm code kh?i t?o 1 s? giá tr? vào ch? này ReadProcessMemory(hProcess, (int *)ppMap, &pSame, sizeof(int), NULL); pSame+=0x74; ReadProcessMemory(hProcess, (int *)ppMap, &pStatus, sizeof(int), NULL); pStatus+=0x72; return 0; case WM_PAINT: hdc=BeginPaint(hwnd, &ps); wsprintf(t, TEXT("Made by langman, puss")); TextOut(hdc, cxChar, cyChar*18, t, strlen(t)); EndPaint(hwnd, &ps); return 0; case WM_COMMAND: switch(LOWORD(wParam)){ case BTN_FROZENTIME: //Sau này s? vi?t thêm code dóng bang vào ch? này if (cFrozenTimeStatus==0){ WriteProcessMemory(hProcess, (int *)pFrozenTime, arrFrozenTime, 6*sizeof(char), NULL); SetWindowText(hwndBtnFrozenTime, TEXT("Dong bang thoi gian *")); } else{ WriteProcessMemory(hProcess, (int *)pFrozenTime, arrUnFrozenTime, 6*sizeof(char), NULL); SetWindowText(hwndBtnFrozenTime, TEXT("Dong bang thoi gian")); } cFrozenTimeStatus=1-cFrozenTimeStatus; break; case BTN_POINTEAT: //Sau này s? vi?t thêm code an 100 di?m / 1 l?n vào ch? này if (cPointEatStatus==0){ fPointEat=-100; SetWindowText(hwndBtnPointEat, TEXT("100 diem/1 lan an *")); } else{ fPointEat=-20; SetWindowText(hwndBtnPointEat, TEXT("100 diem/1 lan an")); } cPointEatStatus=1-cPointEatStatus; WriteProcessMemory(hProcess, (int *)pPointEat, &fPointEat, sizeof(float), NULL); break; case BTN_ULTIMATELIFE: //Sau này s? vi?t thêm code vô h?n lu?t d?i vào ch? này if (cUltimateLifeStatus==0){ WriteProcessMemory(hProcess, (int *)pLifeSub, &vChange, sizeof(vChange), NULL); SetWindowText(hwndBtnUltimateLife, TEXT("Vo han luot doi *")); } else{ WriteProcessMemory(hProcess, (int *)pLifeSub, &vFirst, sizeof(vFirst), NULL); SetWindowText(hwndBtnFrozenTime, TEXT("Vo han luot doi")); } cUltimateLifeStatus=1-cUltimateLifeStatus; break; case BTN_WIN: //Sau này s? vi?t thêm code an 1 con win luôn vào ch? này if (cWinStatus==0){ cNumber=2; WriteProcessMemory(hProcess, (int *)(pNumber), &cNumber, 1, NULL); cNumberConst=2; WriteProcessMemory(hProcess, (int *)(pNumberConst+7), &cNumberConst, 1, NULL); SetWindowText(hwndBtnWin, TEXT("An 1 con Win luon *")); } else{ cNumberConst=144; WriteProcessMemory(hProcess, (int *)(pNumberConst+7), &cNumberConst, 1, NULL); SetWindowText(hwndBtnWin, TEXT("An 1 con Win luon")); } cWinStatus=1-cWinStatus; break; case BTN_SAME: //Sau này s? vi?t thêm code an 2 con khác nhau vào ch? này Same(); SetWindowText(hwndBtnSame, TEXT("An lung tung *")); break; case BTN_CHEAT: //Sau này s? vi?t thêm code tìm 2 con an vào ch? này break; case BTN_AUTO: //Sau này s? vi?t thêm code auto choi pikachu vào ch? này break; case RAD_STATUSAUTOSINGLE: cAutoStatus=0; break; case RAD_STATUSAUTOALL: cAutoStatus=1; break; } return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam);}void Same(){ int i, j, k; k=0; for (i=0; i<9; i++) { for (j=0; j<16; j++) { WriteProcessMemory(hProcess, (int *)(pSame+(16*i+j+k)*6+2), &cSame, 1, NULL); } k+=2; }}  

  5. #5
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Chap 6: Auto Pikachu (Phần 8: Tìm 2 con ăn)</font></font>
    Chào mọi người, mấy hôm vừa rồi mình bận quá, hôm nay mình sẽ post tiếp 2 phần cuối cùng.

    Phân tích bài toán:

    Để có thể tìm 2 con ăn, chúng ta cần:
    • Bản đồ lưu trạng thái quái trên màn hình (mã quái, trạng thái).Thuật toán tìm ra 2 con có thể ăn được trong bản đồ.Làm cho 2 con ăn được.

    Chúng ta sẽ thiết kế code tìm 2 con ăn như sau:
    • Đọc mã con quái và lưu vào 1 mảng.Đọc trạng thái con quái và lưu vào 1 mảng.Tìm địa chỉ 2 con ăn được.Bấm chuột vào 2 con vừa tìm được để ăn.


    Bắt tay vào vấn đề thôi!
    1. Bản đồ lưu trạng thái quái trên màn hình (mã quái, trạng thái).
    Cái này chúng ta đã đề tới ở phần 7, mình xin nhắc lại 1 chút.
    Pointer lưu bản đồ: 0x0040105C
    Offset 0x74: Lưu mã con quái đầu tiên.
    Offset 0x72: Lưu trang thái con quái đầu tiên(đã bị ăn hay là chưa bị ăn)

    Chúng ta sẽ viết 1 hàm để đọc bản đồ và lưu vào 1 mảng trong chương trình của chúng ta.

    Thêm cái này vào chỗ khai báo biến:
    Mã nguồn PHP:
    //chúng ta khai báo mảng 2 chiều gồm [11][18] để sử dụng kỹ thuật lính canh trong mảng.static unsigned char map[11][18]; //Mảng lưu mã con quáistatic unsigned short int status[11][18]; //Mảng lưu trạng thái con quái (đã ăn/chưa ăn)  
    Thêm cái này vào chỗ khai báo hàm:
    Mã nguồn PHP:
    void ReadMap(); //Hàm này sẽ đọc thông tin bản đồ (mã, trạng thái) vào 2 mảng trên.  
    Xuống cuối file code, gõ thêm hàm ReadMap như sau:
    Mã nguồn PHP:
    void ReadMap() { int i, j; for (i=0; i<11; i++){ for (j=0; j<18; j++){ ReadProcessMemory(hProcess, (int *)(pSame-19*6+(18*i+j)*6+2), &map[i][j], 1, NULL); ReadProcessMemory(hProcess, (int *)(pStatus-19*6+(18*i+j)*6), &status[i][j], 2, NULL); } } }  
    2. Thuật toán tìm 2 con ăn.


    Ý tưởng:
    Cần kiểm tra ô map[i1][j1] và ô map[i2][j2] xem có thể ăn được.
    Chúng ta sẽ thiết kế thuật duyệt toán như sau:


    Cho tọa độ [i1][j1] vào danh sách queue để duyệt.
    Trong khi chưa duyệt hết queue:
    nếu điểm queue đang xét = [i2][j2] thì return 1; (tức là [i1][j1] và [i2][j2] tồn tại đường đi)
    Tìm tất cả các ô theo 4 hướng và ô đó chưa duyệt qua và cho vào queue(các ô có số 1 như hình vẽ), nếu đã duyệt thì không cho vào queue.
    Với mỗi ô được cho vào queue, cập nhập số đường thẳng đã để đi tới ô này. Nếu số đường thẳng >3 thì bỏ qua không duyệt điểm này.

    Mình diễn đạt thuật toán hơi kém, mình sẽ comment thêm bên cạnh code để mọi người dễ hiểu hơn.

    Thêm vào chỗ khai báo hàm:
    Mã nguồn PHP:
    /* Hàm int checkPath(int i1, int j1, int i2, int j2); hàm trả về 0 nếu giũa con quái map[i1][j1] và map[i2][j2] không ăn được. hàm trả về 1 nếu giũa con quái map[i1][j1] và map[i2][j2] ăn được. */ int checkPath(int, int, int, int); /* Hàm myInside(int i, int j); hàm trả về 0 nếu i và j vượt ra khỏi chỉ số mảng (i<0 || i>11 || j<0 || j>18) hàm trả về 1 nếu i và j nằm trong mảng. */ int myInside(int, int);  
    Tiếp theo khai báo thêm 1 struct để lưu tọa độ các điểm sẽ duyệt

    Mã nguồn PHP:
    struct strtPoint{ int x, y;};typedef struct strtPoint point;  
    Xuống cuối file code và viết thêm các hàm sau:

    Mã nguồn PHP:
    int myInside(int i, int j) { if (i>=0 && i<11 && j>=0 && j<18) return 1; return 0; } int checkPath(int i1, int j1, int i2, int j2) { int fist, last, i, j, t; //fist, last: lưu điểm đầu và điểm cuối của queue. i, j lưu tọa độ điểm đang duyệt trong queue, t là biến lặp int UU[4]={0, 0, 1, -1};//UU: lưu độ lệch của điểm xét tiếp theo chiều x int VV[4]={1, -1, 0, 0};//VV: lưu độ lệch của điểm xét tiếp theo chiều y point queue[198]; //khai báo queue để lưu danh sách các điểm sẽ duyệt int cx[11][18]; //mảng này lưu trạng thái duyệt của ô [i][j]. Nếu chưa duyệt thì cx[i][j]=0, đã duyệt thì =1 int count[11][18]; //lưu số đường thẳng cần vẽ từ điểm [i1][j1] tới được điểm [i][j]. Theo luật trò chơi thì 2 con ăn được khi có giữa 2 con tồn tại 1 đoạn gồm 3 hoặc ít hơn các đường thẳng nối int canGo[4], p[4], q[4]; //CanGo[0] là hướng lên phía trên, nếu phía trên bị cản thì CanGo[0]=0; đi được thì CanGo[0]=1. 1, 2, 3 là các hướng còn lại // p và q lưu giá trị tạm thời if (i1==i2 && j1==j2) return 0;//kiểm tra nếu 2 ô trùng nhau thì thoát if (status[i1][j1]==0 || status[i2][j2]==0) return 0; /ếu 2 ô kiểm tra đều bị ăn hoặc ngoài biên thì thoát if (map[i1][j1]!=map[i2][j2]) return 0; /ếu 2 ô kiểm tra có mã khác nhau thì thoát fist=0; last=0; //khởi tạo queue queue[0].x=i1; queue[0].y=j1; //đưa i1, j1 vào queue để duyệt //Khởi tạo mảng lưu trạng thái các điểm duyệt. Ban đầu tất cả các điểm đều chưa được duyệt nên khởi tạo =0 for (i=0; i<11; i++) for (j=0; j<18; j++) { cx[i][j]=0; } cx[i1][j1]=1;//[i1][j1] đã được đưa vào queue nên gán cx[i1][j1]=1. count[i1][j1]=0;//Số đường thẳng từ [i1][j1] ban đầu là 0. while (fist<=last)//Trong khi chưa duyệt hết queue { i=queue[fist].x; j=queue[fist].y; fist++;//duyệt qua điểm đầu của queue, tăng fist lên 1 để duyệt điểm tiếp theo for (t=0; t<4; t++){ canGo[t]=1;//Ta coi tất cả các hướng đều có thể đi được p[t]=i; q[t]=j;//gán p[t], q[t] để lưu tạm giá trị, lát nữa sẽ tính ra tọa độ điểm duyệt tiếp theo } do{ for (t=0; t<4; t++){//duyệt theo 4 hướng if (canGo[t]){//Nếu hướng t có thể đi được p[t]+=UU[t];//tọa độ theo hướng x của điểm tiếp theo q[t]+=VV[t];//tọa độ theo hướng y của điểm tiếp theo if (!myInside(p[t], q[t])){//Nếu vượt ra khỏi bản đồ canGo[t]=0;//Hướng t không thể đi được nữa continue;//duyệt tiếp queue } if (p[t]==i2 && q[t]==j2){//Nếu điểm tiếp theo = [i2][j2] trả lại 1 return 1; } if (status[p[t]][q[t]]!=0){//Nếu điểm tiếp theo không đi được(vẫn còn hiện trên màn hình) canGo[t]=0;//Hướng t không thể đi được nữa continue;//duyệt tiếp queue } if (cx[p[t]][q[t]]) continue;/ếu điểm tiếp theo đã được đưa vào queue thì duyệt tiếp queue if (count[i][j]==2) continue;/ếu số đường thẳng tới điểm đang xét =2 thì duyệt tiếp queue(vì tới điểm đang xét =2, nếu cộng thêm điểm sắp đưa vào queue thì sẽ =3, không thỏa mãn luật trò chơi nên bị loại) last++;//Sau khi vượt qua các phép kiểm tra, tới đây thì điểm p[t], q[t] là hợp lệ và được đưa tiếp vào queue để duyệt queue[last].x=p[t]; queue[last].y=q[t]; cx[p[t]][q[t]]=1;//Đánh dấu điểm [p[t]][q[t]] đã được đưa vào queue count[p[t]][q[t]]=count[i][j]+1;//lưu số đường thẳng cần vẽ từ điểm [i1][j1] tới điểm [p[t]][q[t]] } } }while(canGo[0]||canGo[1]||canGo[2]||canGo[3]);// làm việc này khi 1 trong 4 hướng còn có thể đi được. Nếu cả 4 hướng không đi được thì thoát vòng lặp để duyệt tiếp queue } return 0; //duyệt hết queue vẫn chưa tìm ra đường thì trả lại 0 }  
    Vậy là xong phần nặng nề nhất, nhưng trước mặt còn rất nhiều khó khăn, hãy tiến lên nào!


    <font color="Blue">3. Làm cho 2 con ăn.


    Ở phần trên, mình đã viết thuật toán kiểm tra xem con ở ô [i1][j1] và con ở ô [i2][j2] có ăn được không.
    Giờ mình sẽ viết một hàm để duyệt các điểm trong map, tìm ra 2 con có thể ăn được và thực hiện thao tác click chuột để ăn 2 con.

    Thêm vào chỗ khai báo hàm:

    Mã nguồn PHP:
    void findCheat(); //hàm tìm ra 2 con ăn được và thực hiện bấm chuột để ăn 2 con.  
    Tới chỗ "Sau này sẽ viết thêm code khai báo thông tin cửa sổ pikachu vào chỗ này"
    và khai báo:

    Mã nguồn PHP:
    static HWND hwndClient;  
    Các bạn tìm tới đoạn comment này (ở trong thông điệp WM_CREATE):
    //Find Client
    //Sau này sẽ viết thêm code vào chỗ này
    và viết thêm code:

    Mã nguồn PHP:
    h=(HWND)0;//Biến h mình đã khai báo từ phần đầu lúc tạo giao diện. while (1){ h=FindWindowEx(hwin, h, TEXT("ThunderRT5PictureBox"), NULL);//Tìm HANDLE cửa sổ con của pikachu(đây mới là cửa sổ có thể thực hiện được click chuột) if (h==NULL) break; hwndClient=h; } //Mình dùng công cụ Spy++ trong bộ visual studio để tìm cửa sổ này, và biết nó là cửa số con cuối cùng.  
    Xuống cuối file và viết hàm này:

    Mã nguồn PHP:
    int findCheat() { int x1, y1, x2, y2, i, j; unsigned int xt, yt, lpa; //i, j là các biến đếm. //x1, y1: lưu tọa độ của điểm cần kiểm tra đầu tiên //x2, y2: lưu tọa độ của điểm cần kiểm tra thứ hai //xt, yt: lưu tọa độ điểm chuột cần click vào. //lpa: lParam, cái này để chuyển xt, yt vào làm đối số cho hàm SendMessage để giả click chuột ReadMap(); //Đọc bản đồ for (i=0; i<16*9-1; i++){//Chuyển mảng 2 chiều thành mảng 1 chiều để thuận tiện cho việc duyệt x1=i/16+1; y1=i%16+1;//Chuyển chỉ số i trong mảng 1 chiều thành tọa độ trong mảng 2 chiều if (status[x1][y1]==0) continue;//Nếu [x1][y1] không hiện trên màn hình thì ko duyệt for (j=i+1; j<16*9; j++){ x2=j/16+1; y2=j%16+1; if (status[x2][y2]==0) continue;//Nếu [x2][y2] không hiện trên màn hình thì không duyệt if (checkPath(x1, y1, x2, y2)){//kiểm tra giữa [x1][y1], [x2][y2] có ăn được không //Nếu ăn được SendMessage(hwndClient, WM_RBUTTONDOWN, 2, 0x004F0052);//Gửi thông điệp chuột phải được bấm(tránh tình trạng trước đó người dùng đã chọn 1 con nào đó) xt=82+(x1-1)*50;//Tính tọa độ x của ô [x1][y1] yt=82+(y1-1)*40;//Tính tọa độ y của ô [x2][y2] lpa=xt*0x10000+yt;//ép vào lpa SendMessage(hwndClient, WM_LBUTTONDOWN, 1, lpa);//Gửi thông điệp chuột trái được bấm ở tọa độ xt, yt(đã ép vào lpa). Sleep(500);//Ngủ 500 mili giây xt=82+(x2-1)*50;//Tính tọa độ x của ô [x2][y2] yt=82+(y2-1)*40;//Tính tọa độ y của ô [x2][y2] lpa=xt*0x10000+yt; SendMessage(hwndClient, WM_LBUTTONDOWN, 1, lpa); return 0; } } } return 0; }  
    Để có được công thức tính tọa độ bấm chuột, các bạn vào chơi pikachu, sau đó bấm Alt+PrtScr để chụp cửa sổ pikachu.
    Sau đó paste vào paint và phóng to để tínht tọa độ. Cái này không khó lắm.


    Chap 6: Auto Pikachu (Phần 9: Auto pikachu)
    Tới đây, chắc hẳn các bạn cũng hỉnh dung ra được cách viết chương trình auto rồi phải không?

    Vì vậy, <font color="Blue">phần 9 viết auto pikachu là phần thực hành của các bạn nhé.


    Mình xin upload code demo phần auto mà mình đã viết, bạn nào thấy khó viết thì tham khảo nhé.

    Tới chỗ khai báo hàm và khai báo:
    Mã nguồn PHP:
    void UpdateValue(); //Hàm update giá trịvoid AutoPikachu(HWND , int); //Hàm auto pikachu  
    Xuống cuối và viết thêm hai hàm này:

    Mã nguồn PHP:
    void UpdateValue(){ ReadMap(); ReadProcessMemory(hProcess, (int *)pNumber, &cNumber, 1, NULL);}void AutoPikachu(HWND hwnd, int cAutoStatus){ int x1, y1, x2, y2, i, j, x, y; unsigned int xt, yt, lpa; int found; unsigned int pLifeSub=0x4b0fb8; unsigned short int vFirst=0x4866, vChange=0x9090; HWND hwndDialog, hwndOk, h; SetFocus(hwin); WriteProcessMemory(hProcess, (int *)pLifeSub, &vChange, 2, NULL); ShowWindow(hwnd, HIDE_WINDOW); while (1){ UpdateValue(); found=0; if (cNumber==0){ if (cAutoStatus){ Sleep(700); hwndDialog=FindWindow(TEXT("#32770"), TEXT("??")); hwndOk=FindWindowEx(hwndDialog, 0, TEXT("Button"), TEXT("OK")); if (hwndOk!=NULL){ SendMessage(hwndOk, WM_LBUTTONDOWN, 1, 0x00030003); SendMessage(hwndOk, WM_LBUTTONUP, 1, 0x00030003); Sleep(500); } else{ WriteProcessMemory(hProcess, (int *)pLifeSub, &vFirst, 2, NULL); ShowWindow(hwnd, SHOW_OPENWINDOW); return; } } else{ WriteProcessMemory(hProcess, (int *)pLifeSub, &vFirst, 2, NULL); ShowWindow(hwnd, SHOW_OPENWINDOW); return; } } for (i=0; i<16*9-1; i++){ x1=i/16+1; y1=i%16+1; if (status[x1][y1]==0) continue; for (j=i+1; j<16*9; j++){ x2=j/16+1; y2=j%16+1; if (status[x2][y2]==0) continue; if (checkPath(x1, y1, x2, y2)){ SendMessage(hwndClient, WM_RBUTTONDOWN, 2, 0x004F0052); xt=82+(x1-1)*50; yt=82+(y1-1)*40; lpa=xt*0x10000+yt; SendMessage(hwndClient, WM_LBUTTONDOWN, 1, lpa); Sleep(300); xt=82+(x2-1)*50; yt=82+(y2-1)*40; lpa=xt*0x10000+yt; SendMessage(hwndClient, WM_LBUTTONDOWN, 1, lpa); Sleep(300); found=1; break; } } if (found) break; } }}  
    Download file Code: http://www.mediafire.com/?qz70mzd2ppkpi19
    Download file chạy: http://www.mediafire.com/?8f1rz3pyw149yga


    Các bạn có thể nâng cao phần này bằng cách tạo 1 thread auto, khi đó lúc nào bấm vào nút auto thì sẽ auto, bấm thêm lần nữa thì auto sẽ tắt.
    Nâng cao hơn nữa, các bạn có thể tự làm các phim tắt để trong khi chơi có thể thao tác dễ dàng hơn.

    Chúc các bạn vui vẻ với bài viết này!

  6. #6
    Ngày tham gia
    Sep 2015
    Bài viết
    0

    Hướng dẫn viết hack game (game trainer)

    Dẫn nhập
    Đối với các game thủ thì game trainer ko còn là 1 từ lạ lẫm nữa. Vậy làm thế nào để viết 1 game trainer ? Đây là 1 vấn đề mà ko ít bạn sinh viên quan tâm nhưng lại chưa tìm được điểm bắt đầu, vậy hôm nay langman cùng với chút kinh nghiệm nhỏ xíu học được từ cộng đồng c việt quyết định chia sẻ với các bạn 1 tut nhằm dẫn nhập các bạn đến với con đường tà đạo : hack game
    hj hj hj hja
    Bài viết có nguồn từ langman - Cộng Đồng C Việt
    Các file nén có pass là langman.congdongcviet


    <font color="Magenta">Ngày xưa cái này gọi là game trainer, bây giờ các gamer toàn gọi nhầm với hack tool, nên thôi langman cũng cứ gọi bừa là hack, mong các hacker đừng vì thế mà ghét langman


    Yêu cầu theo đuổi tut này
    Đây là 1 tut cực kì đơn giản, với các hình minh họa cụ thể, nên ko khó để các bạn làm quen . Nhưng yêu cầu là các bạn phải chịu khó mày mò, phải thích thật sự và 1 yêu cầu cũng ko kém phần quan trọng đó là : Nếu các bạn thấy tut này thật sự có ý nghĩa với bạn thì hãy để lại 1 vài câu reply có ý nghĩa


    Chap 1 : Pikachu
    Đây là 1 game có từ rất lâu rồi, cũng ko lạ lẫm gì với dân Việt Nam chúng ta nữa, con gái cũng biết chơi, vì thế langman sẽ cùng các bạn viết 1 cái trainer cho game này nhé
    Đầu tiên, nếu bạn chưa có pikachu thì download tại đây : Pokemon
    Do có nhiều sự khác nhau về OS: 7,XP,Vista nên chúng ta thống nhất download file này copy vào thư mục C:\windows\system32\ nhé (Trong windows 7 thì phải có file này mới chạy được pikachu, ở trong XP thì các bạn cũng cứ copy đè lên file cũ nhé, ko sao đâu, như thế thì chúng ta mới làm được theo cái tút này) : msvbvm5


    OK, chúng ta sẽ bắt đầu có 1 cái nhìn sơ bộ về pikachu :


    Game và cách chơi : chắc các bạn đã biết cả rồi



    Chúng ta sẽ tiến hành nghiên cứu 2 vấn về
    + Mod game, sửa đổi các thành phần trong game đi , lấy resource của game, thay resource,.......

    + Viết trainer với các option
    _ Tăng điểm của người chơi (add 1000 to game point)
    _ Tăng thêm thời gian ( set time bar to max time)
    _ Đóng băng thời gian ( unlimited time và infinite time)
    _ Vô hạn lượt đổi (unlimited continue)





    Chap 2 : Mod
    Load bằng Peid (chưa có load tại đây - full plugin và chạy được trên windows7) ta có kết quả như sau :





    Vậy là cái này được pack bằng ASPack 2.11 (vậy để hand mod thì chúng ta phải upack nó trước đã)
    Các bạn làm theo bước 1,2,3 như trong ảnh để lấy được OEP của app này là : 00401628

    Mình gà lắm, ko biết upack thế nào nên tạm dùng cái Qunpack (Chưa có download tại đây)này để unpack nó : chạy qunpack.exe với quyền admin (win7:chuột phải, vào dòng run as admin, XP:cứ bật lên là được), mở file pokemon ra (click vào nút Open File rồi trỏ đến file pokemon.exe), điền giá trị <font color="Red">OEP
    vào rồi click vào nut Full Unpack

    Muốn biết thêm OEP là gì thì xem ở đây :
    Portable Executable File Format


    Vậy là ta đã có được 1 file exe với ở dạng nguyên thể (tạm coi là thế) của game này. Ở đây tôi đặt tên file mới là Upokemon.exe

    Vậy đấy, sau khi unpack (và sau khi ăn 1 suất cơm ở ngoài tiệm) chúng ta thấy đã có sự khác nhiều rồi, ít nhất chúng ta đã thấy rõ ràng rằng cái pikachu này được viết bằng Microsoft Visual Basic , thấy link info là 4.20 hóa ra là Microsoft Visual Basic 5.0

    Sau khi đã unpack ta hoàn toàn có thể dùng Reshack (Chưa có download tại đây) để lấy, thay đổi, các tài nguyên về icon, âm thanh wave, âm thanh midi trong file này 1 cách cực kì đơn giản




    Ôi trời là VB à, nản quá cơ tớ ko thích VB lắm. Nhưng bình tĩnh nào, chúng ta đã lấy được âm thanh, icon rồi, còn các bitmap thì lại ko lấy được bằng Reshack, làm sao đây ???? Vậy ta đành phải Decompile nó ra xem như thế nào,
    ồ, sau 1 hồi tìm tìm, kiếm kiếm, trọc trọc. ngoáy ngoáy, tôi đã tìm ra mấy cái ảnh bitmap của nó bằng tool sau
    Mã nguồn PHP:
    http://www.mediafire.com/?h97gb8q9rb3eka1  
    Hướng dẫn Decompile : cũng run cái vbdecompile với quyền admin, mở file upokemon.exe ra, nó hỏi có unpack ko chọn no vì ta đã unpack rồi, nó rồi click vào nút decompile, để lấy được mấy cái ảnh bitmap của nó thì bạn vào trong menu vào ... (không nhớ rõ lắm, các bạn tự mày mò đi 2' là thấy ngay ấy mà hờ hờ hờ hờ hờ)

    Decompile là gì ?

    đây là quá trình biên dịch:

    vậy Decompile là quá trình dịch ngược từ file .exe,.dll,.ocx.... lại thành mã nguồn, hờ hờ hờ


    Tôi nhận thấy 1 điều lí thú rằng : Upokemon.exe chơi ít bị out, dis, lỗi hơn pokemon.exe</font></font>

  7. #7
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Chap 2: hack điểm

    Khi chơi game, ta thấy điểm hiện lên trên màn hình, vậy thì chắc chắn nó sẽ được lưu trữ ở đâu đó trong bộ nhớ và sẽ có địa chỉ VA cụ thể. Dân lập trình chúng ta gọi chúng là biến</font>, và có địa chỉ cụ thể, hj hj

    Muốn biết VA là gì xem ở đây :
    Portable Executable File Format


    Để thay đổi điểm từ phía app của mình, đầu tiên chúng ta phải tìm được địa chỉ VA của biến điểm này đã nhỉ.

    Để tìm được địa chỉ của biến này ko quá khó với 1 tool cơ bản như artmoney (Chưa có download ở đây, active code là dot68) :

    Bước 1
    Đầu tiên bật pikachu lên chơi lấy 20 điểm và bật artmoney lên,
    đầu tiên là chọn tiến trình, pikachu ở đây có cái tên là D4S
    rồi click vào Search lên 1 hộp thoại


    Bước 2
    click vào ... để chọn kiểu dữ liệu, mình hack nhiều lần rồi nên biết nó là kiểu float 4byte, nếu chưa hack bao giờ, các bạn có thể để ALL để tìm với mọi loại dữ liệu


    Bước 3
    chúng ta sẽ thu được 1 loạt địa chỉ đang chứa giá trị 20, bây giờ chúng ta vào trong game để chơi cho điểm trở thành 40 rồi vào artmoney, click vào nút Filter gõ giá trị mới là 40 rồi ok


    Bước 4


    Vậy là ta đã biết địa chỉ của biến điểm là 004B6088

    Vậy ta sẽ làm 1 demo để hack điểm nhé :
    Vào Visual Studio (Chưa có thì download tại đây) vào File -> New -> Project -> Win32 Project (đặt tên, đường dẫn) -> Next (chọn empty project) -> finish
    chuột phải vào thư mục source code tạo 1 file cpp mới rồi gõ code

    Để biết được tên lớp và tên cửa sổ của tiến trình pikachu ta chỉ việc mở spy++ (tool đính kèm khi cài VS rồi làm như hình sau)






    demo chức năng đầu tiên như sau :

    Demo1 : Set game point to 99999

    Mã nguồn PHP:
    #include <windows.h> int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd) { HWND hwnd =FindWindow(L"ThunderRT6FormDC", L"³s³s¬Ý2"); // tìm cửa sổ pikachu if (!hwnd) // Nếu ko tìm thấy { MessageBox(HWND_DESKTOP,L"Bạn phải bật pikachu lên chơi trước đã",L"Thông báo",MB_OK); //Hiện thông báo } else { DWORD pid; float temp=99998; GetWindowThreadProcessId(hwnd,&pid); // lấy định danh của process HANDLE handle=OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_OPERATION|PROCESS_VM_WRITE,FALSE,pid); // mở process để láy handle int *address=(int*)0x4B6088; // địa chỉ của biến điểm WriteProcessMemory(handle,address,&temp,sizeof(temp),0); // ghi lên vùng nhớ đó MessageBox(HWND_DESKTOP,L"Đã thiết lập xong",L"Thông báo",MB_OK); // thông báo kết quả } return EXIT_SUCCESS; }  
    Demo 2 :
    Tăng điểm của người chơi (add 1000 to game point)
    Mã nguồn PHP:
    #include <windows.h> void Add1000ToPoint() { HWND hwnd =FindWindow(L"ThunderRT6FormDC", L"³s³s¬Ý2"); if (!hwnd) { MessageBox(HWND_DESKTOP,L"Bạn phải bật pikachu lên chơi trước đã",L"Thông báo",MB_OK); } else { DWORD pid; float temp=0; GetWindowThreadProcessId(hwnd,&pid); HANDLE handle=OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_OPERATION|PROCESS_VM_WRITE|PROCESS_VM_READ,FALSE,pid); int *address=(int*)0x4B6088; ReadProcessMemory(handle,address,&temp,sizeof(temp),0); temp+=1000.f; WriteProcessMemory(handle,address,&temp,sizeof(temp),0); MessageBox(HWND_DESKTOP,L"Đã add thành công",L"Thông báo",MB_OK); } } int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd) { Add1000ToPoint(); return EXIT_SUCCESS; }  
    Bây giờ bạn bật pikachu lên , vô game chơi rồi chạy thử cái tool bạn vừa làm xong xem thế nào, hj hj hj hj

    <font color="Red">
    Đặc biệt


    1. Code demo sau chạy ngon trên Dev-C :
    Mã nguồn PHP:
    #include <windows.h> void Add1000ToPoint() { HWND hwnd =FindWindow("ThunderRT6FormDC", "³s³s¬Ý2"); if (!hwnd) { MessageBox(HWND_DESKTOP,"Ban phai bat pikachu len choi truoc da","Thong bao",MB_OK); } else { DWORD pid; float temp=0; GetWindowThreadProcessId(hwnd,&pid); HANDLE handle=OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_OPERATION|PROCESS_VM_WRITE|PROCESS_VM_READ,FALSE,pid); int *address=(int*)0x4B6088; ReadProcessMemory(handle,address,&temp,sizeof(temp),0); temp+=1000.f; WriteProcessMemory(handle,address,&temp,sizeof(temp),0); MessageBox(HWND_DESKTOP,"Da add thanh cong","Thong bao",MB_OK); } } int main() { Add1000ToPoint(); return 1; }  
    2. Và giải thích
    Mã nguồn PHP:
    HWND hwnd =FindWindow("ThunderRT6FormDC", "³s³s¬Ý2");  
    Câu lệnh này giúp tìm ra mã số của cửa sổ và lưu vào biến hwnd . Trong windows thì mỗi cửa số có 1 mã số là 1 số nguyên 32 bit,


    Mã nguồn PHP:
    if (!hwnd) { MessageBox(HWND_DESKTOP,"Ban phai bat pikachu len choi truoc da","Thong bao",MB_OK); }  
    nếu không tìm thấy thì hiển thị lên 1 hộp thông báo với nội dung như các bạn nhìn thấy

    Mã nguồn PHP:
    else { DWORD pid; float temp=0; GetWindowThreadProcessId(hwnd,&pid); // lẫy mã của tiến trình đang chạy HANDLE handle=OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_OPERATION|PROCESS_VM_WRITE|PROCESS_VM_READ,FALSE,pid); // mở tiến trình đó để đọc ghi dữ liệu, dạng dạng như mở file ấy int *address=(int*)0x4B6088; // gán cho biến này địa chỉ của biến điểm mà ta đã tìm ra ReadProcessMemory(handle,address,&temp,sizeof(temp),0); // đọc giá trị của biến điểm lưu vào temp temp+=1000; // tăng temp lên 1000 WriteProcessMemory(handle,address,&temp,sizeof(temp),0); // ghi lại giá trị mới của temp vào trong ô nhớ của biến điểm MessageBox(HWND_DESKTOP,"Da add thanh cong","Thong bao",MB_OK); //thông báo đã ghi thành công }  
    xong cháp 2, nghỉ ngơi , học bài mai viết tiếp chap 3

  8. #8
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Em rất cảm ơn anh, đã cho thêm phần code trên DEV-C. Chứ không em chả biết code thế nào, vì chưa dùng VS bao giờ. ^^!

  9. #9
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Ở phần đóng băng, có 1 số cách khá đơn giản

    Ví dụ có 1 biến timer được thiết đặt sẵn (fix cứng hoặc đặt khi runtime)


    Mã:
    int timer = 60000;  // 60s
    Ví dụ đoạn loop của Timer như sau

    Mã:
    _header:  timer = timer - 1  if (timer <= 0)  {     //Do some thing  }   sleep(1000);goto _header:
    Ta có 1 vài cách
    1. Thay số 1 thành 0 (timer = timer - 0)
    2. Tay phép trừ thành cộng (SUB [0xEC] thành ADD [0xC4])

    Hồi trước, gặp 1 thằng điên nó xét DK như sau

    if (timer == 0) ....

    thế là mình set luôn giá trị của timer (nó fix cứng là 100000) là -1. Trừ mãi mà biến timer cũng != 0 =))

  10. #10
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Ai cũng muốn 1 phát lên nhà lầu xe hơi luôn mà , tâm lý chung .

 

 
Trang 1 của 18 12311 ... CuốiCuối

Quyền viết bài

  • Bạn Không thể gửi Chủ đề mới
  • Bạn Không thể Gửi trả lời
  • Bạn Không thể Gửi file đính kèm
  • Bạn Không thể Sửa bài viết của mình
  •