李跳跳使用、逆向、脫殼和原理介紹

2023-09-07 12:00:46

前言

你可以獨善其身 但你不能兼濟天下

簡介

其實這部分是使用教學,github上面有備份的下載連結,只是可能不更新了,V2.2安裝之後

一把快刀,很簡潔的介面

點選介面裡面的開啟按鈕即可,我這裡就是在無障礙裡面設定了

現在開啟淘寶京東之後就只會看到一閃而過或者沒有開屏廣告的情況了

反編譯

轉成jar

程式碼如下

解壓APK之後目錄為

蒽....還有lib庫和kotlin檔案,怎麼還有JNI程式設計啊~
res資料夾裡面的檔案直接亂成一堆了,反編譯問題

考慮換一個工具來修復靜態檔案 apktool

然後就得到了正常的 res,終於整潔了一點orz

原始碼的話還是看從 jd-gui 解析出來的吧 各部分比較完整
結果發現進行了加固,其實我之前是沒有脫加固APK的經驗的,為啥發現了加固 是因為我把程式碼放到自己的Android工程之後看了半天沒看懂,感覺就是實現了一個類載入器

主工程程式碼就只是去繼承 WrapperProxyApplication 抽象類,給我整不會了,我以為這是什麼高階寫法
主工程還原為

public class MyWrapperProxyApplication extends WrapperProxyApplication {
    protected void initProxyApplication(Context paramContext) {
        String str = (paramContext.getApplicationInfo()).sourceDir;
        ZipFile zipFile = null;
        try {
            ZipFile zipFile1 = new ZipFile(str);
            zipFile = zipFile1;
        } catch (IOException iOException) {
            iOException.printStackTrace();
        }
        if (zipFile == null) {
            Process.killProcess(Process.myPid());
            System.exit(0);
        }
        Util.PrepareSecurefiles(paramContext, zipFile);
        try {
            zipFile.close();
        } catch (IOException iOException) {
            iOException.printStackTrace();
        }
        System.loadLibrary(Util.libname);
    }

    public void onCreate() {
        super.onCreate();
    }
}

然後我覺得這個類載入器可能是一個公用庫 結果就

原來是騰訊的,還是逆向APK的經驗太少了orz
為什麼李跳跳要加殼,應該也是為了防止應用商店或者手機廠商那批人通過特徵檢測到APK然後報毒
為了防止我自己看錯 用工具檢測一下 結果PKID居然檢測不出來,額

開啟MT管理器

可以看到確實騰訊御安全

判斷加殼

手動判斷是騰訊御安全加殼的特徵有三種方式

step1

將APK解壓縮

step2 特徵一

根目錄下存在 tencent_stub 檔案

step3 特徵二

assets目錄存在

  • 0OO00l111l1l
  • o0oooOO0ooOo.dat
  • t86
  • tosversion

step4 特徵三

lib資料夾下存在

  • libshell-super.2019.so
  • libshella-x.so (x代表版本)

MT脫殼

查了一下資料怎麼都需要用MT管理器~
MT管理器使用檔案

https://mt2.cn/guide/

adb 安裝到測試機上面

執行之

接下來安裝李跳跳

在MT管理器裡面安裝包提取尋找李跳跳

可以看到確實是使用騰訊御安全進行加殼的

點選dex選擇dex++

找到這個東西

複製包名

貼上到 AndroidManifest.xml 裡面,儲存
用blackdex脫dex的殼

然後到MT管理器 ,右邊是已脫的

刪除左邊的classes.dex,把右邊的移過去,然後儲存
已經實現了脫殼

最後安裝不上 orz ,流淚了

難道是我工具用的有問題~

frida

只好掏出大殺器 frida 了

frida是平臺原生app的Greasemonkey,說的專業一點,就是一種動態插樁工具,可以插入一些程式碼到原生app的記憶體空間去,(動態地監視和修改其行為),這些原生平臺可以是Win、Mac、Linux、Android或者iOS。而且frida還是開源的

Frida官網:https://www.frida.re/
Frida原始碼:https://github.com/frida

安裝frida

windows安裝使用者端

pip3 install frida

安裝frida-tools

pip3 install frida-tools


安裝 frida-dexdump

pip3 install frida-dexdump

安裝成功

frida --version

安卓安裝frida伺服器端

檢視Android手機的cpu架構

adb shell getprop ro.product.cpu.abi


根據CPU版本下載對應的Frida server https://github.com/frida/frida/releases

下載解壓推到手機目錄下

設定埠轉發

adb forward tcp:27042 tcp:27042
adb forward tcp:27043 tcp:27043


設定許可權並執行

chmod 777 frida-server64
./frida-server64


出現報錯

./frida-server64

檢視當前是否關閉了SELINUX

getenforce

確實開著的

setenforce 0

關閉selinux,執行frida-server
然後重新開啟一個shell檢視是否存在

執行成功

frida升級

pip3 install -U frida
pip3 install -U frida-tools

frida脫殼

手機上開啟需要脫殼的軟體

adb shell啟動frida-server

如果你跟我一樣設定了python script的環境變數,那就可以直接在命令列啟動frida-dexdump

輸入命令 frida-dexdump -FU,如下圖(引數說明,引數 U 是usb,引數 F是前臺活動app)

得到脫殼的dex檔案

檢查之後發現是classes.dex為源dex檔案

還原APK

脫殼之後對APK進行還原
用baksmali工具,把dex轉換成smali

java -jar baksmali.jar d classes.dex


用 apktool d ./com.xxx.mobile.apk,反編譯,得到加固的apk解壓包

替換 smali 資料夾,用前面的 smali 資料夾替換掉 解壓包中的 smali,替換

開啟原檔案的dex,找到com/wrapper/proxyapplication/WrapperProxyApplication
進去複製入口後到AndroidManifest.xml中替換入口
這裡是原本的AndroidManifest.xml

入口我直接用MT管理器看吧

我們需要替換成 hello.litiaotiao.app.LttApp

然後刪除騰訊加固的相關檔案,一般在assets、lib目錄下
也就是我們前面說的那些特徵

  • tencent_stub
  • tosversion
  • 0OO00l111l1l
  • o0oooOO0ooOo
  • 檔名帶有shell的

用 apktool b com.xxx.mobile 編譯apk
最後就是使用AndroidKiller進行重打包

打包完成進行安裝即可
結果還是安裝不了

菜是原罪~

原理

利用安卓系統的無障礙許可權,幫助使用者自動點選廣告上的跳過按鈕

關於無障礙服務

AccessibilityService(無障礙服務)是 Android 作業系統中的一個功能,旨在幫助使用者具有視覺、聽覺或運動上的障礙更輕鬆地使用裝置。它是 Android 提供的一種特殊服務,可以接收裝置上發生的各種事件,並提供自定義的反饋或處理方式。

AccessibilityService 可以在使用者介面上監控和操作應用程式,併為使用者提供額外的輔助功能。它可以接收系統級別的事件,如按鍵、觸控、通知等,還可以存取應用程式的檢視層次結構,以便分析和操作應用程式的介面元素

李跳跳的廣告跳過包含了兩個部分

  • 開屏廣告跳過
  • 應用內彈窗跳過

開屏廣告跳過

有一個簡單的規則 也就是字串 跳過
逆向李跳跳的原始碼檢視規則
hashSet裡面儲存了一些關鍵字

另外還有在檔案內部的 2131755075 位置 ,轉成十六進位制是 7F100043

可以看出這裡的hashSet裡面裝的就是開屏跳過的關鍵字

但是這裡有兩個是從檔案讀取的,轉換一下可以在public.xml裡面找到

在李跳跳掘金的主頁中可以找到答案

所以這裡是使用者自己匯入的規則,這裡我們直接把這幾個跳過的關鍵字都加到我們的邏輯裡面,以後遇到了其他的再處理
翻翻xml檔案裡面還發現有一個白名單列表

應該是為了節省記憶體進行了一次包名判斷
所以對於開屏廣告的檢測核心是

@Override
public void onAccessibilityEvent(AccessibilityEvent accessibilityEvent) {
    onAccessibilityEventPre();
    AccessibilityNodeInfo source = accessibilityEvent.getSource();
    if (source == null)
        return;

    // 判斷是否開啟了檢測
    if (!mMKV.decodeBool(SWITCHMAIN_KEY))
        return;

    CharSequence packageName = accessibilityEvent.getPackageName();
    if (packageName == null)
        return ;
    String currentPackageName = packageName.toString();

    // 讀取白名單陣列
    String[] whiteListArray = getResources().getStringArray(R.array.whitelist);
    List<String> whiteList = Arrays.asList(whiteListArray);

    if (whiteList.contains(currentPackageName)) {
        return; // 如果是白名單內的包名,則不執行後續的檢測邏輯
    }

    for (int i = 0; i < source.getChildCount(); i++) {
        AccessibilityNodeInfo childNode = source.getChild(i);
        if (childNode.getText() == null) {
            continue;
        }

        String text = childNode.getText().toString();

        for (String keyword : keywords) {
            if (text.contains(keyword)) {
                Log.i(TAG, "檢測到開屏廣告關鍵字:" + keyword);
                childNode.performAction(AccessibilityNodeInfo.ACTION_CLICK);
                Toast.makeText(this, SKIP_PROMPT, Toast.LENGTH_LONG).show();
                break;
            }
        }
    }
}

往 AndroidManifest(清單檔案)上設定:

<service android:exported="false" android:label="♥張得乖1.0" android:name="hello.beautifulz.app.ZdgService" android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
    <intent-filter>
        <action android:name="android.accessibilityservice.AccessibilityService"/>
    </intent-filter>
    <meta-data android:name="android.accessibilityservice" android:resource="@xml/accessibility_service_config"/>
</service>

label是這個無障礙服務的名稱
serviceconfig 組態檔如下

<?xml version="1.0" encoding="utf-8"?>
<accessibility-service android:description="@string/accessibility_service_description" android:settingsActivity="hello.beautifulz.app.MainActivity" android:accessibilityEventTypes="typeAllMask" android:accessibilityFeedbackType="feedbackGeneric" android:notificationTimeout="100" android:accessibilityFlags="flagDefault" android:canRetrieveWindowContent="true" android:canPerformGestures="true" android:isAccessibilityTool="true"
  xmlns:android="http://schemas.android.com/apk/res/android" />

應用內彈窗跳過

第二種是應用內的彈窗規則

關於這一點在 https://github.com/Snoopy1866/LiTiaotiao-Custom-Rules 上面有相關規則

跳過應用內的彈窗需要自己編寫解析規則的框架,類似於下面這種

public class MyAccessibilityService extends AccessibilityService {

    @Override
    public void onAccessibilityEvent(AccessibilityEvent accessibilityEvent) {
        // 獲取彈窗內容
        CharSequence popupContent = accessibilityEvent.getText();
        if (popupContent != null) {
            String popupText = popupContent.toString();

            // 呼叫規則匹配函數
            boolean matched = checkPopupRules(popupText);

            if (matched) {
                // 執行關閉彈窗的操作,例如執行返回鍵動作
                performGlobalAction(GLOBAL_ACTION_BACK);
            }
        }
    }

    private boolean checkPopupRules(String popupText) {
        // 將規則字串解析為規則物件,可以使用 JSON 或其他格式進行解析
        // 這裡假設規則已經解析為 Rule 物件

        Rule rule = new Rule("+檢測到&-使用者體驗", "=以後再說");

        // 進行規則匹配判斷
        if (popupText.startsWith(rule.getKeywordStart()) &&
            popupText.endsWith(rule.getKeywordEnd())) {
            if (rule.getAction().equals("=以後再說")) {
                return true;
            }
        }

        return false;
    }

    // 其他回撥方法...

}

這個暫時作為保留節目吧~

後臺保活

APP的後臺保活是一門智慧~為了讓APP一直在後臺執行來跳過廣告,我們需要讓它不被系統殺死
無障礙服務本身許可權就很大,藉助無障礙服務我們來實現強力保活,可以從以下幾個方向入手:

  • 前臺服務保活
  • 申請REQUEST_IGNORE_BATTERY_OPTIMIZATIONS 忽略電池優化開關
  • 開啟自啟動無障礙服務

這裡就不再詳細說明了

效果

最後實現的小demo可以說是李跳跳的閨蜜了

把裡面的很多地方都裁剪了,只留下了開啟廣告跳過的按鈕

這個時候再開啟知乎就可以看到有跳過效果了

參考連結

END

建了一個微信的安全交流群,歡迎新增我微信備註進群,一起來聊天吹水哇,以及一個會發布安全相關內容的公眾號,歡迎關注