Modder khôi phục ROM game từ âm thanh crash của GBA
(arstechnica.com)- TheZZAZZGlitch cho thấy có thể ghi âm âm thanh crash của Game Boy Advance để nhận diện dữ liệu game bên trong cartridge, và cuối cùng khôi phục được cùng một ROM
- Điểm cốt lõi là diễn giải âm thanh phát ra sau khi crash như dữ liệu ROM, nhưng cần nhiều điều chỉnh theo từng định dạng nguồn nên khó dùng như một công cụ dump phổ dụng
- Trong hơn 4 giờ ghi âm, một dạng sóng đặc trưng xuất hiện ở khoảng mốc 1 giờ 50 phút, sau đó lần lượt nghe thấy âm thanh nhạc cụ và các mẫu âm thanh của game
- Bằng script Python và hiệu chỉnh căn chỉnh, độ chính xác đạt tới 99,76% nhưng vẫn không boot được; khi gộp 3 bản ghi bằng thuật toán biểu quyết đa số, kết quả cải thiện lên 99,979%
- Sau khi gộp 7 bản ghi và lọc các vùng trống, đạt được mức khớp 100%, xác nhận khả năng thử nghiệm rằng có thể khôi phục ROM GBA chỉ từ âm thanh crash
Thí nghiệm đọc dữ liệu ROM từ âm thanh crash
- TheZZAZZGlitch trình diễn rằng âm thanh GBA phát ra sau khi phần mềm crash có thể chứa dữ liệu game
- Một GBA bị crash có thể tiếp tục phát ra âm thanh dựa trên dữ liệu bên trong cartridge; với phần cứng và mã đặc biệt để phân tích âm thanh này, có thể nhận diện đó là game nào
- Tuy nhiên, cách này không phải là phương pháp dễ dàng để dump dữ liệu cartridge, cũng không phải là giải pháp dùng ngay được
- Cần rất nhiều tinh chỉnh phù hợp với các định dạng nguồn khác nhau
Dạng sóng lộ ra trong bản ghi dài
- Sau khi làm GBA crash và ghi âm hơn 4 giờ, một dạng sóng đặc trưng xuất hiện ở khoảng mốc 1 giờ 50 phút
- Ở các đoạn sau đó, có thể nghe lần lượt các âm thanh nhạc cụ và mẫu âm thanh thực sự có trong game
- Phần dữ liệu còn lại nghe như dữ liệu 8-bit ở 13.100Hz, và một số đoạn nghe rất kỳ lạ
Script Python và lần thử khôi phục đầu tiên
- TheZZAZZGlitch đã chuẩn bị một script Python để đọc bản ghi dump crash GBA sạch, sau “2 ngày sửa lỗi”
- Trong dữ liệu ROM có những vùng byte 0 lớn, và các phần này xuất hiện như im lặng nên khó parse từ âm thanh
- Sau khi chạy một script riêng để căn chỉnh lại các section dựa trên vị trí trong ROM gốc, ROM được khôi phục đạt độ chính xác 99,76%
- ROM này vẫn không boot được, và vì sử dụng dữ liệu ROM đã biết để làm lộ dữ liệu chưa biết nên về mặt kỹ thuật được xem là “gian lận”
- Ngay cả khi tiến hành hoàn toàn mù, vẫn còn những giả định và suy đoán có thể áp dụng
Gộp nhiều bản ghi để tăng độ chính xác
- Bước tiếp theo tập trung vào cải thiện chất lượng ghi âm
- Khi gộp kết quả từ 3 lần ghi bằng thuật toán “biểu quyết đa số”, độ chính xác tăng lên 99,979%
- ROM đầu ra này boot được, nhưng văn bản bị lỗi hiển thị và xảy ra crash ở màn hình tiêu đề
- Sau đó, khi kết hợp 7 bản ghi và lọc các vùng trống, họ đạt mức khớp 100%
Phần cứng vật lý và các thí nghiệm bổ sung
- Ở nửa sau video, họ cũng kiểm tra cách phương pháp này hoạt động trên phần cứng vật lý
- Họ thử nghiệm với các game khác, đồng thời lần theo một bí ẩn liên quan đến mã ARM bên trong cartridge sao chép
- Một số cách để thu được bản ghi tốt hơn cũng được thử nghiệm
- Một trong số đó là dùng “cursed adapter” để mixdown thô xuống một kênh
1 bình luận
Ý kiến trên Hacker News
Vấn đề khi
0x00kéo dài liên tục có liên quan đến khôi phục xung nhịp (clock recovery)Một số luồng dữ liệu số, đặc biệt là dữ liệu thô từ đầu từ của ổ đĩa hoặc truyền thông nối tiếp tốc độ cao như Ethernet, được truyền mà không có tín hiệu clock riêng
Bộ thu tạo clock dựa trên một chuẩn tần số gần đúng, rồi dùng vòng khóa pha (PLL) để căn pha clock theo các điểm chuyển mức của luồng dữ liệu
Để cách này hoạt động, các điểm chuyển mức trong dữ liệu phải xuất hiện đủ thường xuyên để bù trôi của bộ dao động PLL, và khoảng thời gian có thể chịu được lâu đến đâu khi không có chuyển mức được gọi là thông số CID tối đa (consecutive identical digits)
https://en.wikipedia.org/wiki/Clock_recovery
Sau đó người ta chuyển sang cách gắn header ngắn vào các khối bit lớn như 64/66b để đảm bảo có chuyển mức clock, rồi cho toàn bộ dữ liệu đi qua bộ xáo trộn giả ngẫu nhiên
Ngay cả khi clock được đồng bộ hoàn hảo, trong các đoạn dài thì tín hiệu gần như toàn 1 và tín hiệu gần như toàn 0 rốt cuộc sẽ trở nên giống hệt nhau
Âm thanh là tín hiệu analog, và để giải mã thành bitstream thì cần DAC, đồng thời nó được truyền ở tần số cố định như 44.1kHz hay 48kHz mà không cần đồng bộ đặc biệt
https://en.wikipedia.org/wiki/Wireless_Set_Number_10
Gợi nhớ đến vụ hack iPodLinux nguyên thủy, khi gần 20 năm trước họ dump firmware iPod thế hệ 4 bằng loa piezo
https://web.archive.org/web/20140810083116/http://www.newscientist.com/article/dn7085
Tình cờ là nhờ vậy mà người ta cũng có thể chạy game GBA trên iPod, nhưng chỉ riêng việc chơi Doom bằng click wheel và xem video đen trắng đã đủ khiến tôi thấy mãn nguyện rồi
Tôi vẫn còn giữ một chiếc iPod Classic, đã nâng cấp pin và lắp vào 4 thẻ MicroSD 256GB
Gần đây tôi cũng thấy bản mod thêm Bluetooth, nhưng phải thay cả nắp lưng nên chắc tôi không làm tới mức đó
Cả thiết kế lẫn cảm giác tự mình sở hữu bản sao các file nhạc đều có một sức hút không phai theo thời gian
Thật vui khi chủ đề này được chú ý hơn ở đây
Nó cũng đã được đăng mấy ngày trước nhưng chìm mất: https://news.ycombinator.com/item?id=39037104
Video gốc có nhiều nội dung hơn bài viết ngắn này, bao gồm cả adapter tùy chỉnh do hacker tự cắt dán để đạt được chất lượng âm thanh phù hợp từ DS
https://www.youtube.com/watch?v=0-7PSmYYHF0
Zzazz tổ chức một cuộc thi/sự kiện Cá tháng Tư hằng năm, và thường có xen vào một mức độ nào đó của retro hacking hoặc reverse engineering
Rất đáng để tham gia
Các cuộc thi trước đây đều có trên GitHub
Kiến trúc âm thanh của Nintendo lúc nào cũng rất thú vị
Ban đầu NES có một bộ tạo mẫu có thể tạo dạng sóng tùy ý, và có thể chạy theo hai cách
Một cách là đưa cho nó một địa chỉ bộ nhớ, nó sẽ đọc các bit và xử lý thành dạng sóng cực kỳ đơn giản, trong đó 1 nghĩa là “tăng giá trị lên một đơn vị”, còn 0 là “giảm giá trị xuống một đơn vị”, nên nếu muốn tạo dạng sóng phẳng thì phải lặp kiểu
10101010Cách còn lại là CPU liên tục tự ghi “giá trị khởi tạo” vào để điều khiển chip trực tiếp, mà trên thực tế còn nhanh hơn việc để driver âm thanh đọc bit từ RAM
Vấn đề là cách này ngốn sạch chu kỳ CPU, nên chỉ dùng được khi không cần làm việc gì khác
Các game như Battletoads đã tận dụng điều đó để phát các cú đánh trống chất lượng cao hơn trong lúc hành động tạm dừng, và dùng nó ở màn hình tiêu đề, hiệu ứng “giòn” khi mọi hành động khựng lại thoáng chốc lúc tung đòn cuối vào kẻ địch, cùng bản nhạc tạm dừng rất đáng nhớ
Đây là bản demo cho thấy game chuyển đổi giữa chế độ điều khiển trực tiếp và chế độ để chip tự đọc mẫu. Retro Game Audio đã đăng một video chỉnh sửa bằng emulator để chỉ ra đúng khoảnh khắc đi vào subroutine điều khiển trực tiếp: https://www.youtube.com/watch?v=JGT0FM3yh-w
Ban đầu tôi thắc mắc vì sao chuyện này lại xảy ra
Việc những game như thế này dump trạng thái thành âm thanh có phổ biến không? Đây có phải là một công cụ gỡ lỗi được chủ ý dành cho nhà phát triển game không?
Về cơ bản, âm thanh của GBA phát trực tuyến audio từ một bộ đệm trong RAM, và ngắt phải báo cho phần cứng quay lại đọc từ đầu bộ đệm
Nhưng nếu ngắt không xảy ra, như khi game bị crash, thì luồng âm thanh sẽ vượt ra ngoài bộ đệm và đọc sang các vùng bộ nhớ khác
[1] https://www.youtube.com/watch?v=wSWNkpqjtQY&t=361s
Về lý thuyết, GBA có thể đã được thiết kế để “đóng băng” kiến trúc khi game bị crash, hoặc có một watchdog gắn các cập nhật trạng thái phải chạy định kỳ vào ngắt không thể che, để nếu các cập nhật đó dừng lại thì máy sẽ khởi động lại
Nhưng các tính năng như vậy tốn thêm chi phí, nên GBA không có
Nintendo về cơ bản đã chọn cách tiếp cận truyền thống của các nhà sản xuất băng game đời cũ: “nếu game của chúng ta không có bug, thì không cần lo phần cứng sẽ làm gì trong trạng thái không xác định”
Vì vậy, khi một game GBA rơi vào trạng thái crash như vòng lặp vô hạn với ngắt bị vô hiệu hóa, chip âm thanh không hề biết hệ thống đã crash và cứ tiếp tục làm việc đơn giản là đọc các bit liên tiếp từ RAM rồi biến chúng thành âm thanh
Trong hoạt động bình thường, quy trình dọn dẹp quản lý việc đọc này sẽ tồn tại, nhưng khi nó biến mất thì việc đọc cứ tiếp diễn cho đến lúc chạm tới cả những bit biểu diễn giá trị của cartridge ROM
Thật sự ấn tượng đến mức khó tin
Có cảm giác những kỹ thuật như thuật toán bỏ phiếu đa số dùng ở đây vẫn chưa được khai thác đủ trong nhiều ngành công nghiệp
Các thiết bị lưu trữ từ tính về cơ bản hoạt động theo cùng nguyên lý như màn hack này
https://en.wikipedia.org/wiki/Partial-response_maximum-likelihood
Cùng ý tưởng đó cũng có thể áp dụng ở đây, vì nội dung ROM GBA có thể sẽ có độ thiên lệch mạnh
Bỏ phiếu đa số làm lãng phí rất nhiều thông tin
Chỉ cần chồng tất cả ảnh lên nhau rồi giữ lại giá trị trung vị cho từng pixel[1]
[1]: https://patdavid.net/2013/05/noise-removal-in-photos-with-median_6/
Người ta sẽ đọc đi đọc lại ảnh đĩa, chạy cơ chế xét đủ số phiếu, rồi khi ra được kết quả vượt qua checksum thì xem có hoạt động đúng không
Nếu có checksum ở mức cao hơn như chữ ký tệp thì càng tốt cho việc xác minh thêm
Nó cũng được dùng trong một số ứng dụng hàng không vũ trụ
Vì họ xử lý các bản in chiếu rạp có thể đã hư hại chứ không phải bản master pristine, nên nếu có thể dùng nhiều bản để loại bỏ vết xước v.v. thì sẽ giảm cực nhiều thời gian chỉnh sửa thủ công ở hậu kỳ
Việc 0xFF bị biến thành 0x00 có thể là do tụ chặn DC hoặc lọc thông cao
Mạch âm thanh không thực sự phù hợp với nội dung không nghe được
Nếu may mắn, việc nối trực tiếp một máy hiện sóng số vào đầu ra âm thanh của chip có thể cải thiện độ chính xác khi capture, nhưng dù vậy việc lấy ra được một image có thể khởi động vẫn rất ấn tượng
Vì thế họ đã dành hàng giờ để capture lặp đi lặp lại và lấy trung bình lỗi, thay vì dùng máy hiện sóng ghi dữ liệu đúng nghĩa
Chỉ một cách đơn giản như mã hóa Manchester cũng đã giúp ích rất nhiều
Nếu thế vẫn chưa đủ thì có thể dùng NRZ hoặc thậm chí mã hóa chập
Ngoài ra cũng có thể gửi sóng sin, hoặc nếu không được thì ít nhất phải đẩy tần số sóng vuông lên đủ cao để không bị tụ ghép AC nuốt mất
Phần ấn tượng nhất trong tất cả chuyện này, với cá nhân tôi, là cách những kẻ sao chép lậu đã sửa code để chạy game từ flash có thể ghi được thay vì từ ROM + bộ nhớ lưu trữ bay hơi
Thực ra việc tạo ra các bản vá như vậy cũng không quá khó
Những kẻ sao chép lậu sẽ reverse engineering sơ qua vị trí mà mã game ghi dữ liệu, rồi viết bản vá riêng cho từng game để flush dữ liệu lưu vào flash có thể ghi được
Tuy nhiên, game GBA chính thức luôn dùng các hàm của Nintendo SDK để lưu, nên nếu hook các hàm đó thì có thể tạo ra một bản vá tổng quát khá đơn giản giúp bất kỳ game GBA nào cũng lưu được trên cartridge sao chép không pin
Tôi đã viết một công cụ vá làm việc này và có thể xem tại đây
https://github.com/metroid-maniac/gba-auto-batteryless-patcher
Có ai biết bên trong chuyện gì xảy ra khi trình giả lập của TheZZAZZGlitch báo rằng game đang cố nhảy tới một địa chỉ sai không?
Tôi không quen với bộ xử lý ARM7 dùng trong GameBoy Advance, nhưng thật khó hình dung làm sao có thể tạo ra một lệnh gọi nhảy với giá trị sai như vậy
Tôi cũng tò mò nếu chạy một trong các ROM được khôi phục sai của TheZZAZZGlitch trên máy GameBoy thật thì chuyện gì sẽ xảy ra
bx, bạn có thể nhảy tới bất kỳ địa chỉ nào được lưu trong thanh ghiVà nếu chạy ROM được khôi phục sai trên máy GameBoy thật, nó sẽ crash và cuối cùng bắt đầu phát ROM qua loa
Đó chính là ý chính của video :)
Còn trên phần cứng thật thì sẽ thế nào... ai mà biết được :)