Lý thuyết
Giới thiệu về mã độc file Helper
Đây là mã độc được giả dạng trông như một ứng dụng trợ giúp tệp hợp pháp, quản lý tệp và các tài nguyên khác được lưu trữ trên điện thoại Android của bạn.
Mã độc được phát hiện hoạt động trên các dòng máy android từ bản 4.1.x đến 5.x chạy trên nền kiến trúc ARM
Tổng quan về Rootkit
Mã độc thuộc rootnik, một dạng mã độc (malware) nhắm vào hệ điều hành Android. Rootnik được phân loại là một loại rootkit, cho phép kẻ tấn công kiểm soát hoàn toàn thiết bị bị nhiễm. Ngoài ra nó có khả năng xâm nhập vào hệ thống và cấp quyền truy cập root mà không cần sự cho phép của người dùng
Các đặc điểm chính của Rootkit:
Quyền truy cập root: Rootkit khai thác các lỗ hổng bảo mật để có được quyền truy cập root trên thiết bị, cho phép nó cài đặt các ứng dụng khác mà không cần sự cho phép của người dùng.
Khả năng ẩn mình: Rootnik có khả năng ẩn mình khỏi các công cụ bảo mật và quản lý, làm cho việc phát hiện và loại bỏ nó trở nên khó khăn hơn.
Chức năng đa dạng: Có thể thực hiện nhiều hành động khác nhau như ghi lại các hoạt động của người dùng, đánh cắp thông tin cá nhân, tải xuống và cài đặt các ứng dụng độc hại khác, và gửi dữ liệu nhạy cảm đến máy chủ điều khiển của kẻ tấn công.
Phát tán thông qua ứng dụng giả mạo: Thường được phát tán thông qua các ứng dụng giả mạo hoặc các file APK không rõ nguồn gốc. Người dùng có thể vô tình tải và cài đặt nó khi nghĩ rằng đó là ứng dụng hợp pháp.
→ Mã độc file Helper chứa tất cả các đặc điểm trên khi thực hiện cài mã độc trên máy ảo
Luồng hoạt động chính
Luồng hoạt động của mã độc được miêu tả trong ảnh sau:
Nhìn vào sơ đồ ta có thể tóm gọn chu trình hoạt động gồm 3 hoạt động chính:
Đầu tìn chạy file .dex đầu tiên load file .so (file share objects binary) để lấy ra một file .dex thứ hai thực hiện
File .dex thứ hai thực hiện parse file KK.bin để lấy ra các file .dex, .apk , các file ELF
Phân tích từ các file được tải về từ remote server, tạo một file .js để thực hiện các command trong máy tạo 1 file .apk trong system/priv-app để thực hiện cac mục tiêu cuối
Đoạn cuối sau khi cài thêm file BSetting.apk nữa thì máy nạn nhân sẽ các “triệu chứng” sau:
Máy bị tạo nhiều screen shortcut trên màn hình
Các quảng cáo xuất hiện kèm theo là nhiều thông báo từ các apps lạ
Download nhiều file khác nhau cho lên máy nạn nhân
Phân tích file apk đầu vào
Kết cấu file mã độc
Đầu tiên sử dụng apktool giải mã file mã độc ta sẽ có cây thư mục của mã độc như sau:
Đối với phân tich mã độc trên Android thì đầu tiên chúng ta cần phải đọc tệp cấu hình
AndroidManifest.xml
. Đây là tệp tin cấu hình chính của ứng dụng Android và chứa các thông tin quan trọng như thành phần ứng dụng, quyền ứng dụng yêu cầu, ….Dòng đầu tiên cho chúng ta thấy package name cho mã độc xuât hiện trong máy sẽ là
com.web.sdlife
, thuộc tínhstandalone="no"
: Chỉ ra rằng tài liệu này phụ thuộc vào các thực thể bên ngoài (external entities). Các phiên bản platform chỉ ra phiên bản mà mã độc được build lênBên dưới là các quyền mà mã độc yêu cầu để được sử dụng để hoạt động đúng cách. Mã độc đã yêu cầu hơn 50 quyền khác nhau cho hoạt động của mình
Đọc xuống bên dưới sẽ cung cấp thêm thông tin về cách hoạt động của mã độc
Chi tiết đoạn này đã khai báo application có chứa một lớp java có tên là
com.secshell.shellwrapper.SecAppWrapper
nhằm mục đích lớp này sẽ là lớp được chạy đầu tiên trước khi lớp mà hệ thống Android khởi tạoBên dưới là lớp Java định nghĩa action.main là
com.sd
.clip.activity.FileManagerActivity
, nhưng ta không thể tìm được lớp Java này, bên cạnh đó là các lớp java Service class or Broadcast class trong lớp class.dex chính của mã độc→ Mã độc sẽ tải một file .dex khác và thực thi nó
Giờ chúng ta đã biết đầu tiên chúng ta cần phải làm tìm hiểu lớp
com.secshell.shellwrapper.SecAppWrapper
trong class.dex
Phân tích tĩnh class.dex
Sau khi dùng d2j-jar và jd-gui ta thu được cấu trúc trong file class.dex sau:
Như đã nói ở trên ta sẽ phân tích class
SecAppWrapper
:Đầu tiên class đã thực hiện tải thư viện native
SecShell
và (nếu có) tải một thư viện từ đường dẫn được chỉ định bởiHelper.PPATH
. Điều này có thể được sử dụng để tích hợp mã native hoặc thư viện bên ngoài vào ứng dụng.Thư viện native là các tập tin thư viện được viết bằng các ngôn ngữ lập trình cấp thấp như C hoặc C++, và được biên dịch thành mã máy để có thể thực thi trực tiếp bởi phần cứng của hệ thống.
Bên dưới đó ta thấy hàm
attachBaseContext()
nhằm tạo đối tượng ứng dụng thật sự có thể là ứng dụng thực sự mà lớpSecAppWrapper
đang cố gắng thay thế hoặc mở rộng. Ngoài ra còn gọiHelper.attach
có thể là để gán bối cảnh hoặc thực hiện một số thao tác đặc biệt với ứng dụng thực sự.Class Helper có cấu tạo như sau:
→ Có thể
Attach
là để dùng giao tiếp với code native
Cuối cùng là
OnCreate()
để thực hiện thao tác khởi tạo lên ứng dụng vớirealApplication
→ Tóm lại luồng cơ bản của class này sẽ là:
Static code block (Load SecShell)-> attachBaseContext -> onCreate
Ngoài ra mã độc còn dùng multidex scheme để thực hiện tải file .dex thứ hai về từ thư viện native được thể hiện qua class DexInstall
Sau đó, chương trình gọi phương thức cài đặt DexInstall để tải tệp dex phụ. Việc gọi phương thức cài đặt của DexInstall được thực thi ở thư viện native
Multidex scheme là một phương pháp trong Android để xử lý các ứng dụng có quá nhiều mã nguồn để đặt vào một tập tin APK đơn. Khi số lượng phương thức trong ứng dụng vượt quá giới hạn (65,65,536 phương thức) của
Dalvik Executable (DEX) file
, chương trình sẽ gặp lỗi vượt quá giới hạn phương thức (lỗi “method limit exceeded”) . Multidex giúp giải quyết vấn đề này bằng cách chia mã nguồn của ứng dụng thành nhiều file DEX thay vì chỉ một.
Trong class này chỉ có 2 lớp chính như trên nên tiếp theo ta sẽ đi sâu vào phân tích thư viên native
SecShell
Phân tích tĩnh thư viện native
Đọc luồng thực thi trong native code
Ném file SecShell vào IDA Pro để đọc file:
Đầu tiên ta xem phần Sections
→ Ta có thể thấy được các thành phần của thư viện như bảng GOT, phần BSS, … cũng như các quyền của từng phần và địa chỉ
Nhìn sơ qua phần các hàm trong thư viện thì nó đều để tên obfuscated làm rối người phân tích
Nhưng vì đây là thư viện native giao tiếp với code trong Java nên ta sẽ đi tìm phần hàm
Java Native Interface
(JNI)JNI là một khung lập trình cho phép mã Java chạy trên một Máy ảo Java (JVM) có thể gọi và được gọi bởi những ứng dụng gốc (các chương trình cụ thể cho một nền tảng phần cứng và hệ điều hành) và những thư viện được viết bằng các ngôn ngữ khác như C, C++ và hợp ngữ.
Tìm trong list các hàm trong thư viện ta đã thấy hàm JNI_OnLoad()
Trong trường hợp có các hàm JNI khác thì ta cũng nên bắt đầu bằng JNI_Onload trước vì trước khi phương thức native code nào được chạy thì vẫn cần được load library vào trong memory trước. Đó là cũng là lí do nên phân tích JNI_OnLoad trước
Khi bắt đầu nhìn vào đoạn code Assembly của phần hàm JNI_Onload()
- Thư viện viết theo kiến trúc ARM
Kiến trúc ARM sử dụng kiến trúc RISC (Reduced Instruction Set Computing), có nghĩa là nó sử dụng một tập lệnh đơn giản và tối ưu hóa để thực hiện các tác vụ nhanh chóng và hiệu quả. Điếm khác biệt lớn ngoài hiệu năng và thời gian so với Intel đó là phần thanh ghi của ARM có nhiều hơn so với Intel nhưng số lượng instruction thì không bằng
Chúng ta sử dụng phân tích động để xem luồng hoạt động của phần này
Thực hiện Attach vào process của mã độc
Sau khi chạy nhiều lần chương trình thì ta sẽ thấy không thể tiếp tục tại chỗ này
Lệnh tại địa chỉ
0xF832
nhày tới địa chỉLoc_F924
. Sau đó sẽ bị nhảy vào hàmp7E7056598F77DFCC42AE68DF7F0151CA()
→ bị out khỏi process debugging
→ Hàm p7E7056598F77DFCC42AE68DF7F0151CA()
sẽ thực hiện chức năng anti-debugging
Anti-Debug là các kỹ thuật được sử dụng để vô hiệu hóa các Debugger, nhằm mục đích gây khó khăn cho công việc Reverse, làm tiêu tốn nhiều thời gian hơn khi thực hiện phân tích một mẫu
Nhìn qua graph của hàm anti-debugging ta có thấy rất phức tạp:
Để có thể anti-debugging thì trong phần này code đã thực hiện cả anti-hooking với sự xuất hiện như phát hiện một số hook framework phổ biến như Xpose, base, adbi, ddi, dexpose. Sau khi tìm thấy, hãy chương trình debug dùng hook bằng các hook framework phổ biến này thì nó sẽ kill quá trình liên quan
Kĩ thuật anti-hooking là các kỹ thuật và các chiến lược được sử dụng để ngăn chặn các kĩ thuật hooking trong phần mềm. Hooking là một kỹ thuật phổ biến được sử dụng trong lập trình máy tính để thay đổi hoặc mở rộng hành vi của các hàm, phương thức, hoặc sự kiện của một ứng dụng mà không cần thay đổi mã nguồn gốc của ứng dụng đó. Dễ hiểu hơn thì hook sẽ nhắm vào khoảng thời gian trước khi hệ thống đọc được dữ liệu thành công. Thư viện hook sẽ khiến cho hệ thống đọc sai địa chỉ lưu dữ liệu và các chỉ thị của hàm, từ đó khiến cho chương trình hoạt động sai so với thiết kế
Tiếp theo ta có thể tìm được hàm find_hook_features()
Ngoài ra thư viện này còn thực hiện scan thread để xem có trình gỡ lỗi xuất hiện hay không
Thực hiện bypass anti-debugging
Theo như chúng ta đã phân tích, điều cần làm là tránh cho chương trình chạy đến hàm
p7E7056598F77DFCC42AE68DF7F0151CA()
để thực thi hàm check có đang được debug hay không, do đó ta đi đến instruction trước khi gọi đến hàmLoc_F924
. Vì vậy:Như trên ảnh thay vì để instruction
“SUBS R1, R0, #0”
tại địa chỉ0xF828
, với instructions trước R1 chứa kết quả của R0 - 0 lưu vào R1 và vì BNE là lệnh "Branch if Not Equal", nghĩa là nhảy đến địa chỉ đích nếu kết quả của lệnh trước đó không bằng 0 (dựa trên cờ Zero). có 2 kết quả sau:Nếu R1 = 0 thì cờ Zero được bật → sẽ không nhảy đến địa chỉ
0xF828
Nếu R1 khác 0 thì cờ Zero ko được bật → sẽ nhảy đến địa chỉ
0xF828
Qua đó đến khi debug ta sẽ thực hiện thay đổi giá trị thanh ghi R1
Ta có thấy địa chỉ thay đổi do phân tích tĩnh ta đang xem gọi là địa chỉ ảo còn khi thực hiện thì chúng ta sẽ thấy gọi là địa chỉ vật lý khi hệ điều hành ánh xạ các địa chỉ ảo này sang địa chỉ vật lý thực tế trong không gian địa chỉ của quá trình. Để thực hiện điều này thì cờ Address Space Layout Randomization (ASLR) cần được bật
Sau đó sẽ nhảy đến local_75178834
Sau khi bypass khỏi hàm anti-debugging, ta tiếp tục theo luồng và gặp một hàm load vào memory
Hàm p34D946B85C4E13BE6E95110517F61C41() gọi là decryption function vì đầu vào R0 là trỏ đến vùng nhớ có mã hex như trên và file size là 608830. Khi so sánh ta sẽ thấy mã hex của vùng nhớ đó tương đồng với file secData0.jar
Tiếp tục theo sau đó ta sẽ thu được một vùng memory khác chứa chữ ký khác
Chữ ký PK tượng trưng cho đây là file .zip. Do đó ta sẽ thực hiện dump memory này ra để chương trình đã lấy điều gì qua script của IDA
Bên dưới ta sẽ có thể thấy một hàm như install file .dex qua lời gọi của JNI
Phân tích file class.dex thứ hai
Sau khi thực hiện dump memory ta sẽ có file decrypt.dump như sau:
Vì là file .zip nên thực hiện decompress, sau đó ta sẽ có file .dex:
Dùng jd-gui phân tích thì trong cây thư mục ta sẽ có các class đã nói ở phần một:
Xem xét hàm
OnCreate()
trong class FileManagerActivity()Sau khi xem xét thì ta sẽ thấy hàm
initadv()
gọi class Nws:Trong
Nws.getStart()
sẽ thực hiệnstartService()
của class PG
Giờ chúng ta sẽ đi sâu vào class PG
Giờ chúng ta có class và từng phần dưới đây:
readDex()
Như trên ảnh thì đầu tiên lấy string là KK.bin ra biến V9 (KK.bin chính là file nằm trong cây thư mục gốc của file )
v10 sẽ lấy tên KK.bin đọc file đó trong thư mục assets (Vì KK.bin nằm trong thư mục KK.bin)
Đến phần cuối thì nó sẽ đọc trong file KK.bin thành các chuỗi ngắt nhau bằng dấu xuống dòng. Ta xem
Cuối là gọi hàm getAppid() của class Pls
→ Cuối cùng ta thu được một list các tên app trong Pls sau khi decode Base64
Pls.Kbin: wddex.jar
Pls.OI: xdt
Pls.PL: com.svq.cvo.Rtow
Pls.Jr: getDex
Pls.Wv: sgdex
Pls.as: dos.jar
Pls.NQ: KK.bin
dxFile()
Code trong hàm này được định nghĩa như sau trong class Pls:
Nhận hai tham số đầu vào Pls.kobs và string wddex.jar
Câu lệnh đầu tiên khai báo file v5 sẽ nằm ở thư mục
/data/data/com.web.sdlife/app_sgdex
có tên là dos.jarTạo file v10 tại đường dẫn
/data/data/com.web.sdlife/files
với tên là wddex.jarNếu file này chưa tồn tại sẽ thực hiện hàm
UnZipFolder()
- Với dữ liệu như trên, ta có thể thấy tạo file wddex.jar là từ KK.bin bằng việc lấy dữ liệu từ 0x20 đến 0x1CDB và save file đó dưới dạng
/data/data/com.web.sdlife/files/wddex.jar
- Với dữ liệu như trên, ta có thể thấy tạo file wddex.jar là từ KK.bin bằng việc lấy dữ liệu từ 0x20 đến 0x1CDB và save file đó dưới dạng
Với các dòng cuối thì sẽ thực hiện decrypt file wddex.jar vừa tạo bằng giải thuật DES để tạo thành file dos.jar
DexClassLoader()
Lớp này có cấu trúc như sau:
Đây là một lớp trong Android thuộc gói
dalvik.system
, được sử dụng để tải các lớp từ các tệp .jar và .apk, mà có chứa mã bytecode Java và cho phép bạn tải và sử dụng các lớp từ các tệp mà không cần phải biên dịch chúng vào APK chính của ứng dụngVới dexpath là file muốn tải, OptimizedDirectory là nơi chứa thì có thể biết được đối số muốn load là
/data/data/com.web.sdfile/app_sgdex/dos.jar
và đầu ra sẽ là/data/data/com.web.sdfile/app_xdt
.
Phân tích file .dex từ dos.jar
Phân tích class com.svq.cvo.Rtow
Phân tích lớp getDex()
Theo luồng thực hiện, ta đi đến class
com.kdw.xoa.Dwol()
. Như đã comment ở trên, đến cuối sẽ khai báo tên file là mda.ico trong folder/data/data/com.web.sdfile/files
.Sau đó tải một payload từ một remote server có url là [
http://gt](<http://gt/>)[.]rogsob[.]com/stmp/ad.png
và save lại vào file mda.ico vừa khai báo.
Sau khi ghi vào mda.ico thành công thì sẽ đến hàm
initData()
Bên dưới là cấu trúc hàm initData():
Cấu trúc của hàm
silentInstall()
có dạng như sau:Tóm gọn 5 bước giải thích cho chức năng class trên là:
Hàm dxfile của class Dwol sẽ thực hiện decrypt file
/data/data/com.web.sdfile/files/mda.ico
và lưu file decrypt đầu ra vào/data/data/com.web.sdfile/app_snex/dkt.jar
Hàm unZipfile của class Ngss sẽ thực hiện giải nén file dkt.jar ở trên vào vào thư mục
/data/data/com.web.sdfile/files
.Sau khi giải nén sẽ lần lượt xóa các file dkt.jar. thư mục app_snex, file mda.ico
Rename file class.dex thành file wsh.jar
Sử dùng hàm
DexClassLoader()
để lấy ra file wsh.dexYêu cầu thực hiện hàm getDex trong class com.rootdex.MainActivity của file wsh.dex
Phân tích file wsh.dex
Cấu trúc của file như sau:
Nội dung của class getDex():
Thực hiện nếu trong thư mục system không xuất hiện các apk trên sẽ thực hiện hàm GetActive() là được sử dụng để thu thập thông tin thiết bị và gửi nó đến máy chủ từ xa. URL của máy chủ từ xa là [`http://grs[.]gowdsy.]com:8092/active.do`
Kiểm tra xem một số tệp có tồn tại trong thư mục /data/data/com.web.sdfile/files/ hay không và thêm tên tệp của chúng vào danh sách mảng mà mã độc đang chuẩn bị cho bước tiếp theo là root thiết bị.
Thực thi rooting trên thiết bị.
Theo hàm run() trong class MTKRoot(), ta sẽ xem xét hàm HandleRoot():
Bắt đầu với copyRootFile()
FileUtil.dxfile() được sử dụng để giải mã tệp /data/data/com.web.sdfile/files/png.ico và lưu nó dưới dạng tệp /data/data/com.web.sdfile/app_dex/.do.
FileUtil.UnZip() được sử dụng để giải nén tệp /data/data/com.web.sdfile/app_dex/.do vào thư mục /data/data/com.web.sdfile/.rtt, là thư mục hệ thống ẩn chứa sáu tệp thực thi ELF, như được hiển thị bên dưới. Nó bao gồm bốn khai thác root r1,r2,r3,r4.
Nó xóa các công cụ root đã được giải mã /data/data/com.web.sdfile/app_dex/.do và thư mục /data/data/com.web.sdfile/app_dex
Sau đó, nó tạo một tệp mới, psneuter.js, trong thư mục /data/data/com.web.sdfile/files/. Nội dung của nó được hiển thị dưới đây.
Tiếp trong hàm executeRootAct() thì sẽ thực hiện với nội dung sau:
Với nội dung trên, hàm muốn thực hiện một loạt command với nội dung được tóm tắt như sau:
→ như vậy các thành phần từ r1 đến r4 sẽ thực hiện root được thiết bị còn thành phần psneuter.js sẽ thực hiện với quyền cao nhất tải các tệp thực thi vào /system/priv-app
Phân tích file apk trong system
Phân tích code
Sau khi file abc.apk chuyển tên thành BSetting.apk và được install vào máy nạn nhân nên ta sẽ thực hiện phân tích file abc.apk.
Xem xét cấu trúc của file abc.apk sau:
File AndroidManifest.xml:
- Package chạy trong máy nạn nhân sẽ là
com.android
.sync
- Package chạy trong máy nạn nhân sẽ là
class đầu tiên ta phân tích là
com.sfy.oyr.R
:Vì gọi đến class D hàm a() nên ta phân tích
Mở đầu là một loạt khai báo các kiểu string
Chuyển mã Ascii sẽ là:
public static String d = "testdex.jar"; public static String e = "temp"; public static String f = "com.android.sync.ADSservice"; public static String g = "getDex"; public static String h = "com.android.sync.ADBoot"; public static String i = "getBDex"; public static String j = "sdex"; public static String k = "do.jar"; public static String l = "jif.png"; public static String m = "doSo"; public static String n = "/system/app"; public static String o = "intent.action.file.deleted"; public static String p = "/system/priv-app";
Hàm a():
Dựa vào kí tự đã giải mã thì đây là yêu cầu thực hiện hàm doSO() trong class com.android.sync.ADBoot
Còn thành phần onStart() của class D sẽ thực hiện decrypt file jif.png thành một file class.dex mới
Phân tích file class.dex từ jif.png
Ta có cấu trúc của file class.dex:
Sau khi xem xét 2 class này ta sẽ thấy trong class ADService sẽ thực hiện fetch đến 2 domain là
grs[.]gowdsy[.]com
vàgrs[.]rogsob[.]com
.Ở đây ta sẽ thấy các hành vi cuối cùng của mã độc như:
Tạo Shortcut trên giao diện:
Thực hiện tải nhiều package chạy ngầm trên thiết bị thông qua tiện ích “pm install -r” của hệ thống Android
Thực hiện push nhiều thông báo trên thiết bị:
Tổng kết
Từ phân tích trên, chúng ta có thể thấy rằng phần mềm độc hại rootnik đã sử dụng các kỹ thuật Anti-debug và Anti-hooking để ngăn chặn kỹ thuật đảo ngược và các loại mã hóa khác nhau cho tệp và chuỗi. Ngoài ra, nó cũng sử dụng một lMultidex scheme để tải và cài đặt động tệp dex thứ cấp là logic chính của phần mềm độc hại này. Phần mềm độc hại sử dụng một số công cụ khai thác gốc Android nguồn mở. Sau khi giành được quyền root thành công trên thiết bị, phần mềm độc hại rootnik có thể thực hiện nhiều hành vi độc hại, bao gồm quảng cáo ứng dụng và quảng cáo, tạo shorcut trên màn hình chính, cài đặt ứng dụng âm thầm và đẩy thông báo, v.v.
C&C Server
gt[.]rogsob[.]com
grs[.]gowdsy[.]com
alog[.]umeng[.]com