Kỹ sư đảo ngược app phòng gym để bỏ qua mạng xã hội

Phần mềm06 tháng 11, 2026·4 phút đọc

Một người dùng khó chịu vì app phòng gym biến màn hình chính thành bảng tin mạng xã hội đã tự đảo ngược (reverse-engineer) ứng dụng để trích xuất khóa mã hóa, từ đó tự tạo mã QR điểm danh bằng web. Câu chuyện cho thấy giới hạn của các mô hình ứng dụng ép người dùng tương tác mạng xã hội.

Kỹ sư đảo ngược app phòng gym để bỏ qua mạng xã hội

Một người dùng vừa chia sẻ câu chuyện đảo ngược (reverse-engineer) ứng dụng của phòng gym mới mà anh tham gia, chỉ vì ứng dụng này biến màn hình chính thành một bảng tin mạng xã hội đầy ảnh selfie của người tập. Điều anh cần duy nhất chỉ là mã QR quét ở cổng để điểm danh ra vào.

Sự việc đáng chú ý ở chỗ nó cho thấy: khi một sản phẩm công nghệ ép người dùng chấp nhận những trải nghiệm họ không muốn, người có chuyên môn kỹ thuật hoàn toàn có thể tìm cách đi vòng.

Một ứng dụng tốt, nhưng mắc thứ người dùng không cần

Theo bài viết, đây không phải ứng dụng làm ẩu. Nó có giao diện và trải nghiệm người dùng (UI/UX) khá chỉn chu, ngôn ngữ thiết kế nhất quán, và tác giả chỉ tìm ra đúng một lỗi. Vấn đề nằm ở triết lý sản phẩm: màn hình chính là một bảng tin mạng xã hội, và sau khi check-out, ứng dụng thúc người dùng đăng story về buổi tập.

Với tác giả — người đã không dùng mạng xã hội hơn 12 năm và luôn chặn quảng cáo, bình luận YouTube, Shorts và video gợi ý — việc bị buộc phải xem một bảng tin không thể tắt, sắp xếp hay lọc bị coi là "chiến tranh tâm lý". Anh quyết định thử tách riêng phần logic mã QR khỏi toàn bộ phần thừa của ứng dụng.

Những gì nằm trong mã QR

Quá trình tìm hiểu cho thấy mã QR thay đổi mỗi 15 giây, và ứng dụng chặn chụp màn hình ở màn hình này, phù hợp với cờ FLAG_SECURE của Android. Khi tắt Wi-Fi, ứng dụng báo mã vẫn hợp lệ trong một số ngày nhất định — nghĩa là mã được sinh cục bộ trên máy chứ không phải từ máy chủ.

Ứng dụng được viết bằng Flutter, với phần lớn logic biên dịch sang mã Dart native. Tác giả dùng blutter để soi phần Dart, jadx cho phía Android, công cụ SDK của Android để xem gói ứng dụng, sau đó dùng OpenSSL và WebCrypto để kiểm tra phần mã hóa, và zbar để giải mã QR độc lập.

Mã QR hóa ra là một URL chứa bốn thành phần: tài khoản được mã hóa, dấu thời gian hết hạn được mã hóa, một nonce (số dùng một lần) ngẫu nhiên và một checksum (mã kiểm tra). Thời hạn được mã hóa bằng AES-128-CTR, còn checksum tính bằng một khóa bí mật riêng. Như vậy cần hai khóa bí mật gắn với tài khoản người dùng.

Từ giả định sai đến mã QR chạy thật

Ban đầu tác giả định để AI điều khiển trình giả lập Android để đăng nhập và trích xuất khóa, nhưng chiếc laptop mười năm tuổi không đủ sức chạy giả lập. May mắn là anh còn một chiếc điện thoại Android đã root. Kết nối qua ADB không dây, nhóm phát hiện ứng dụng ghi lại toàn bộ payload yêu cầu và phản hồi vào một tệp log văn bản thường — khóa nằm ngay đó.

Quá trình này cũng có vài giả định sai: dấu thời gian phải tính bằng mili giây chứ không phải giây; mã hóa dùng base64url và vẫn giữ phần đệm, không phải base64 chuẩn; và có một bản AES viết sai nhưng vẫn "qua" bài kiểm tra vòng lặp vì cả mã hóa lẫn giải mã mắc cùng một lỗi. So sánh với WebCrypto và các test vector của OpenSSL đã phát hiện sai lệch.

Kết quả là một ứng dụng web SvelteKit sinh mã QR cục bộ từ khóa đã trích xuất. Với cùng đầu vào, bản dựng này tạo ra URL trùng khớp từng byte với ứng dụng gốc. Hôm sau, tác giả tới phòng gym, khoe với bạn và thử quét — điểm danh vào và ra đều thành công.

Góc nhìn

Câu chuyện là một lời nhắc cho các nhóm phát triển sản phẩm: khi đặt mạng xã hội lên trước nhu cầu cốt lõi, bạn đang tạo ra động lực để người dùng kỹ thuật tìm đường vòng. Với lập trình viên, đây cũng là ví dụ thực tế về quy trình kiểm thử bảo mật phía client: ứng dụng Flutter bị đảo ngược dễ dàng, khóa mã hóa bị ghi ra log văn bản thường, và mã điểm danh sinh cục bộ thì không thể giữ bí mật trước người có quyền truy cập thiết bị đã root.

Cần lưu ý rằng cách làm này chỉ giải quyết việc sinh mã, không thay thế đăng nhập độc lập và vẫn cần lấy khóa mới khi khóa bị xoay. Với doanh nghiệp, bài học thực dụng hơn nằm ở thiết kế: nếu tính năng cốt lõi là điểm danh, hãy đảm bảo nó không bị chôn dưới những lớp tương tác mà người dùng không thể tắt — bởi chi phí để họ rời bỏ thường thấp hơn nhiều so với chi phí bảo vệ phần client.

Nguồn: shayon.work · Quy trình biên tập

Chia sẻ:FacebookX