Hướng dẫn cơ bản về Cheat Engine - Code Injection (Phần 3)
Mở đầu
Ở phần trước chúng ta đã tìm hiểu cách tìm con trỏ trỏ tới giá trị mục tiêu. Tiếp theo, bài viết này sẽ giải quyết phần còn lại của CE tutorial: Code Injection. Nhắc đến code mà lại còn code assembly thì phần đông chúng ta sẽ thấy khó và ngại đọc/viết ngôn ngữ lập trình cấp thấp này. Nhưng với sự phát triển bùng nổ của chatbot AI, việc đọc hiểu code asembly giờ đây đã dễ dàng hơn rất nhiều. Thêm vào đó, chỉ một số ít các đoạn code assembly hay được sử dụng nên các bạn cũng không cần quá lo lắng. Vậy chúng ta cùng bắt đầu với các khái niệm sẽ nhắc tới trong bài viết.
Code Injection là gì?
Code injection là một kỹ thuật đưa một đoạn code vào trong chương trình đang chạy, sau đó điều hướng việc thực thi mã để chạy qua đoạn code do bạn viết (ví dụ như được cộng điểm thay vì trừ điểm).
Code Injection trong Cheat Engine
Chúng ta có thể thực hiện code injection với hầu hết các ngôn ngữ lập trình miễn là ngôn ngữ đó hỗ trợ khả năng tương tác với bộ nhớ và tiến trình nhưng sẽ khá khó với người ít kinh nghiệm lập trình, kể cả với những lập trình viên đi nữa thì việc này cũng sẽ tốn kha khá thời gian để tìm hiểu và đọc document của ngôn ngữ.
Cheat Engine có các tính năng giúp chúng ta đơn giản hóa việc code injection, bao gồm tích hợp script code vào CheatTable để dễ dàng enable/disable script, Injecting a DLL, LUA script. Chúng ta sẽ bắt đầu làm quen với code injection thông qua CE tutorial step 7.
Lập trình hướng đối tượng (Object oriented programming)
Lập trình hướng đối tượng (OOP) là một phương pháp lập trình lấy đối tượng làm trung tâm để thiết kế và phát triển phần mềm. Các đối tượng được mô phỏng theo các thực thể trong thế giới thực, sở hữu thuộc tính (đặc điểm) và phương thức (hành vi). Nó đóng vai trò làm nền tảng quan trọng cho việc phát triển phần mềm hiện đại, được ứng dụng rộng rãi trong nhiều lĩnh vực như: phần mềm doanh nghiệp, hệ thống web, ứng dụng di động, trò chơi điện tử, ... OOP cũng giải thích nhiều trường hợp ta hay gặp phải trong quá trình sử dụng CE, ta sẽ thấy một ví dụ điển hình trong CE tutorial step 9.
Thanh ghi
Hãy tưởng tượng bên trong CPU của máy tính có một quyển sổ ghi chép siêu nhỏ và siêu nhanh. Đó chính là thanh ghi (register)! Thanh ghi lưu trữ dữ liệu và các hướng dẫn mà CPU cần ngay lập tức, giống như một bảng tính nháp để thực hiện các phép tính. Thanh ghi hoạt động nhanh hơn nhiều so với bộ nhớ thông thường, cho phép CPU hoạt động hiệu quả. Mỗi thanh ghi có những nhiệm vụ riêng biệt, chẳng hạn như theo dõi các chương trình đang chạy hoặc lưu trữ kết quả tính toán. Nói tóm lại, thanh ghi là nơi lưu trữ tiện lợi của CPU để truy cập nhanh, giúp máy tính của bạn chạy mượt mà. Các thanh ghi phổ biến trong kiến trúc CPU x64 là RAX, RBX, RCX, RDX, RSI, RSP, ...
Thực hành Step 7 trong CE tutorial (Password: 013370)
Trong tutorial này ta có một giá trị health và một nút bấm mà khi nhấn vào sẽ khiến giá trị health giảm đi 1. Nhiệm vụ của chúng ta là khiến giá trị health tăng lên 2 khi nhấn nút Hit me này. Cách làm thì đầu tiên vẫn là tìm địa chỉ chứa giá trị health, thêm vào CheatTable phía dưới, nhấn chuột phải chọn Find out what write to this address sẽ tìm được duy nhất một dòng code cập nhật health:
sub dword ptr [rsi+000007E0],01
Thay vì chọn Replace do nothing như đã từng làm ở step trước thì lần này ta chọn Show disassembler để mở cửa sổ Memory viewer (dòng code ta tìm được đã select sẵn)
Tại đây ta có thể giải quyết luôn challenge bằng cách sửa binary trực tiếp, ví dụ sửa 01 thành -2 sub dword ptr [rsi+000007E0],-2
hoặc thay đổi cả instruction code từ sub
-> add
: add dword ptr [rsi+000007E0],2
. Nhưng mục đích của step này là giúp chúng ta làm quen với code injection trong CE nên ta sẽ giữ nguyên dòng code trên và mở cừa sổ Auto assemble
bằng cách chọn menu Tools -> Auto assemble, hot key mặc định là Ctrl + A.
CE cung cấp sẵn cho chúng ta các template code với các mục đích khác nhau ở menu Template trong cửa sổ Auto assemble. Ở challenge này mình sẽ sử dụng 2 template cơ bản nhất: Cheat Table Framework Code giúp ta có thể lựa chọn active/deactive script trong Cheat Table của CE, Code Injection thì giúp ta điền phần lớn code cần thiết để có thể inject code vào vị trí địa chỉ được chọn.
Lưu ý ta cần chọn Template theo đúng thứ tự Cheat Table Framework Code rồi mới chọn Code Injection như hình trên thì phần [DISABLE] mới được điền code đầy đủ. Bạn đọc có thể nhờ các chatbot AI như Copilot của Microsoft, Gemini của Google giúp giải thích ý nghĩa của đoạn code.
[ENABLE]
//code from here to '[DISABLE]' will be used to enable the cheat
alloc(newmem,2048,"Tutorial-x86_64.exe"+2DB57)
label(returnhere)
label(originalcode)
label(exit)
newmem: //this is allocated memory, you have read,write,execute access
//place your code here
add dword ptr [rsi+000007E0],02
jmp exit
originalcode:
sub dword ptr [rsi+000007E0],01
exit:
jmp returnhere
"Tutorial-x86_64.exe"+2DB57:
jmp newmem
nop 2
returnhere:
[DISABLE]
//code from here till the end of the code will be used to disable the cheat
dealloc(newmem)
"Tutorial-x86_64.exe"+2DB57:
db 83 AE E0 07 00 00 01
//sub dword ptr [rsi+000007E0],01
Vẫn còn các Template code khác nữa nhưng để đi hết thì bài viết sẽ rất dài, bạn đọc có thể tham khảo thêm từ tài liệu phía dưới.
Thực hành Step 9 trong CE tutorial (Password: 31337157)
Challenge này vẫn có thể giải quyết bằng cách dùng pointer scan giá trị Health Player bất kỳ của phe ta như mình đã hưỡng dẫn trong bài viết trước, nhưng khá hên xui, chỉ ở mức enable được nút Next.
Trong hầu hết các trường hợp thì code injection luôn là giải pháp giải quyết các vấn đề tối ưu hơn nhưng nhược điểm là khó và mất nhiều thời gian để cho ra được đoạn code chính xác theo như mong muốn. Step 9 này muốn giải thích một vấn đề thường gặp khi ta chỉnh sửa logic trong game, cụ thể ở challenge này là giá trị HP. Ví dụ khi ta chỉnh sửa đoạn code update HP thành do nothing thì sẽ áp dụng cho cả kẻ địch, nghĩa là kẻ địch cũng bất tử giống mình, chắc chắn chúng ta sẽ không muốn như vậy.
Nguyên nhân ở đây chính là tiêu đề của step này: Shared Code
Xuất phát từ đặc trưng của lập trình hướng đối tượng, mã game thường được chia thành các class. Mỗi class đại diện cho một đối tượng cụ thể (nhân vật chính, đồng đội, kẻ địch, v.v.) và có thể chia sẻ các đoạn mã chung nhằm tối ưu hóa hiệu quả lập trình. Ví dụ, mã cập nhật HP có thể được chia sẻ giữa các lớp nhân vật để tiết kiệm thời gian phát triển. Tuy nhiên, việc sửa đổi mã chung trực tiếp sẽ dẫn đến thay đổi cho tất cả các lớp sử dụng nó. Dưới đây là code minh họa bằng ngôn ngữ lập trình C#.
class Actor
{
public int Health { get; set; }
public string Name { get; set; }
public virtual void UpdateHealth()
{
// Cập nhật trạng thái sức khỏe mặc định cho class Actor
}
}
class Player : Actor
{
public int TeamId { get; set; }
public override void UpdateHealth()
{
if (TeamId == 1)
{
// Cập nhật sức khỏe cho người chơi thuộc nhóm 1
}
else if (TeamId == 2)
{
// Cập nhật sức khỏe cho người chơi thuộc nhóm 2
}
else
{
// Cập nhật sức khỏe cho người chơi thuộc nhóm khác
}
}
}
Theo CE tutorial, trong những trường hợp này, chúng ta cần tìm cách phân biệt object nào là đội mình và object nào là đội địch. Đôi khi điều này đơn giản như kiểm tra 4 byte đầu tiên (Function pointer table), đôi khi đó là TeamId hoặc một multi-level pointer trỏ đến thuộc tính nào đó của object. Tất cả phụ thuộc vào độ phức tạp của trò chơi và cả sự may mắn nữa. Phương pháp dễ nhất là tìm địa chỉ write memory và sử dụng tính năng phân tích dữ liệu (Context menu: Open dissect data with selected addresses) để so sánh các structure. Hoặc như hình dưới mình dùng tính năng Commonality scanner của CE để tìm giá trị giống nhau trong cùng một group của một thanh ghi + offset (cùng 1 team mình cho vào cùng 1 group).
Sau đó, hãy xem liệu bạn có thể tìm ra cách để phân biệt giữa chúng không. Khi bạn đã tìm ra cách phân biệt giữa đội bạn và đội địch, bạn có thể dùng code injection như ở step 7.
Kết luận
Vậy là chúng ta đã đi hết 9 challenge trong CE tutorial. Những ví dụ trong các step của tutorial này đều chỉ nhằm mục đích demo, giải thích các tính năng của CE nên ở mức rất đơn giản, khi bạn sử dụng CE với các game thực tế chắc chắn sẽ gặp rất nhiều những trường hợp khác không giống với tutorial này. Việc này là bình thường vì mỗi video game sẽ sử dụng các công nghệ khác nhau, mức độ quan tâm đến bảo mật của mỗi game cũng khác nhau.
Tuy nhiên, với những kiến thức cơ bản đã học được từ tutorial này, bạn đã có thể tự tin bắt đầu hành trình khám phá thế giới video game, tự mình tìm tòi và chinh phục những thử thách khó khăn hơn. Hãy nhớ rằng, chìa khóa thành công trong lĩnh vực này chính là sự kiên trì, lòng ham học hỏi và không ngừng trau dồi kiến thức. Bạn đọc có thể tham khảo những tài liệu hữu ích do CrypoCat tổng hợp tại https://github.com/Crypto-Cat/CTF/tree/main/game_hacking
Ngoài ra, theo trang Grand View Research thị trường game toàn cầu đang phát triển mạnh mẽ với tốc độ tăng trưởng kép dự kiến là 13.4% từ năm 2023 đến năm 2030, dự kiến đạt 583,69 tỷ USD vào năm 2030. Đi cùng với sự phát triển đó chắc chắn ngân sách đầu tư cho việc phòng chống gian lận trong game cũng tăng tương ứng vì đây là yếu tố quan trọng quyết định sự thành công của một tựa game. Nắm vững những kiến thức và kỹ năng này sẽ mở ra cho bạn nhiều cơ hội nghề nghiệp hấp dẫn trong tương lai.
All Rights Reserved