真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

【APP 逆向百例】Frida 初體驗(yàn),root 檢測(cè)與加密字符串定位

網(wǎng)站建設(shè)哪家好,找創(chuàng)新互聯(lián)!專(zhuān)注于網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開(kāi)發(fā)、小程序設(shè)計(jì)、集團(tuán)企業(yè)網(wǎng)站建設(shè)等服務(wù)項(xiàng)目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了東阿免費(fèi)建站歡迎大家使用!

聲明

本文章中所有內(nèi)容僅供學(xué)習(xí)交流使用,不用于其他任何目的,不提供完整代碼,抓包內(nèi)容、敏感網(wǎng)址、數(shù)據(jù)接口等均已做脫敏處理,嚴(yán)禁用于商業(yè)用途和非法用途,否則由此產(chǎn)生的一切后果均與作者無(wú)關(guān)!

本文章未經(jīng)許可禁止轉(zhuǎn)載,禁止任何修改后二次傳播,擅自使用本文講解的技術(shù)而導(dǎo)致的任何意外,作者均不負(fù)責(zé),若有侵權(quán),請(qǐng)?jiān)诠娞?hào)【K哥爬蟲(chóng)】聯(lián)系作者立即刪除!

逆向目標(biāo)

  • 設(shè)備:Google Pixel4,Android 10,已 root
  • APP:UnCrackable-Level1.apk(可在公眾號(hào)回復(fù) APP 獲?。?/li>
  • APP 檢測(cè)了 root,如果手機(jī) root 了,會(huì)強(qiáng)制退出 APP,過(guò)了 root 檢測(cè)后,還需要輸入一個(gè)字符串進(jìn)行校驗(yàn)。

安裝 ADB

adb(Android Debug Bridge)即安卓調(diào)試橋,安裝后可以在電腦上與手機(jī)進(jìn)行交互,Android Studio 等工具里面會(huì)自帶 adb,有時(shí)候我們并不想下載這么大的工具,所以這里介紹一下 Android SDK Platform-Tools,它是 Android SDK 的一個(gè)組件,它包括與 Android 平臺(tái)交互的工具,主要是 adb 和 fastboot,官方下載地址:https://developer.android.com/studio/releases/platform-tools ,下載完成后將該目錄添加到環(huán)境變量,USB 連接手機(jī),手機(jī)上設(shè)置允許 USB 調(diào)試,使用命令 adb version 可查看版本信息,adb devices 可以查看當(dāng)前連接的設(shè)備,如下圖所示:

安裝 Frida

Frida 是一款基于 Python + JavaScript 的 Hook 與調(diào)試框架,首先電腦端使用命令 pip install frida-tools 安裝 frida 模塊(此命令默認(rèn)會(huì)安裝最新版的 frida 和 frida-tools,如),然后下載 frida-server,下載地址:https://github.com/frida/frida/releases

frida-server 要根據(jù)你電腦端安裝的 frida 版本和手機(jī)的 CPU 架構(gòu)來(lái)選擇對(duì)應(yīng)的,使用命令 frida --version 可以查看 frida 版本,使用命令 adb shell 進(jìn)入手機(jī),輸入 getprop ro.product.cpu.abi 查看 CPU 架構(gòu),如下圖所示,我這里 frida 是 15.2.2 版本,手機(jī) CPU 為 arm64,所以我下載的是 frida-server-15.2.2-android-arm64.xz

某些 Android 低版本使用高版本 frida 可能有問(wèn)題,遇到問(wèn)題可嘗試降低 frida 版本來(lái)解決。

將下載好的 frida-server 使用 adb push 命令傳到手機(jī)的 /data/local/tmp/ 目錄下,并給予 777 讀、寫(xiě)、執(zhí)行的權(quán)限,然后直接運(yùn)行 frida-server,正常不會(huì)有任何輸出,當(dāng)然也可以使用 & 等方式讓其在后臺(tái)運(yùn)行。

然后另開(kāi)一個(gè) cmd 使用命令 frida-ps -U 可查看手機(jī)進(jìn)程,有輸出則正常。

逆向分析

使用 adb install 命令安裝 UnCrackable-Level1.apk,打開(kāi)該 APP,會(huì)檢測(cè)到 root,出現(xiàn) Root detected! 的提示,如下圖所示:

使用 JEB、JADX、GDA 等工具反編譯 apk,直接搜索關(guān)鍵字 Root detected! 即可定位到檢測(cè)的地方:

可以看到圖中有三個(gè)檢測(cè)方法 c.a()、c.b()、c.c(),其中一個(gè)返回為真,則彈出 Root detected!,然后前面還有一個(gè) onClick 方法,如果點(diǎn)擊 OK 按鈕,則觸發(fā) System.exit(0);,即退出 APP,先點(diǎn)進(jìn)三個(gè)檢測(cè)方法看看:

a() 方法通過(guò)檢測(cè) Android 系統(tǒng)環(huán)境變量中是否有 su 文件來(lái)判斷是否被 root;

b() 方法通過(guò)檢測(cè) Build.TAGS 中是否包含字符串 test-keys 來(lái)判斷是否被 root;

c() 方法通過(guò)檢測(cè)指定路徑下是否包含指定的文件來(lái)判斷是否被 root。

所以我們這里就有多種過(guò)掉檢測(cè)的方法:

方法一:Hook 三個(gè)檢測(cè)方法,讓它們都返回 false,不再執(zhí)行后續(xù)的 a 方法,就不會(huì)退出 APP 了:

Java.perform(
    function(){
        console.log("[*] Hook begin")
        var vantagePoint = Java.use("sg.vantagepoint.a.c")
        vantagePoint.a.implementation = function(){
            console.log("[*] Hook vantagepoint.a.c.a")
            this.a();
            return false;
        }
        vantagePoint.b.implementation = function(){
            console.log("[*] Hook vantagepoint.a.c.b")
            this.b();
            return false;
        }
        vantagePoint.c.implementation = function(){
            console.log("[*] Hook vantagepoint.a.c.c")
            this.c();
            return false;
        }
    }
)

方法二:Hook a() 方法,置空,什么都不做,不彈出對(duì)話框,也不退出 APP:

Java.perform(
    function(){
        console.log("[*] Hook begin")
        var mainActivity = Java.use("sg.vantagepoint.uncrackable1.MainActivity");
        mainActivity.a.implementation = function(){
            console.log("[*] Hook mainActivity.a")
        }
    }
)

方法三:Hook onClick() 方法,點(diǎn)擊 OK 后不讓其退出 APP,注意這里是內(nèi)部類(lèi)的 Hook 寫(xiě)法:

Java.perform(
    function(){
        console.log("[*] Hook begin")
        var mainActivity$1 = Java.use("sg.vantagepoint.uncrackable1.MainActivity$1");
        mainActivity$1.onClick.implementation = function(){
            console.log("[*] Hook mainActivity$1.onClick")
        }
    }
)

方法四:Hook System.exit() 方法,點(diǎn)擊 OK 后不讓其退出 APP:

Java.perform(
    function(){
        console.log("[*] Hook begin")
        var javaSystem = Java.use("java.lang.System");
        javaSystem.exit.implementation = function(){
            console.log("[*] Hook system.exit")
        }
    }
)

root 檢測(cè)過(guò)掉之后,APP 還要輸入一個(gè)字符串,輸入錯(cuò)誤會(huì)提示 That's not it. Try again.,如下圖所示:

分析 Java 代碼,有一個(gè) if-else 判斷,obj 為輸入的字符串,a.a(obj) 判斷為真,就表示輸入正確。

跟到 a.a() 方法,可以看到 bArr 是內(nèi)置的字符串,通過(guò) equals() 方法比較輸入的 str 是否和 bArr 相等:

bArr 的值,主要經(jīng)過(guò) sg.vantagepoint.a.a.a() 方法處理后得到,繼續(xù)跟進(jìn)去可以發(fā)現(xiàn)是 AES 加密算法:

這里就可以直接 Hook sg.vantagepoint.a.a.a(),直接拿到加密后的值,也就是我們要的正確字符串,由于這里返回的是 ASCII 碼,所以我們還需要在 JavaScript 代碼中使用 String.fromCharCode() 將其轉(zhuǎn)換成正常字符,Hook 代碼如下:

Java.perform(
    function(){
        var cryptoAES = Java.use("sg.vantagepoint.a.a");
        cryptoAES.a.implementation = function(bArr, bArr2){
            console.log("[*] Hook cryptoAES")
            var secret = "";
            var decryptValue = this.a(bArr, bArr2);
            console.log("[*] DecryptValue:", decryptValue)
            for (var i=0; i < decryptValue.length; i++){
              secret += String.fromCharCode(decryptValue[i]);
            }
            console.log("[*] Secret:", secret)
            return decryptValue;
        }
    }
)

運(yùn)行 Hook 腳本有兩種方式,一是結(jié)合 Python 使用,二是直接通過(guò) frida 命令使用腳本,注入 Hook 代碼也有個(gè)時(shí)機(jī)問(wèn)題,有時(shí)候需要在 APP 啟動(dòng)就開(kāi)始 Hook,有時(shí)候可以等 APP 啟動(dòng)加載完畢了再 Hook,本例中,過(guò) root 檢測(cè)的時(shí)候,如果采用第一、二種方法,即 Hook 三個(gè)檢測(cè)方法或者 a 方法,那就需要在 APP 啟動(dòng)的時(shí)候就 Hook,如果采用第三、四種方法,即 Hook onClick() 或者 System.exit() 方法,那么等 APP 啟動(dòng)了再 Hook 也可以。

結(jié)合 Python 使用

首先來(lái)看一下結(jié)合 Python 怎么使用,JavaScript 代碼如下(frida-hook.js):

/* ==================================
# @Time    : 2022-08-29
# @Author  : 微信公眾號(hào):K哥爬蟲(chóng)
# @FileName: frida-hook.js
# @Software: PyCharm
# ================================== */


Java.perform(
    function(){
        console.log("[*] Hook begin")

        // 方法一:Hook 三個(gè)檢測(cè)方法,讓它們都返回 false,不再執(zhí)行后續(xù)的 a 方法,就不會(huì)退出 APP 了
        // var vantagePoint = Java.use("sg.vantagepoint.a.c")
        // vantagePoint.a.implementation = function(){
        //     console.log("[*] Hook vantagepoint.a.c.a")
        //     this.a();
        //     return false;
        // }
        // vantagePoint.b.implementation = function(){
        //     console.log("[*] Hook vantagepoint.a.c.b")
        //     this.b();
        //     return false;
        // }
        // vantagePoint.c.implementation = function(){
        //     console.log("[*] Hook vantagepoint.a.c.c")
        //     this.c();
        //     return false;
        // }

        // 方法二:Hook a() 方法,置空,什么都不做,不彈出對(duì)話框,也不退出 APP
        // var mainActivity = Java.use("sg.vantagepoint.uncrackable1.MainActivity");
        // mainActivity.a.implementation = function(){
        //    console.log("[*] Hook mainActivity.a")
        // }

        // 方法三:Hook onClick() 方法,點(diǎn)擊 OK 后不讓其退出 APP
        // var mainActivity$1 = Java.use("sg.vantagepoint.uncrackable1.MainActivity$1");
        // mainActivity$1.onClick.implementation = function(){
        //     console.log("[*] Hook mainActivity$1.onClick")
        // }

        // 方法四:Hook System.exit 方法,點(diǎn)擊 OK 后不讓其退出 APP
        var javaSystem = Java.use("java.lang.System");
        javaSystem.exit.implementation = function(){
            console.log("[*] Hook system.exit")
        }

        var cryptoAES = Java.use("sg.vantagepoint.a.a");
        cryptoAES.a.implementation = function(bArr, bArr2){
            console.log("[*] Hook cryptoAES")
            var secret = "";
            var decryptValue = this.a(bArr, bArr2);
            console.log("[*] DecryptValue:", decryptValue)
            for (var i=0; i < decryptValue.length; i++){
              secret += String.fromCharCode(decryptValue[i]);
            }
            console.log("[*] Secret:", secret)
            return decryptValue;
        }
    }
)

Python 代碼如下(frida-hook.py):

# ==================================
# --*-- coding: utf-8 --*--
# @Time    : 2022-08-29
# @Author  : 微信公眾號(hào):K哥爬蟲(chóng)
# @FileName: frida-hook.py
# @Software: PyCharm
# ==================================


import sys
import frida


def on_message(message, data):
    if message['type'] == 'send':
        print("[*] {0}".format(message['payload']))
    else:
        print(message)


with open("./frida-hook.js", "r", encoding="utf-8") as fp:
    hook_string = fp.read()

# 方式一:attach 模式,已經(jīng)啟動(dòng)的 APP
process = frida.get_usb_device(-1).attach("Uncrackable1")
script = process.create_script(hook_string)
script.on("message", on_message)
script.load()
sys.stdin.read()

# 方式二,spawn 模式,重啟 APP
# device = frida.get_usb_device(-1)
# pid = device.spawn(["owasp.mstg.uncrackable1"])
# process = device.attach(pid)
# script = process.create_script(hook_string)
# script.on("message", on_message)
# script.load()
# device.resume(pid)
# sys.stdin.read()

Python 代碼中,attach 模式 Hook 已經(jīng)存在的進(jìn)程,spawn 模式會(huì)重啟 APP,啟動(dòng)一個(gè)新的進(jìn)程并掛起,在啟動(dòng)的同時(shí)注入 frida 代碼,適用于在進(jìn)程啟動(dòng)前的一些 Hook,attach 模式傳入的是 APP 名稱(chēng),spawn 模式傳入的是 APP 包名,查看 APP 名稱(chēng)和包名的方法有很多,這里介紹兩個(gè) frida 命令,frida-ps -Uai:列出安裝的程序,frida-ps -Ua:列出正在運(yùn)行中的程序,如下圖所示,本例中 Uncrackable1 就是 APP 名稱(chēng),owasp.mstg.uncrackable1 就是包名:

運(yùn)行 Python 代碼,注意手機(jī)端也要啟動(dòng) frida-server,過(guò)掉 root 檢測(cè)后,先隨便輸入字符串,點(diǎn)擊 VERIFY 就會(huì) Hook 到正確的字符串為 I want to believe,再次輸入正確的字符串,即可驗(yàn)證成功。

frida 命令

不使用 Python,也可以直接使用 frida 命令來(lái)實(shí)現(xiàn),和前面 Python 一樣也有兩種模式,同樣的一個(gè)是 APP 名一個(gè)是包名:

frida -U Uncrackable1 -l .\frida-hook.js:attach 模式,APP 啟動(dòng)后注入 frida 代碼;

frida -U -f owasp.mstg.uncrackable1 -l .\frida-hook.js --no-pause:spawn 模式,重啟 APP,啟動(dòng)的同時(shí)注入 frida 代碼。

至此,我們完美繞過(guò)了 root 檢測(cè),并成功找到了正確的字符串。


當(dāng)前文章:【APP 逆向百例】Frida 初體驗(yàn),root 檢測(cè)與加密字符串定位
文章位置:http://weahome.cn/article/dsogsps.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部