Mở đầu
Ở bài viết trước chúng ta đã giải quyết các thử thách CubeMadness1 và CubeMadness2, bài viết này chúng ta sẽ cùng nhau giải quyết một thử thách khó nhằn hơn với độ khó Medium: https://app.hackthebox.com/challenges/CubeBreaker
Writeup CubeBreaker
Đề bài có đồ họa khá giống với hai thử thách trước. Nhìn tổng quát thử thách thấy có đúng 20 box chia ra 10 box nằm trong vùng mà ta có thể lấy được, 10 box nằm ngoài vùng ta có thể di chuyển chia đều mỗi bên. Các box được bố trí như này thì khá rõ dụng ý của tác giả là muốn ta thoát khỏi vùng bên trong hình chữ nhật ra bên ngoài để lấy box.
Để thoát khỏi các cạnh hình chữ nhật thì điều đầu tiên ta nên nghĩ tới là tìm tọa độ của object ta điều khiển và chỉnh sửa nó thôi. Giống với thử thách của CE graphical tutorial, mình scan và tìm được giá trị tọa độ theo chiều ngang, gọi là X cho ngắn gọn đi (bạn sẽ tìm được khoảng 14 giá trị địa chỉ giống với X nhưng chỉ có 1 địa chỉ thực sự giúp ta thay đổi tọa độ trong game). Thử thay đổi giá trị của X để lấy các box bên ngoài thì thấy object của ta bị đưa về tâm của hình chữ nhật. Mình thử tìm đoạn code write giá trị của X lúc X bị đưa về trong hình chữ nhật rồi chuyển thành do nothing
thì kết quả như phía dưới, chưa có gì khả quan:
Để có thể test tiếp thì mình sẽ cần restore to original code
đoạn code vừa chuyển thành do nothing
. Đồng thời đề phòng trường hợp khi sửa code làm game bị crash và ta sẽ phải scan địa chỉ lại từ đầu mất thời gian, ta sẽ tìm luôn các pointer luôn trỏ tới giá trị ta cần, chi tiết bạn đọc có thể đọc lại chủ đề về pointer trong loạt bài viết về CE của mình.
Tìm được X rồi thì mình tìm đến Y, khi sửa giá trị của Y để object ra bên ngoài hình chữ nhật, cụ thể là phía trên thì thấy object ra ngoài một cách bình thường, khác với X. Ở phía trên rồi, khi không còn bị cạnh hình chữ nhật ngăn cản nhưng khi ta di chuyển vượt quá chiều dài hình chữ nhật thì vẫn bị đưa về tâm hình chữ nhật phía bên trong. Vậy ta có thể kết luận game có một ngưỡng như là 1 đường thẳng trùng với cạnh ngắn của hình chữ nhật để khi mà tọa độ X object của ta vượt ngưỡng đó thì sẽ đưa object của ta về tâm hình chữ nhật. Ngưỡng này sẽ là một giá trị cố định nào đó được lưu trong vùng nhớ của game. Để tìm được giá trị ngưỡng này mình chỉ biết cách debug đặt break point ở đoạn code cập nhật giá trị X khi ta di chuyển vượt quá ngưỡng và tìm đoạn code assembly so sánh với giá trị ngưỡng, nếu bạn đọc tìm được cách hay hơn thì hãy comment chia sẻ cho mình với nhé. Để tiện cho quá trình test và debug mình đã freeze giá trị tọa độ Y cho object của ta luôn nằm phía trên hình chữ nhật.
Trong quá trình debug, mình rút ra một số tip hữu ích giúp ta nhanh chóng tìm được đoạn code cần tìm:
- Luôn chỉ để tối đa 2 breakpoint, khi cần thêm breakpoint mới hãy xóa breakpoint không cần thiết nhất đi, điều này giúp ta không bị quá loạn mỗi lần
Step out
- Chọn những đoạn code mở đầu một function để đặt breakpoint, thường bắt đầu với
push (thanh ghi)
vàStep out
tại đây - Chú ý những dòng code dùng để so sánh 2 giá trị với nhau, nếu dòng code này được chạy liên tục thì khả năng cao chính là dòng code ta cần tìm
Sau quá trình debug thì mình đã tìm ra được đoạn code check tọa độ X vượt ngưỡng:
movsd xmm1,[1E7C4891F00]
comisd xmm1,xmm0
jna 1E7C4891DD0
...
Giá trị ngưỡng được lưu tại địa chỉ 1E7C4891F00
gán vào thành ghi bổ sung xmm1 và so sánh với xmm0 lưu giá trị X. Add address manually
địa chỉ 1E7C4891F00
đã tìm được với kiểu dữ liệu Double ta thấy giá trị ngưỡng này là 14.5
, tương tự phía bên kia thì địa chỉ là 1E7C4891F10
và giá trị ngưỡng là -14.5
. Khi mình tăng các giá trị ngưỡng này thành 30 và -30 chẳng hạn thì vùng di chuyển của object đã được mở rộng ra
Đến đây tưởng như đã giải quyết xong challenge rồi nhưng thực ra mới được nửa chặng đường thôi
Khi ta điều khiển object nhặt các box phía bên ngoài hình chữ nhật thì object vẫn đi xuyên qua và box không biến mất.
Đến đây thì mình phải Browse memory region
của X và theo dõi xem có gì hay ho không.
Mỗi lần object chạm vào cạnh hình chữ nhật hay chạm vào các box thì ta thấy được một địa chỉ luôn thay đổi theo, vì value của địa chỉ này lại giống một giá trị địa chỉ khác nên mình đánh dấu đây là pointer xem giá trị nó trỏ tới là gì, kết quả lại là một địa chỉ khác nữa nên mình tiếp tục add thêm một offset nữa thì thấy value trỏ đến có giá trị 0x2400000000
. Tóm lại là khi không có va chạm thì value này không tồn tại, còn khi xảy ra va chạm thì value của con trỏ này luôn là 0x2400000000
, mình rất để tâm đến con trỏ này. Để tìm hiểu sâu hơn về con trỏ này, mình chọn Find out what access this address
, sau một hồi theo dõi thì phát hiện ra dòng code cmp dword ptr [rcx],01
được gọi chỉ khi ta lấy được box bên trong hình chữ nhật. Từ đây mình lại debug để tìm ra đoạn code phân biệt giữa box tính điểm bên trong và box chưa thể tính điểm bên ngoài, mình tạm gọi real box
và fake box
cho ngắn gọn.
Sau quá trình debug mình tìm được dòng code phân biệt giữa real box
và fake box
là: call rsi
, với mỗi loại box thì giá trị thanh ghi rsi tương ứng sẽ khác nhau. Đến đây thì ta có thể dùng code injection để sửa giá trị thanh ghi rsi trong trường hợp fake box
cho giống với trường hợp real box
thì đã có thể giải quyết thử thách rồi, Nhưng mình vẫn muốn cách làm đơn giản hơn là tìm dòng code liên quan mà code có cặp dấu ngoặc vuông [ ] và dùng tính năng Find out what address this instruction access
để tìm ra địa chỉ bộ nhớ được truy cập trong 2 trường hợp và chỉnh sửa trực tiếp giá trị bộ nhớ mà thôi.
Tiếp tục trace mình tìm thấy đoạn code move rsi, r9
ở phía trên, vậy bây giờ phải tìm tiếp đoạn code nào gán giá trị cho thanh ghi r9, trace tiếp lên đến hết hàm thì không còn thấy đoạn code nào liên quan đến r9 nữa, vậy phải step out
và trace tiếp thôi. Ra ngoài rồi thấy luôn dòng code: mov r9,[r13+08]
, đã đáp ứng điều kiện rồi bây giờ ta right click vào dòng code chọn Find out what address this instruction access
và qua game lấy các loại box để tìm địa chỉ được access tương ứng thôi, như trường hợp của mình tìm được thì địa chỉ 18C517F16B8
ứng với real box
và địa chỉ 18C517F2518
ứng với fake box
. Tiếp theo chỉ cần sửa value của fake box
giống với real box
là có thể lấy điểm với fake box
rồi.
Khi ăn đủ 20/20 box thì flag xuất hiện. Bạn đọc hãy tự thực hành và lấy được flag nha 🤜🤛
Kết luận
CubeBreaker không chỉ là một thử thách đòi hỏi kỹ thuật mà còn yêu cầu người chơi sự kiên nhẫn và khả năng phân tích từng chi tiết. Qua bài viết, chúng ta đã đi sâu vào quy trình thử nghiệm từng bước từ việc tìm địa chỉ, breakpoint, tới phân biệt các loại box và chỉnh sửa giá trị trong bộ nhớ để hoàn thành mục tiêu. Đây là minh chứng rõ ràng cho việc mỗi thử thách đều có nhiều cách tiếp cận khác nhau, tùy thuộc vào khả năng và sự sáng tạo của người giải. Hy vọng những chia sẻ này giúp ích cho các bạn trong hành trình chinh phục những thử thách tương tự trong tương lai.
Nếu bạn có cách làm nào tối ưu hoặc sáng tạo hơn, đừng ngần ngại chia sẻ để cộng đồng cùng học hỏi nhé!