- Trong Magic: The Gathering Arena, có thể buộc đối thủ đầu hàng vào đúng thời điểm mong muốn, từ đó tạo ra trạng thái không thua trong các trận matchmaking
- Trò chơi thẻ bài thường phù hợp với kiến trúc máy chủ toàn quyền, nơi máy chủ quản lý toàn bộ trạng thái, nhưng đối thủ bot Sparky của MTGA lại được triển khai bằng logic client cục bộ
- Client MTGA viết bằng C# cho phép truy cập các đối tượng runtime và các trường private bằng reflection, và trong mã đã decompile có thể thấy các tên như
JoinMatch,ConnectAndJoinMatch,HeadlessClient - Trong trận đấu với bot, cấu trúc kết nối dùng
PersonaIDvà JWT của cùng một tài khoản cho cả hai ghế, và khi áp dụng điều này vào trận thường, có thể gắn một headless client vào ghế của đối thủ rồi gọiConcedeGame() - Sau đó máy chủ đã được vá để ngăn hai ghế trong các trận matchmaking dùng cùng một tài khoản và JWT, trở thành một ví dụ cho thấy ranh giới giữa triển khai bot phía client và xác thực ghế ảnh hưởng trực tiếp đến bảo mật thực chiến
Vì sao game thẻ bài khó bị hack
- Game thẻ bài theo lượt và lượng thông tin trao đổi giữa client và máy chủ không nhiều, nên rất phù hợp với kiến trúc máy chủ toàn quyền
- Máy chủ quản lý toàn bộ trạng thái trò chơi và chỉ gửi cho client những thông tin cần thiết
- Thông tin chưa được công khai như bài trên tay hoặc bộ bài của đối thủ sẽ không tồn tại trên máy cục bộ
- Các kiểu can thiệp như đổi thứ tự bộ bài hoặc thao túng lá sắp rút rất khó thực hiện vì máy chủ xử lý hành động và chỉ thông báo kết quả
- Khác với game bắn súng góc nhìn thứ nhất, hành vi của người chơi trong game thẻ bài bị giới hạn và chỉ xảy ra vào những thời điểm xác định
- Trong FPS, thông tin như vị trí mô hình địch có thể được cache sẵn ở client nên có thể xuất hiện kiểu wallhack
- Bài viết anti-wallhack của Riot nói về cách tiếp cận giảm dữ liệu vị trí người chơi ở phía client
- Việc phát hiện hành vi sai trái cũng tương đối dễ
- Đánh ra lá bài không có trên tay
- Hành động khi chưa đến lượt của mình
Điểm khởi đầu phân tích: mạng và client C#
- Tác giả chọn cách bắt đầu việc hack game bằng cách xem xét giao tiếp mạng
- Bài nói chuyện DEF CON của Manfred về các trường hợp hack MMO cho thấy việc dịch ngược giao thức mạng là chìa khóa để phân tích nhiều lỗi
- MTGA được viết bằng C#, nên thay vì hook các hàm gửi nhận traffic, có thể thao tác đối tượng ngay trong runtime
- Reflection của .NET cho phép truy cập cả các trường và phương thức private
- Ví dụ nền tảng liên quan có bài hướng dẫn hack game Unity bằng reflection
- Các assembly .NET không bị làm rối mã cho phép xem tên hàm, biến, lớp ở dạng con người đọc được nhờ metadata token
- Vì vậy kết quả decompile gần như tương đương với việc review mã nguồn
Cấu trúc Sparky được tìm thấy trong JoinMatch
- Trong lúc tìm tên hàm liên quan để lần ra quá trình khởi tạo tham gia trận, tác giả phát hiện hàm
JoinMatch JoinMatchlà một hàm dài hơn 200 dòng, và ở phần cuối có lời gọiConnectAndJoinMatch- Hàm này có vẻ là luồng nhận thông tin cấu hình trận rồi kết nối tới máy chủ game
- Trong cùng luồng mã có các nhánh
MatchType.NPEvàMatchType.FamiliarNPEđược suy đoán là các trận dạng hướng dẫn cho người chơi mớiFamiliarlà trận bot tiêu chuẩn
- Logic được gọi trong nhánh này liên kết với Sparky, đối thủ bot của MTGA
- Sparky là đối thủ mang tính biểu tượng của MTGA, dùng trong tutorial và đấu với bot
- Trong trận bot, logic bot được chạy ngay bên trong game client trên máy cục bộ
Bot cục bộ và HeadlessClient
- Bộ xử lý logic thực tế của bot nằm trong lớp
HeadlessClient HeadlessClientlà một headless client không render bàn chơi nhưng vẫn kết nối máy chủ để chơi trận đấu- Client bot được tạo cục bộ dùng cùng thông tin xác thực người dùng với game client
PersonaIDđóng vai trò ID người dùng- JSON web token được cấp cho game sau khi đăng nhập
- Trong trận bot, hệ thống được thiết kế sao cho máy chủ không coi việc cùng một client thực chất kết nối vào cả hai phía của trận là vấn đề
- Ghế (seat) được dùng để phân biệt người chơi nào là ai trong trận
- Trong trận bot, có thể điền các ghế khác nhau bằng cùng một thông tin xác thực
Cách chiếm quyền trận đấu thường
- Tác giả thử áp dụng logic trận bot vào trận thường để xem có thể kết nối vào cả hai ghế hay không
- Các thông tin cần thiết được lấy từ các đối tượng game trong runtime
- Cấu hình trận hiện tại
- Host và cổng của máy chủ trận
controllerFabricUrimatchIdPersonaIDJwt- Cơ sở dữ liệu thẻ bài
- Trình quản lý trận
- Hệ thống tra cứu asset
- Ghế của đối thủ được tính dựa trên ghế của chính mình
- Trong mã, ghế còn lại được tính bằng
man.LocalPlayerSeatId % 2U + 1U
- Trong mã, ghế còn lại được tính bằng
- Dùng
UnityFamiliar.SpawnFamiliar_DEBUG(...)để kết nối bot vào ghế của đối thủ - Sau đó tìm đối tượng
UnityFamiliarđã tạo và gọicheatbot.Client.Gre.ConcedeGame()để buộc đầu hàng ngay lập tức
Kết quả và bản vá
- Cách này hoạt động cả trong trận thường
- Nó vẫn hoạt động ngay cả khi đối thủ đã kết nối và trận đấu đang diễn ra
- Vì đây là game matchmaking, người khai thác vẫn nhận được phần thưởng như thể đã thắng người chơi thật
- Cốt lõi của lỗ hổng là máy chủ trận thường cho phép cùng một tài khoản và JWT kết nối vào cả hai ghế
- Sau đó máy chủ đã được vá để trong các trận matchmaking, hai ghế không thể dùng cùng một tài khoản và JWT
- Đoạn mã
InstaWintrong phụ lục là mộtMonoBehaviourcủa Unity, tạo nút GUI và khi bấm sẽ thu thập thông tin trận hiện tại, gắn bot vào ghế đối thủ rồi buộc đầu hàng
1 bình luận
Các ý kiến trên Hacker News
Lần đầu tôi thực sự đào sâu vào Linux là khi dùng ShowEQ cho EverQuest để xem lưu lượng mạng
Khi đó lưu lượng chưa được mã hóa và chứa rất nhiều thông tin hữu ích. Tôi sao chép lưu lượng sang một máy Linux bằng hub để vẽ bản đồ thời gian thực của khu vực, hiển thị vị trí quái vật, NPC và người dùng, thậm chí còn cho thấy cả chiến lợi phẩm mà quái vật mang theo, nhờ đó có thể chọn đúng quái vật cần săn. Ưu điểm là cách này hoàn toàn thụ động nên không thể bị phát hiện; cuối cùng SOE cũng nhận ra và bắt đầu mã hóa lưu lượng.
Khi đó phía bên kia sẽ đưa vào chữ ký dựa trên khóa, rồi lại có người cố đánh cắp khóa từ client để phá mã hóa, và sau đó khi hệ thống chống gian lận xuất hiện thì trò mèo vờn chuột bắt đầu.
Nó có đáng để kiếm lợi thế trong game không? Không. Tôi không chơi nghiêm túc, nên chỉ mất 2 tuần cài đặt rồi dùng khoảng 1 tuần, nhưng xét như trải nghiệm học tập thì rất tuyệt.
Ví dụ như sự tồn tại của hell level, việc halfling chứ không phải human nhận bonus kinh nghiệm và trên thực tế có chênh lệch kinh nghiệm theo chủng tộc/nghề, hay việc thuật giả kim Shaman thời kỳ đầu thực sự bị hỏng. Và tôi nghĩ chuyện này đã dẫn tới eqemulator.org.
Có vẻ chủ sở hữu EQ hiện tại không bận tâm lắm nên dùng cũng khá ổn. Tuy vậy, cả hai ứng dụng đều chưa từng hiển thị chiến lợi phẩm của quái vật ngoài trang bị có thể nhìn thấy. Qua thời gian, một số dữ liệu cũng đã thay đổi; trước đây máu chính xác của quái vật được gửi đi, còn giờ chỉ gửi phần trăm.
Tôi không hiểu lắm đoạn “một bot gần như hoàn chỉnh có thể chơi bất kỳ ván Magic: The Gathering nào đủ nhỏ để chạy trên máy cục bộ”
Nếu AI MTG nặng đến mức khó chạy trên máy khách hàng, có lẽ họ cũng sẽ không chạy nó trên máy chủ. Các trận bot trong game bài thường không tính phí theo từng ván nên chi phí sẽ lớn. Máy chủ cũng không phải phép màu; phần lớn dùng CPU x86 giống máy cục bộ, và thường xung nhịp còn thấp hơn desktop. Muốn giảm thời gian lượt của bot so với chạy cục bộ thì phải dùng nhiều lõi hơn hẳn so với khách hàng, nhưng nếu cấp 8–16 lõi cho mỗi người chơi thì giờ cao điểm đồng thời sẽ như ác mộng. Nếu người chơi CPU không hỗ trợ đa lõi thì chạy cục bộ dù sao cũng phải nhanh hơn.
Tức là engine luật của bot đủ nhỏ để vừa trong bộ nhớ của iPhone đời cũ hoặc thiết bị Android. Trên máy chủ, bạn có thể giữ nhiều máy trạng thái hoặc engine luật trong bộ nhớ, và việc thực thi một yêu cầu cụ thể có thể gần như không tốn năng lực xử lý.
Daniel, một lần nữa chúc mừng vì bài viết lên top. Sau khi bài này được đăng, tôi đã thử hack MTGA và cũng trao đổi một chút trên GitHub [0]
Với những ai quan tâm: hiện tôi đang làm một client MTGA không chính thức, gần như chưa có tính năng, trong trạng thái không hoạt động tích cực. Mục tiêu là tự động hóa việc chơi ranked và cung cấp đối thủ bot mạnh hơn. Gần đây tôi bị các việc khác cuốn đi, và vẫn chưa biết phải làm một UI tốt, dễ nhìn như thế nào, nên rất khó dự đoán khi nào nó mới hữu dụng tối thiểu. Ngoài ra tôi vẫn muốn nghe thêm các câu chuyện hack game từ Daniel hoặc những người khác: cách tìm những lỗi kiểu này, làm sao không lo bị ban sau khi hack, cách công bố lỗi như @aethros nói, hay cách cấu trúc một client game bài không chính thức.
[0] https://github.com/MayerDaniel/mayerdaniel.github.io/issues/...
Nói rằng mình tưởng việc tạo đối thủ AI cho một game phức tạp như MTG sẽ có overhead lớn là một cách nói giảm khá mạnh
Trò chơi gần như Turing-complete, và ngay cả nếu loại trừ vòng lặp vô hạn thì người ta vẫn nghịch được rất nhiều thứ với nó. Dù vậy, có lẽ phần nghiên cứu về chiến lược AI đã được làm khá nhiều rồi. Và vì đây là bài do chính tác giả đăng, có lẽ tiêu đề nên được gắn “Show HN:”.
Điều khó với người viết bot có vẻ là vế sau.
Ví dụ như dùng hiệu ứng vào sân/rời sân/untap để tạo và giết sinh vật token. Những vòng lặp như vậy cũng không phải lúc nào cũng gây sát thương cho một bên nào đó.
Tôi chưa từng chơi MTG, nhưng lập luận này có vẻ nói rằng nếu không nhằm mục đích thắng mà cố tình tạo ra một cấu trúc có trạng thái thì về mặt kỹ thuật là có thể.
Chơi Old School Magic 93/94 bằng bài giấy cùng con trai thật sự rất vui
Hằng năm tôi đến Madrid để tham dự Giải vô địch thế giới 7pts Singleton. Mùa hè này con trai tôi xếp hạng 9 nên tôi rất tự hào. 7pts Singleton là một thể thức tuyệt vời, cho phép xây dựng nhiều kiểu bộ bài khác nhau và đem lại lối chơi cân bằng với chi phí tương đối nhẹ nhàng (https://7pts-singleton.com)
Dù trong 7pts Singleton không thể dùng tất cả, chỉ một lá thôi cũng đã tốn từ vài nghìn đến vài chục nghìn USD. Dù vậy, thật tốt khi bạn được chơi cùng con trai, và chúc mừng vì đã vào nhóm có thứ hạng cao
Logic game thuần phía client cơ à. Trước đây khi làm một game nhỏ, có lúc tôi phải đưa logic game vào client để tăng độ phản hồi, nhưng đâu có luật nào cấm chạy lại cùng logic đó trên server, nên tôi đã làm vậy
Với game thời gian thực như FPS hay RTS thì có thể khó, nhưng với game bài thì không có lý do bào chữa. Với dạng game bài này, đúng ra không nên gửi cho client nhiều thông tin hơn những gì người chơi thật có thể thấy. Ví dụ, đừng gửi nội dung các lá bài trên tay đối thủ, chỉ gửi số lượng lá bài thôi. Các hành động gửi lên server cũng chỉ nên liên quan đến chính mình, vì vậy không được phép tuyên bố đối thủ đầu hàng. Nếu tôi nói “Đầu hàng!” thì server phải diễn giải đó là việc tôi đầu hàng
Lỗ hổng là có thể mở client thứ hai và kết nối vào ván đang diễn ra ở ghế của đối thủ. Một khi làm được vậy, có thể gửi hành động của đối thủ, bao gồm cả đầu hàng
Thứ tác giả khai thác không phải logic game phía client, mà là vấn đề trong mã phân quyền và kết nối vào game. Câu “không được phép tuyên bố đầu hàng thay đối thủ” chỉ là lặp lại đúng cách exploit mà tác giả tìm ra hoạt động
Trong League of Legends từng có lỗi chia cho 0 với một tổ hợp tướng và trang bị cụ thể, khiến server đá tất cả người chơi ra rồi crash
Vì kẻ khai thác bị đá ra cuối cùng, đội của người đó được xử thắng, còn đội đối phương nhận Loss Prevented thay vì kết quả bình thường
Bài viết này dễ tiếp cận mà vẫn có các chi tiết rất sâu sắc
Tuy nhiên tôi không hiểu trường hợp kết nối bot vào trong lúc trận đấu đang diễn ra. Vì sao game lại cho phép tham gia giữa trận, và khi bot đầu hàng thì vì sao việc đó lại được xử lý thành đối thủ đầu hàng? Nếu đang tạo một game 3 người, thì người chơi số 3 đầu hàng cũng không được tính là người chơi số 2 đầu hàng
Mã tìm ra chỉ số ghế của tài khoản của tôi, rồi cho bot tham gia bằng chỉ số ghế khác. Vấn đề là không kiểm tra người dùng tham gia có đúng là người dùng phải ngồi ở ghế đó hay không. Cũng có thể nghĩ rằng không nên cho phép kết nối lại vào một ghế đã có kết nối, nhưng nếu game hỗ trợ cả mobile thì có lẽ bạn sẽ muốn thời gian chờ khi mất kết nối khá dài. Vì bạn không muốn chặn một người chơi chỉ bị ngắt kết nối chốc lát rồi kết nối lại trước khi thời gian chờ nhận ra kết nối cũ đã chết. Tôi từng thấy ở game khác, khi cố kết nối lại thì khoảng 10 giây hiện “không thể tham gia game đang diễn ra”, rồi sau đó mới kết nối lại được. Ví von thì giống như xuất hiện ở một giải MTG tại cửa hàng bài địa phương, đẩy ai đó khỏi ghế rồi ngồi xuống hô “Tôi đầu hàng!”, và trọng tài công nhận người ngồi trên chiếc ghế đó đã tuyên bố nên người chơi B bỏ cuộc
Vì vậy có vẻ nó có thể đầu hàng thay đối thủ. Có thể các nhà phát triển không nghĩ rằng ai đó lại có lý do để cố làm như vậy nên đã không kiểm tra
Nhớ lại thời Diablo 2, từng có lúc có thể tái sử dụng cùng gói tin đăng nhập để đưa nhân vật server mở (LAN) vào server Internet bnet chính thức
Vì dữ liệu server mở được lưu toàn bộ cục bộ, người ta có thể tạo đủ loại vật phẩm lẽ ra không được tồn tại, và server chính thức cũng chấp nhận chúng
Gần đây tôi quay lại với MTG qua MTGA. Đây là game Unity và không dùng il2cpp nên tôi đã decompile nhanh, mà kể cả có dùng il2cpp thì có lẽ cũng không bảo vệ được nhiều, và tôi đã tìm thấy vài thứ khá thú vị
Có những thứ như key cho bản build Epic Launcher hoặc API chưa được tài liệu hóa. Tôi không muốn dùng để gian lận, chỉ là muốn có lịch sử trận đấu. Chẳng hạn như đã thắng thua những trận nào, hay chức năng xem lại trạng thái bàn đấu của một game đã kết thúc. Tôi cũng sẽ xem bài viết này, và hy vọng nó sớm được vá
Nếu muốn xem lịch sử, bạn có thể xem https://untapped.gg/en. Tôi đã trao đổi với họ một chút, và về cơ bản nó làm đúng việc bạn muốn. Phần lớn thông tin được lấy từ log debug MTG trong thư mục ứng dụng MTGA, nên nếu muốn bạn cũng có thể tự làm tracker. Trang web cũng giải thích điều này: https://help.hearthsim.net/en/articles/3620440-how-do-i-supp...
Tôi nhớ là có khá nhiều ứng dụng dùng log đó để theo dõi