前言
電話錄音是android逆向產(chǎn)品中一個非常重要的功能禁添,同時它也是一個比較難以處理的模塊。難點有3:
1.在正向應用中桨踪,我們通過RECORD_AUDIO權(quán)限得到的錄音只能聽到自己的聲音老翘,對方的聲音完全聽不到,這是谷歌對電話模塊的特殊處理锻离,增強用戶隱私。
2.在正向應用中,電話有三種狀態(tài)揉稚,
CALL_STATE_IDLE 空閑態(tài)(沒有通話活動)
CALL_STATE_RINGING 包括響鈴炼七,第三方來電等待
CALL_STATE_OFFHOOK 包括撥號中,接通虱朵,掛起 3個狀態(tài)
這里我們可以知道莉炉,如果不做其他的特殊處理,你記錄的錄音是包含撥打時候的嘟嘟聲碴犬,所以獲取接通那一刻狀態(tài)即 active狀態(tài)非常關(guān)鍵絮宁。
3.運營商的問題》可能有些朋友覺得很奇怪绍昂,這個跟運營商也有關(guān)系,是不是在扯淡偿荷。稍安勿躁窘游,有用過電信卡的朋友可能知道,只要你撥出去了跳纳,你的通話界面就開始從00:00開始計時了忍饰,而移動聯(lián)通則不會。據(jù)我觀察棒旗,好像跟機型有關(guān)系喘批,極少數(shù)手機在撥通后才開始計時撩荣。聰明的你可能發(fā)現(xiàn)問題了,我的思路就是從撥號界面出現(xiàn)00:00就開始計時饶深,針對電信就特殊處理一下餐曹。
硬件及環(huán)境
裝好xposed的華為8c,android 系統(tǒng)版本:8.1.0
對xpose不熟怎么辦
xpose入門非常簡單敌厘,有正向開發(fā)的經(jīng)驗將會非常容易台猴。我寫了一個xpose模塊庫,在你手機裝好xpose后俱两,就可以直接運行該庫了饱狂,也可以在HookMain中定制你的代碼,在編碼逆向代碼時宪彩,請牢記你代碼會運行在哪個進程休讳。
Github地址:https://github.com/twangithub/XposedBase
實現(xiàn)功能
在文章的開始列出了實現(xiàn)功能的難點,下面我直接祭出核心代碼并標示注解尿孔。
電話的狀態(tài):
public static final int PRECISE_CALL_STATE_IDLE = 0; //通話空閑
public static final int PRECISE_CALL_STATE_ACTIVE = 1; //正在通話(活動中)
public static final int PRECISE_CALL_STATE_HOLDING = 2; //通話掛起(例如我和多個人通話,其中一個通話在活動,而其它通話就會進入掛起狀態(tài))
public static final int PRECISE_CALL_STATE_DIALING = 3; //撥號開始
public static final int PRECISE_CALL_STATE_ALERTING = 4; //正在呼出(提醒對方接電話)
public static final int PRECISE_CALL_STATE_INCOMING = 5; //對方來電
public static final int PRECISE_CALL_STATE_WAITING = 6; //第三方來電等待(例如我正在和某人通話,而其他人打入時就會就進入等待狀態(tài))
public static final int PRECISE_CALL_STATE_DISCONNECTED = 7; //掛斷完成
public static final int PRECISE_CALL_STATE_DISCONNECTING = 8; //正在掛斷
① hook android framework層android.telephony包下的核心類俊柔,獲取撥打過來的電話號碼
XposedHelpers.findAndHookMethod("android.telephony.PhoneNumberUtils", loadPkgParam.classLoader, "normalizeNumber", String.class,
new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
String number = (String) param.args[0];
if (null != number) {
String phonenumber = number.toString().trim();
LogUtils.d("獲取對方電話號碼=" + phonenumber.trim().replace(" ", ""));
}
}
});
② 同樣在該包下活合,獲取電話撥打的狀態(tài)雏婶。這里有一個很重要的注意點,對于電信卡是無法獲取active的狀態(tài)白指,所以只能采用別的方法留晚,但是撥號是知道的,這里為了區(qū)分是呼入還是呼出提前記錄一下該值告嘲。
Class PreciseCallState = XposedHelpers.findClass("android.telephony.PreciseCallState",loadPkgParam.classLoader);
XposedHelpers.findAndHookMethod(PreciseCallState, "getForegroundCallState", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
int result = (int) param.getResult();
LogUtils.d("電話狀態(tài):" + result); //對應上面8個狀態(tài)
}
});
③ 那什么時候開始錄音呢, 我們可以從撥打電話的界面下手错维,撥通后,從00:00開始計時橄唬,而且計時有一個遞增的數(shù)值需五,所以有兩種解決方式。這兩種方式在電信卡接通后重新開始計時都要特殊處理一下轧坎,不過這些已經(jīng)是小問題了宏邮。
1.用00:00的方式, 這個api通用性較低,很多機型可能不支持
XposedHelpers.findAndHookMethod("com.android.incallui.view.CallCardStateInfoView",
mLpp.classLoader,"setCallElapsedTime", boolean.class, String.class,
new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
String callRecordTime = (String) param.args[1];
//判斷callRecordTime 出現(xiàn)00:00并開始錄音操作
}
});
2.用計時增長的方式(本例采用)缸血,能適用于較多機型蜜氨,實際已測試為準
XposedHelpers.findAndHookMethod("com.android.incallui.CallCardFragment",
loadPkgParam.classLoader, "setPrimaryCallElapsedTimeLong", boolean.class, long.class,
new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
long mElapsed = (long) param.args[1];
//針對電信: 經(jīng)過多次驗證發(fā)現(xiàn) mElapsed 的值幾乎是小于1000的,第二次的話肯定比上一次小,極少數(shù)情況在接通后mElapsed的值大于1000.
//錄音處理
}
});
④ 如何能錄到對方的聲音
正向應用我們只能獲取MediaRecorder.AudioSource.MIC捎泻,考慮到我們適用xpose的時候能指定任意進程飒炎,
所以在錄音的時候找一個有這樣的權(quán)限的進程即可,本例中采用的是com.android.incallui
并把錄音源指定為 MediaRecorder.AudioSource.VOICE_CALL笆豁。
最后
以上就是實現(xiàn)電話錄音最核心的代碼(可別小看了以上幾行代碼郎汪,逆向一個api并加以驗證要花不少時間)赤赊。而且我在做的過程中所踩的坑也在注釋中標明。需要注意的是煞赢,逆向代碼很難有通用性抛计,原因是android每個版本代碼都可能會改變,而且手機廠商還會對ROM代碼進行修改照筑。所以吹截,逆向都是針對特定的機型。如果你對逆向感興趣凝危,或者有什么問題想交流波俄,方便的話可以加我微信(tuhuan32005)。謝謝 _ !