# Phân tích mã độc android
## Thông tin cơ bản
MD5: `ec054b7025b9c35692d42163d1e0bd9f`
App name: `DỊCH VỤ CÔNG`
Package name: `com.phommvb.dotihanj`
Arch: `arm64-v8a, armeabi-v7a`
Target SDK: `32: Android 12.0L`
Permission:
```
android.permission.CAMERA
android.permission.BIND_ACCESSIBILITY_SERVICE
android.permission.REQUEST_DELETE_PACKAGES
android.permission.QUERY_ALL_PACKAGES
android.permission.GET_INSTALLED_APPS
android.permission.VIBRATE
android.permission.WRITE_EXTERNAL_STORAGE
android.permission.READ_EXTERNAL_STORAGE
android.permission.GRANT_RUNTIME_PERMISSIONS
android.permission.READ_SYNC_STATS
android.permission.READ_SYNC_SETTINGS
android.permission.DISABLE_KEYGUARD
android.permission.WAKE_LOCK
android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
android.permission.RECEIVE_BOOT_COMPLETED
android.permission.SYSTEM_ALERT_WINDOW
android.permission.WRITE_SETTINGS
android.permission.FOREGROUND_SERVICE
android.permission.READ_SMS
android.permission.SEND_SMS
android.permission.ACCESS_NETWORK_STATE
android.permission.ACCESS_WIFI_STATE
android.permission.USE_FULL_SCREEN_INTENT
android.permission.SET_WALLPAPER
android.permission.CALL_PHONE
android.permission.INTERNET
android.permission.BATTERY_STATS
```
ApkID:

Qua các thông tin trên, ta thấy được mã độc yêu cầu cấp nhiều quyền nhạy cảm. Đồng thời, sử dụng trình protector `Virbox` đối với các lib `l4ccd64a6_***.so`.
## Phân tích chi tiết
AndroidManifest.xml:
```xml
.................
<application
android:theme="@style/md2"
android:label="@string/ehv"
android:icon="@mipmap/b1w"
android:name="v4ccd64a6.l4ccd64a6"
android:screenOrientation="portrait"
android:allowBackup="true"
android:hardwareAccelerated="true"
android:supportsRtl="true"
android:usesCleartextTraffic="true"
android:networkSecurityConfig="@xml/ebz"
android:appComponentFactory="androidx.core.app.CoreComponentFactory"
android:requestLegacyExternalStorage="true">
<meta-data
android:name="SAPP_NAME"
android:value="com.yiwuzhibo.BaseApplication"/>
<activity
android:name="com.yiwuzhibo.activity.NNNNNNNAAAAActivity"
android:screenOrientation="portrait"/>
<activity
android:label="@string/xao"
android:icon="@mipmap/b1w"
android:name="com.yiwuzhibo.activity.SplashActivity"
android:exported="true"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
.......
```
Theo file AndroidManifest.xml, `v4ccd64a6.l4ccd64a6` sẽ là entrypoint được chạy khi người dùng nhấn vào icon để mở ứng dụng.

Chúng ta thấy có string "virbox", trình protector được sử dụng cho các lib trong asset. Rename lại class,method để thuận tiện hơn. Drop file lib `.so` và load:

Overload `onCreate`:

Tất cả mã nguồn tại entrypoint của chương trình tại đây:[source](https://gist.github.com/h1bAna/d13786debda788a5a4c61c719bfcad12)
Tổng quát lại, tại entrypoint của chương trình, mã nguồn thực hiện các hành vi sau:
+ drop file lib và load
+ Khởi tạo môi trường phù hợp để phục vụ cho việc dynamic loading. Mình đọc qua 3 hàm `swapApplicationReferences`, `updateAssetManager`,`reinstallContentProviders` thì thấy có chút liên quan đến bài [này](https://mp.weixin.qq.com/s/Uwr6Rimc7Gpnq4wMFZSAag?utm_source=androidweekly&utm_medium=website)
File `index.html, kqkticwjgzy.dat` cũng đã được encrypt:


Khi thử phân tích tĩnh file thư viện trong `asset`, ta cũng không thu được gì. Do file đã được bảo vệ bằng `virbox`, rất có thể thư viện đã bị obfuscate. Rất nhiều đoạn tại phân vùng `.text` công cụ không nhận diện được, các hàm thì rất khó đọc và phân tích code.

Tiến hành cái ứng dụng lên môi trường test, ứng dụng có sử dụng các cơ chế detect root, detect developer mode, detect unlock bootloader,.... để phát hiện môi trường test. Có thể bypass bằng các cài thêm các module ẩn root, ẩn developer mode,....
Giao diện ứng dụng khi truy cập:

Sử dụng frida để dump các class trong quá trình runtime: [script](https://github.com/apkunpacker/DexDumper/tree/main)


Các string từ các class được dump từ dex ra đã bị mã hóa, được giải mã trong lúc runtime bằng method `m4ccd64a6.F4ccd64a6_11()`. Tuy nhiên, hàm này là hàm native code, load từ thư viện. Điều này khiến việc decrypt string khó khăn hơn. Vì chưa tìm được cách reverse được method này nên mình dùng hook để bắt input và output. Recover lại được kha khá string.

```javascript=
Java.perform(function() {
console.log("[*] Starting script");
Java.enumerateLoadedClasses({
onMatch: function(className) {
if (className.includes("m4ccd64a6")) {
console.log(`[*] Potential target class found: ${className}`);
hookTargetClass(className);
}
},
onComplete: function() {
console.log("[*] Finished enumerating loaded classes");
}
});
function hookTargetClass(targetClassName) {
Java.perform(function() {
try {
var targetClass = Java.use(targetClassName);
var targetMethod = targetClass.F4ccd64a6_11.overload('java.lang.String');
targetMethod.implementation = function(arg0) {
console.log(`[*] Hooked ${targetClassName}.F4ccd64a6_11`);
console.log(`[*] Input: ${arg0}`);
var result = this.F4ccd64a6_11(arg0);
console.log(`[*] Output: ${result}`);
return result;
};
console.log(`[*] Hooking successful for ${targetClassName}.F4ccd64a6_11`);
} catch (e) {
console.log(`[*] Error: ${e}`);
}
});
}
});
```
Sau khi đã có thể hook được thành công, mình nghĩ liệu mình có thể tự gọi hàm bằng frida? Và câu trả lời là có. Đây là ví dụ:
```javascript=
Java.perform(function() {
console.log("[*] Starting script");
// Liệt kê tất cả các class đã được load
Java.enumerateLoadedClasses({
onMatch: function(className) {
if (className.includes("m4ccd64a6")) {
console.log(`[*] Potential target class found: ${className}`);
callTargetMethod(className);
}
},
onComplete: function() {
console.log("[*] Finished enumerating loaded classes");
}
});
function callTargetMethod(targetClassName) {
Java.perform(function() {
try {
// Sử dụng class được load động
var targetClass = Java.use(targetClassName);
// Gọi hàm F4ccd64a6_11 với tham số truyền vào
var inputArg = "^L23230F323C2A402C403E2638454C37377C3B35518042454F3D533F5351938A";
var result = targetClass.F4ccd64a6_11(inputArg);
console.log(`[*] Called ${targetClassName}.F4ccd64a6_11`);
console.log(`[*] Input: ${inputArg}`);
console.log(`[*] Output: ${result}`);
} catch (e) {
console.log(`[*] Error: ${e}`);
}
});
}
});
```

Lúc này, nếu muốn decrypt hết tất cả các strings ta có 2 cách.
+ bung file dex thành smali code, tìm tất các cả string cần decrypt. Chạy frida script để decrypt tất cả đống này, thường là các const-string. Ví dụ như:

cách này khá hiệu quả và dễ thực hiện
+ Viết jeb script, cách này khó hơn nhưng đổi lại đọc source dễ hơn.
https://blog.viettelcybersecurity.com/mot-vai-phuong-phap-deobfuscate-trong-qua-trinh-phan-tich-ma-doc-android/
Sau khi dịch ngược mã nguồn, có thể thấy ứng dụng này là một banking trojan. Ứng dụng yêu cầu cấp quyền để đăng ký Accessiblity Service. Tính năng này cho phép ứng dụng quay lại màn hình, keylogger,.... Nhằm đánh cắp các thông tin liên quan đến các ứng dụng ngân hàng. Chi tiết hơn:
trong libstrategy.so của ứng dụng có các string liên quan đến phone brand, các ứng dụng ngân hàng:



Ứng dụng có thể tự thao tác chạm với màn hình, không cần người dùng chạm vào màn hình điểu khiển.



ghi lại quá trình authen của user, sau đó có thể tự click lại giống vậy.

TouchAccessibilityService

LockManager$swipeUp$1 Tự động swipeup, mở khóa màn hình.

PasswordCapture2 capture mật khẩu

RemoteCommandClient tạo connect đến C2

1 số endpoint của c2, tuy nhiên máy chủ đã không thể connect đến.
Kết luận lại: Ứng dụng là trojan banking, khi người dùng cài đặt có nguy cơ bị mã độc ghi lại các thao tác đăng nhập, đánh cắp mật khẩu. Kết hợp với các quyền được cấp khác như đọc sms, ứng dụng có thể tự mở khóa màn hình, mở ứng dụng banking, đăng nhập, tạo giao dịch chuyển tiền, đọc otp từ sms.