那些年Android黑科技①:只要活著臀玄,就有希望

“黑科技什么的最喜歡了瓢阴!
對(duì),我們就是要搞事健无。
來呀荣恐。誰怕誰。三年血賺,死刑不虧。(?′?`?) ”
-- 來自暗世界android工程師

前言:
這個(gè)世界上手機(jī)有三大系統(tǒng)叠穆,蘋果少漆、 安卓、 中國(guó)安卓 硼被。本篇強(qiáng)烈呼吁大家不要去做哪些違反用戶體驗(yàn)的黑科技功能示损,研究研究玩玩就好了啦。全當(dāng)增長(zhǎng)技術(shù)嚷硫,在真實(shí)的項(xiàng)目開發(fā)中盡量能不用就不要用得好检访。道理大家都懂的。

目錄

那些年Android黑科技①:只要活著仔掸,就有希望

  • android應(yīng)用內(nèi)執(zhí)行shell
  • 雙進(jìn)程贝喙螅活aidl版
  • 雙進(jìn)程保活jni版
  • 奔翁活JobService版

那些年Android黑科技②:欺騙的藝術(shù)

  • hook技術(shù)
  • 欺騙系統(tǒng)之偷梁換柱

那些年Android黑科技③:干大事不擇手段

  • 應(yīng)用卸載反饋
  • Home鍵監(jiān)聽
  • 桌面添加快捷方式
  • 無法卸載app(DevicePolicManager)
  • 無網(wǎng)絡(luò)權(quán)限偷偷上傳數(shù)據(jù)

android應(yīng)用內(nèi)執(zhí)行shell

android系統(tǒng)本身是Linux作為內(nèi)核丹禀,我們一般開發(fā)中使用 adb shell 命令來操作状勤。但其實(shí)本身在應(yīng)用內(nèi)也是可以執(zhí)行的鞋怀。強(qiáng)大的地方是在root的情況下,可以實(shí)現(xiàn)靜默安裝和操作一切你想在設(shè)備內(nèi)做事情持搜。其方法如下密似。

調(diào)用工具代碼:

    /**
     * 是否是在root下執(zhí)行命令
     *
     * @param commands        命令數(shù)組
     * @param isRoot          是否需要root權(quán)限執(zhí)行
     */
    public static void execCmd(String[] commands, boolean isRoot) {
    //便于觀看刪除來不影響的部分代碼,完整的可以在文中的github里找到葫盼。
            process = Runtime.getRuntime().exec(isRoot ? "su" : "sh");
            os = new DataOutputStream(process.getOutputStream());
            for (String command : commands) {
                if (command == null) continue;
                os.write(command.getBytes());
                os.writeBytes("\n");
                os.flush();
            }
            os.writeBytes("exit\n");
            os.flush();
            result = process.waitFor();
                successMsg = new StringBuilder();
                errorMsg = new StringBuilder();
                successResult = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
                errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream(), "UTF-8"));
    }

沒有root權(quán)限的情況下在屏幕上操作,實(shí)測(cè)可被執(zhí)行的命令只有swipe和部分keyevent可以生效残腌,其余的可以通過adb的方式調(diào)用成功。但是一但在應(yīng)用內(nèi)通過shell是不可以的贫导。這確保了android手機(jī)的安全抛猫。

其中keyevent 返回鍵 音量鍵可以調(diào)用 而home按鍵這種則不可以。
如果你試圖調(diào)用dumpsys activity activities 來查看孩灯。會(huì)拋出權(quán)限的異常如下闺金。實(shí)測(cè)中我有申請(qǐng)權(quán)限,但一樣無法在應(yīng)用內(nèi)部調(diào)起峰档。

Permission Denial: can't dump ActivityManager from from pid=12414, uid=10369 without permission android.permission.DUMP0
image.png

使用參考:

Root情況下靜默安裝:

 String command = "LD_LIBRARY_PATH=/vendor/lib:/system/lib pm install " +"apk路徑";
  ShellUtils.execCmd(command, ture);

代碼:https://github.com/BolexLiu/AndroidShell


雙進(jìn)程卑芷ィ活aidl版 (android5.0以下)

原理介紹:實(shí)現(xiàn)的機(jī)制并不復(fù)雜,通過AIDL的方式開啟兩個(gè)服務(wù)分別在不同進(jìn)程中啟動(dòng)讥巡,然后互相守護(hù)監(jiān)聽對(duì)方是否被關(guān)閉掀亩,如果有一方被斷開連接,另一方測(cè)重啟服務(wù)欢顷。因?yàn)閍ndroid在5.0之前銷毀進(jìn)程是一個(gè)一個(gè)銷毀的槽棍,他并不能同時(shí)銷毀兩個(gè)。所以可以做這件事。(被修改的rom除外炼七,比如華為4.4就不行外里,但三星可以。)

1.配置服務(wù)進(jìn)程特石。注意process屬性會(huì)獨(dú)立在另一個(gè)進(jìn)程中盅蝗。

    <service android:name=".Service.LocalService" />
    <service android:name=".Service.RemoteService"  android:process=".Remote"/>

2.我們擁有兩個(gè)服務(wù)LocalService RemoteService。項(xiàng)目運(yùn)行后第一件事姆蘸,同時(shí)啟動(dòng)服務(wù)墩莫。

       startService(new Intent(this, LocalService.class));
        startService(new Intent(this, RemoteService.class));

3.在LocalService中綁定RemoteService并監(jiān)聽對(duì)方的創(chuàng)建和銷毀,RemoteService中的實(shí)現(xiàn)也一樣逞敷。

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        super.onStartCommand(intent, flags, startId);
        Log.e(TAG, TAG + " onStartCommand");
        //  綁定遠(yuǎn)程服務(wù)
        bindService(new Intent(this, RemoteService.class), mLocalServiceConnection, Context.BIND_IMPORTANT);
        return START_STICKY;
    }
    //連接遠(yuǎn)程服務(wù)
    class localServiceConnection implements ServiceConnection {

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            try {
                // 與遠(yuǎn)程服務(wù)通信
                MyProcessAIDL process = MyProcessAIDL.Stub.asInterface(service);
                Log.e(TAG, "連接" + process.getServiceName() + "服務(wù)成功");
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            // RemoteException連接過程出現(xiàn)的異常狂秦,才會(huì)回調(diào),unbind不會(huì)回調(diào)
            // 監(jiān)測(cè),遠(yuǎn)程服務(wù)已經(jīng)死掉推捐,則重啟遠(yuǎn)程服務(wù)
            Log.e(TAG, "遠(yuǎn)程服務(wù)掛掉了,遠(yuǎn)程服務(wù)被殺死");
            // 啟動(dòng)遠(yuǎn)程服務(wù)
            startService(new Intent(LocalService.this, RemoteService.class));
            // 綁定遠(yuǎn)程服務(wù)
            bindService(new Intent(LocalService.this, RemoteService.class), mLocalServiceConnection, Context.BIND_IMPORTANT);
        }
    }

代碼:https://github.com/BolexLiu/DoubleProcess


雙進(jìn)程绷盐剩活jni版 (android5.0以下)

原理介紹:這種雙進(jìn)程守利用了Linux子進(jìn)程在父進(jìn)程被干掉后還能運(yùn)行而實(shí)現(xiàn)。所以我們要做的是通過java去fork一段C的代碼牛柒。通過動(dòng)態(tài)鏈接庫封裝起來堪簿。然后在C代碼里不斷輪訓(xùn)父進(jìn)程的ppid是否存活。如果掛掉了側(cè)重新喚醒皮壁。

1.配置服務(wù)進(jìn)程椭更。注意process屬性會(huì)獨(dú)立在另一個(gè)進(jìn)程中。

        <service
            android:name=".service.DaemonService"
            android:process=":daemon"></service>
            

2.在DaemonService里利用靜態(tài)代碼塊調(diào)起so蛾魄。

public class DaemonService extends Service{
  // 便于閱讀省略無關(guān)代碼虑瀑,詳情去移步至github···
       static {
        System.loadLibrary("daemon");
    }
}

3.so中的C代碼輪訓(xùn)進(jìn)程判斷是否存活。

 //便于閱讀省略無關(guān)代碼滴须,詳情去移步至github···
//fork子進(jìn)程舌狗,以執(zhí)行輪詢?nèi)蝿?wù)
    pid_t pid = fork();
    LOGI("fork=%d", pid);
    if (pid < 0) {
// fork失敗了
    } else if (pid == 0) {
// 可以一直采用一直判斷文件是否存在的方式去判斷,但是這樣效率稍低扔水,下面使用監(jiān)聽的方式痛侍,死循環(huán),每個(gè)一秒判斷一次铭污,這樣太浪費(fèi)資源了恋日。
        int check = 1;
        while (check) {
            pid_t ppid = getppid();
            LOGI("pid=%d", getpid());
            LOGI("ppid=%d", ppid);
            if (ppid == 1) {
                LOGI("ppid == 1");
                if (sdkVersion >= 17) {
                    LOGI("> 17");
                    int ret = execlp("am", "am", "startservice", "--user", "0",
                                     "-n", name,
                                     (char *) NULL);
                } else {
                    execlp("am", "am", "startservice", "-n",
                           name,
                           (char *) NULL);
                    LOGI("else");
                }
                check = 0;
            } else {
            }
            sleep(1);
        }
    } 

感謝CharonChui開源代碼。處應(yīng)該有掌聲嘹狞!

代碼:https://github.com/CharonChui/DaemonService

逼裆牛活 JobService版 (android5.0++)

原理: JobService是官方推薦的方式,即使app完成被殺死的狀態(tài)下也能調(diào)用起來磅网,本質(zhì)是向系統(tǒng)注冊(cè)一個(gè)任務(wù)谈截。通過getSystemService拿到系統(tǒng)的JobScheduler。然后通過JobInfo.Buidler進(jìn)行構(gòu)造。需要注意的是一定要指定被觸發(fā)的條件簸喂。比如:設(shè)備充電中毙死、空閑狀態(tài)、連接wifi... 非常類似以前的廣播保護(hù)原理喻鳄。但是實(shí)現(xiàn)不一樣扼倘。這次是我們反向注冊(cè)給系統(tǒng),而不是接收系統(tǒng)的廣播除呵。

1.在AndroidManifest進(jìn)行配置添加permission屬性

 <service
            android:name=".MyJobService"
            android:permission="android.permission.BIND_JOB_SERVICE" />

2.MyJobServer繼承JobService類:


    @Override
    public boolean onStartJob(JobParameters params) {
        //該方法被觸發(fā)調(diào)用 可以做喚醒其他服務(wù)的操作
        return true;
    }

    @Override
    public boolean onStopJob(JobParameters params) {
      
        return true;
    }

3.在合適的地方向系統(tǒng)注冊(cè)

 JobScheduler scheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);  
        ComponentName componentName = new ComponentName(MainActivity.this, MyJobService.class);  
        JobInfo.Builder builder = new JobInfo.Builder(++mJobId, componentName);  
         String delay = mDelayEditText.getText().toString();  
        if (delay != null && !TextUtils.isEmpty(delay)) {  
            //設(shè)置JobService執(zhí)行的最小延時(shí)時(shí)間  
            builder.setMinimumLatency(Long.valueOf(delay) * 1000);  
        }  
        String deadline = mDeadlineEditText.getText().toString();  
        if (deadline != null && !TextUtils.isEmpty(deadline)) {  
            //設(shè)置JobService執(zhí)行的最晚時(shí)間  
            builder.setOverrideDeadline(Long.valueOf(deadline) * 1000);  
        }  
        boolean requiresUnmetered = mWiFiConnectivityRadioButton.isChecked();  
        boolean requiresAnyConnectivity = mAnyConnectivityRadioButton.isChecked();  
        //設(shè)置執(zhí)行的網(wǎng)絡(luò)條件  
        if (requiresUnmetered) {  
            builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED);  
        } else if (requiresAnyConnectivity) {  
            builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);  
        }  
        builder.setRequiresDeviceIdle(mRequiresIdleCheckbox.isChecked());//是否要求設(shè)備為idle狀態(tài)  
        builder.setRequiresCharging(mRequiresChargingCheckBox.isChecked());//是否要設(shè)備為充電狀態(tài)  
        scheduler.schedule(builder.build());  
     

注意jobScheduler無法兼容Android 5.0以下的設(shè)備再菊,可以參考下面的項(xiàng)目,在低版本中也可以使用颜曾。

**實(shí)際測(cè)試 : **
研究了一段時(shí)間發(fā)現(xiàn)這個(gè)玩意纠拔,在國(guó)內(nèi)的廠商定制過后的rom好多不起作用。 比如魅族 和小米上 如果把a(bǔ)pp殺死以后泛豪,這個(gè)服務(wù)也調(diào)用不起來了稠诲。但是在模擬器和aosp版本的Rom上是可行的。我測(cè)試時(shí)用的電池充電狀態(tài)來調(diào)用job服務(wù)诡曙。

代碼:https://github.com/evant/JobSchedulerCompat


第一部分就先到這里臀叙。后續(xù)還有兩篇續(xù)集會(huì)緊接著營(yíng)養(yǎng)跟上,如果你覺得不錯(cuò)可以關(guān)注我一波點(diǎn)個(gè)喜歡神馬的哈哈岗仑。

那些年Android黑科技①:只要活著匹耕,就有希望

  • android應(yīng)用內(nèi)執(zhí)行shell
  • 雙進(jìn)程保活aidl版
  • 雙進(jìn)程避瘢活jni版
  • 保活JobService版

那些年Android黑科技②:欺騙的藝術(shù)

  • hook技術(shù)
  • 欺騙系統(tǒng)之偷梁換柱

那些年Android黑科技③:干大事不擇手段

  • 應(yīng)用卸載反饋
  • Home鍵監(jiān)聽
  • 桌面添加快捷方式
  • 無法卸載app(DevicePolicManager)
  • 無網(wǎng)絡(luò)權(quán)限偷偷上傳數(shù)據(jù)

如何下次找到我?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末驶赏,一起剝皮案震驚了整個(gè)濱河市炸卑,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌煤傍,老刑警劉巖盖文,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異蚯姆,居然都是意外死亡五续,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門龄恋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來疙驾,“玉大人,你說我怎么就攤上這事郭毕∷椋” “怎么了?”我有些...
    開封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)扳肛。 經(jīng)常有香客問我傻挂,道長(zhǎng),這世上最難降的妖魔是什么挖息? 我笑而不...
    開封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任金拒,我火速辦了婚禮,結(jié)果婚禮上套腹,老公的妹妹穿的比我還像新娘殖蚕。我一直安慰自己,他們只是感情好沉迹,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開白布睦疫。 她就那樣靜靜地躺著,像睡著了一般鞭呕。 火紅的嫁衣襯著肌膚如雪蛤育。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天葫松,我揣著相機(jī)與錄音瓦糕,去河邊找鬼。 笑死腋么,一個(gè)胖子當(dāng)著我的面吹牛咕娄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播珊擂,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼圣勒,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了摧扇?” 一聲冷哼從身側(cè)響起圣贸,我...
    開封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎扛稽,沒想到半個(gè)月后吁峻,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡在张,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年用含,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片帮匾。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡啄骇,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出辟狈,到底是詐尸還是另有隱情肠缔,我是刑警寧澤夏跷,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站明未,受9級(jí)特大地震影響槽华,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜趟妥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一猫态、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧披摄,春花似錦亲雪、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至寓盗,卻和暖如春灌砖,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背傀蚌。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來泰國(guó)打工基显, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人善炫。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓撩幽,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親箩艺。 傳聞我的和親對(duì)象是個(gè)殘疾皇子窜醉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容