Gần đây, khi lướt Facebook, tôi thấy có bài cảnh báo về việc kẻ gian dụ nạn nhân cài ứng dụng chứa mã độc để chiếm đoạt tiền trong tài khoản ngân hàng. Chi tiết tại bài viết trên Facebook.
Thủ đoạn này không mới nhưng vẫn còn có hiệu quả.


Website phishing
Địa chỉ website được đề cập trong bài viết là vndvc-vndvc.cc. Google Safe Browsing đã gắn nhãn phishing, song trang vẫn có thể truy cập tại thời điểm kiểm tra.

Giao diện bắt chước trang tải app của Google Play, cho phép download apk tên DỊCHVỤCÔNG.apk. App này đạt 4.6 sao và có hơn 1 triệu bài đánh giá, đương nhiên là fake.

Tôi đã thử tải về và thực hiện phân tích sơ bộ APK này.
Phân tích
Xem qua cấu trúc apk, có hai điểm đáng chú ý là file assets/OoooooOooo và thư mục chứa thư viện native assets/vwwwwwvwww/ (các file lib*.so theo ABI).

APK được pack bằng tool dpt-shell.
Cơ chế tổng quát: packer thu thập các file DEX trong APK, biến đổi thành i11111i111.zip và OoooooOooo. Thư viện trong assets/vwwwwwvwww/<abi>/lib<random>.so được thêm vào để khi chạy app khôi phục mã gốc. Logic ban đầu của các DEX chỉ nằm trong hai khối dữ liệu đó; phần còn lại phục vụ giải nén và nạp đúng.
- i11111i111.zip: chứa các DEX đã bị “nop” phần thân method, chỉ còn khung class/method. File không nằm riêng rẽ trong APK mà được tách ra khi chạy, app sẽ trích từ classes.dex và đặt dưới
/data/data/<app>/code_cache. - OoooooOooo: chứa dữ liệu mã thật, nằm trong assets/ của APK.
Khi runtime gọi một class, packer sẽ giải mã và điền lại bytecode vào body các method tương ứng; toàn bộ diễn ra trong bộ nhớ.
Unpack APK
Quy trình unpack như sau:
graph LR
A[Protected APK] --> B(Unzip)
B --> C["Parse assets/OoooooOooo<br/>(MultiDexCode:<br/>dexIndex<br/>-> methodIndex<br/>-> insns bytes)"]
B --> D["Extract i11111i111.zip<br/>(file zip được thêm vào<br/>cuối classes.dex,<br/>4 bytes cuối = zip length)"]
D --> E["Unzip i11111i111.zip -><br/>classes*.dex files"]
C --> F{For each classes*.dex}
E --> F
F --> G["Từ dexIndex<br/>-> duyệt methodIndex<br/>-> Lookup insns tương ứng"]
G --> H[Ghi insns<br/>trở lại method]
H --> I["Fix dex hashes<br/>(SHA1<br/>+ checksum<br/>+ file size)"]
I --> J[Output:<br/>classes*.dex]
Tôi đã tái sử dụng code, logic từ packer để viết tool unpack các file DEX gốc; xem tại github.com/sonx4444/dpt-unpack.
Trong i11111i111.zip có: classes.dex mang logic chính, classes2.dex là junk code. Kết quả sau khi unpack:

Dưới đây là vài ví dụ minh họa so sánh code trước và sau khi unpack:
Trước:

Sau:

Trước:

Sau:

Có thể thấy rằng sau khi unpack, method đã được khôi phục đầy đủ.
String deobfuscation
String trong APK được obfuscate như sau:

JEB có chức năng tự động deobfuscate string. Load vào JEB và export decompiled code.
Một phần log JEB trong quá trình deobfuscate string:
[I] Method Lo1/o$l;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;: Decrypted string: "call to \'resume\' before \'invoke\' with coroutine"
[I] Method Lo1/o$l;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;: Decrypted string: "shot crop "
[I] Method Lo1/o$l;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;: Decrypted string: "shot with accessibility"
[I] Method Lo1/o$l;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;: Decrypted string: "imageCapturing,can\'t shot."
[I] Method Lo1/o$l;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;: Decrypted string: "shot with ScreenRecorder"
[I] Method Lo1/o$l;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;: Decrypted string: "screenShot ---> "
[I] Method Lo1/o$l;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;: Decrypted string: "ScreenRecorder shot failed: "
[I] Method Lo1/o$l;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;: Decrypted string: "screenshot failed"
[I] Method Lo1/o$l;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;: Decrypted string: "imageCapturing,can\'t shot."
[I] Method Lo1/o$l;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;: Decrypted string: "screenshot failed"
...
[I] Method Lf/z/x/do;->for(Landroid/view/accessibility/AccessibilityEvent;)V: Decrypted string: "event"
[I] Method Lf/z/x/do;->for(Landroid/view/accessibility/AccessibilityEvent;)V: Decrypted string: "com.mservice.momotransfer"
[I] Method Lf/z/x/do;->for(Landroid/view/accessibility/AccessibilityEvent;)V: Decrypted string: "Enter password/TextInput"
[I] Method Lf/z/x/do;->for(Landroid/view/accessibility/AccessibilityEvent;)V: Decrypted string: "Nhập mật khẩu/TextInput"
[I] Method Lf/z/x/do;->for(Landroid/view/accessibility/AccessibilityEvent;)V: Decrypted string: "Please"
[I] Method Lf/z/x/do;->for(Landroid/view/accessibility/AccessibilityEvent;)V: Decrypted string: "/"
...
[I] Method Landroidx/core/remo/modules/nm$ۥ۠;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;: Decrypted string: "initApiSuccess"
[I] Method Landroidx/core/remo/modules/nm$ۥ۠;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;: Decrypted string: "status"
[I] Method Landroidx/core/remo/modules/nm$ۥ۠;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;: Decrypted string: "OK"
[I] Method Landroidx/core/remo/modules/nm$ۥ۠;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;: Decrypted string: "initApiSuccess"
[I] Method Landroidx/core/remo/modules/nm$ۥ۠;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;: Decrypted string: "init device api call failed: "
[I] Method Landroidx/core/remo/modules/nm$ۥ۠;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;: Decrypted string: "init device api call failed "
[I] Method Landroidx/core/remo/modules/nm$ۥ۠;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;: Decrypted string: "init device api call failed"
[I] Method Landroidx/core/remo/modules/nm$ۥ۠;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;: Decrypted string: "domain"
[I] Method Landroidx/core/remo/modules/nm$ۥ۠;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;: Decrypted string: "isHostReachable "
[I] Method Landroidx/core/remo/modules/nm$ۥ۠;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;: Decrypted string: " isHostReachable: "
[I] Method Landroidx/core/remo/modules/nm$ۥ۠;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;: Decrypted string: "init device api call failed"
Các chuỗi này phản ánh chức năng của mã độc, bao gồm chụp màn hình, accessibility, kết nối đến hạ tầng điều khiển, v.v.
IOCs và các cấu hình liên quan
Endpoints, URLs:
https://sock8.top:8081— C2 chínhhttps://ping.shop4s.cc:8181— API/device/addOrUpdateDevice/device/deviceUpdateVerify/device/getAllDeviceAppPackageSetting/device/saveAddressBookList/device/saveAppList/device/saveKeyboardEvent/device/saveScreenIn/device/saveScreenText/device/uploadErrorFile/device/uploadFlowingWater
wss://ping.shop4s.cc— WebSocket điều khiển thời gian thựcwss://ping.shop4s.cc:8989— Janus WebSocket (streaming/WebRTC)ping.yna1m4s.vip:8443— ZLK serverhttps://ping.yna1m4s.vip:8443/index/api/webrtc?app=live&stream={device_id}&type=pushrtmp://ping.yna1m4s.vip:8443/live/{device_id}rtsp://ping.yna1m4s.vip:8443/live/{device_id}
https://h5.shop4adm.cc— panel/admin load trong WebView (phishing)https://cpcom.cyou:9000— upload/download dữ liệuhttps://ap-southeast-5.log.aliyuncs.com— upload/download qua log servicehttps://test09966.s3.ap-east-1.amazonaws.com/WebView.apk— tải thêm APKhttps://raw.githubusercontent.com/o8g4q/i/main/l— repo GitHub còn hoạt động (từ 2023; có thể chứa config, không thấy nội dung đặc biệt khi kiểm tra)
Configuration:
- appName: DỊCHVỤCÔNG
- buildType: release
- buildTime: 2026-01-12 20:28:11
- buildTheme: 0-vnsho4pmadm
- buildHash: 0b0483c
- PBuild; deviceId, deviceNumber, distHosts: trống trong bản build phân tích
- apiUrl:
https://ping.shop4s.cc:8181 - wsUrl:
wss://ping.shop4s.cc - zlkServer:
https://ping.yna1m4s.vip:8443 - janusWsUrl:
wss://ping.shop4s.cc:8989 - screenPushMode: janus
- BRAND:
Build.BRAND, MODEL:Build.MODEL, Pid:Process.myPid(), Process, App:getApplicationInfo().name, SYS_VER:Build.VERSION.RELEASE(Build.VERSION.SDK_INT)
Alibaba Cloud Log Service (thử truy cập nhưng không thành công):
- LSL Producer:
https://ap-southeast-5.log.aliyuncs.com - Project:
[REDACTED] - AccessKeyId:
[REDACTED] - AccessKeySecret:
[REDACTED] - Logstore:
[REDACTED]
AWS:
- Endpoint:
https://cpcom.cyou:9000 - AccessKeyId:
[REDACTED] - AccessKeySecret:
[REDACTED] - Region: us-east-1
Capabilities:ACC_DISABLE, ACC_ENABLE, CALL_FORWARD, CANCEL_UNLOAD, CLICK, CLOSE_SCREEN, DELETE_SMS, DISABLE_ACCESSIBILITY, DOWNLOAD_FILE, ENABLE_POWER_IGNORE, GESTURE, GET_APP_LIST, GET_CONTACTS_LIST, GET_DEVICE_STATUS, GET_LOCATION, GET_SMS_LIST, HIDE_FLOAT_WIN, HIDE_MASK, INSTALL_APK, LIGHT_SCREEN, NAV_BACK, NAV_HOME, NAV_NOTIFICATIONS, NAV_RECENTS, OPEN_ACCESSIBILITY, OPEN_APP, POWER_DIALOG, RECOVER_IME, REFRESH_SCREEN, REMOVE_DEVICE_ADMIN, REQUEST_PERMISSIONS, SCREEN_SHOT, SEND_SMS, SET_DEFAULT_SMS, SET_DEVICE_ADMIN, SET_IME, SET_TEXT, SHOW_FLOAT_WIN, SHOW_MASK, SMS_SETTINGS, START_CAPTURE, START_IMAGE_MODE, START_IMAGE_MODE_NO_AUTO_GRANT, STOP_CAPTURE, STOP_IMAGE_MODE, SWIPE_DOWN, SWIPE_LEFT, SWIPE_RIGHT, SWIPE_UP, TAKE_PHOTO, UNINSTALL_APK, UNINSTALL_APP, UNLOAD, UNLOCK_SCREEN, UN_CALL_FORWARD.
Banking / Wallet:
- Ngân hàng: MB (
com.mbmobile), VietinBank (com.vietinbank.ipay), Agribank (com.vnpay.Agribank3g), TPBank (com.tpb.mb.gprsandroid), VPBank (com.vnpay.vpbankonline), Techcombank (vn.com.techcombank.bb.app). - Ví: MoMo (
com.mservice.momotransfer), Coinomi, Trust Wallet, MEW.
Trong mã nguồn có nhiều chuỗi tiếng Trung; một số API cũng trả về thông báo tiếng Trung — có thể gợi ý về nguồn gốc nhóm phát triển hoặc hạ tầng, nhưng chưa thể kết luận chắc chắn.
Kết luận
Với người dùng phổ thông, lưu ý ngắn gọn: chỉ nên tải app từ Google Play trực tiếp trên điện thoại, không cài ứng dụng từ bất kỳ nguồn nào khác, không cài từ APK.
Google sắp tới sẽ siết yêu cầu định danh nhà phát triển và hạn chế cài APK ngoài cửa hàng (side load). Một mặt điều đó làm giảm sự tự do cho người thích vọc vạch, nhưng mặt khác sẽ khiến kiểu lừa đảo như trên khó thực hiện hơn nhiều so với bây giờ.