主頁 > 資料庫 > 抖音資料采集Frida教程,Frida Java Hook 詳解:代碼及示例(上)

抖音資料采集Frida教程,Frida Java Hook 詳解:代碼及示例(上)

2021-01-24 19:06:20 資料庫

抖音資料采集Frida教程,Frida Java Hook 詳解:代碼及示例(上)

短視頻、直播資料實時采集介面,請查看檔案: TiToData


免責宣告:本檔案僅供學習與參考,請勿用于非法用途!否則一切后果自負,

**前言
1.1 FRIDA SCRIPT的"hello world"
1.1.1 "hello world"腳本代碼示例
1.1.2 "hello world"腳本代碼示例詳解
1.2 Java層攔截普通方法
1.2.1 攔截普通方法腳本示例
1.2.2 執行攔截普通方法腳本示例
1.3 Java層攔截建構式
1.3.1 攔截建構式腳本代碼示例
1.3.2 攔截建構式腳本代碼示例解詳解
1.4 Java層攔截方法多載
1.4.1 攔截方法多載腳本代碼示例
1.5 Java層攔截構造物件引數
1.5.1 攔截構造物件引數腳本示例
1.6 Java層修改成員變數的值以及函式的回傳值
1.6.1 修改成員變數的值以及函式的回傳值腳本代碼示例
1.6.2 修改成員變數的值以及函式的回傳值之小實戰 
結語

咱們在這篇來深入學習如何HOOK Java層函式,應用于與各種不同的Java層函式,結合實際APK案例使用FRIDA框架對其APP進行附加、hook、以及FRIDA腳本的詳細撰寫,

1.1 FRIDA SCRIPT的"hello world"

在本章節中,依然會大量使用注入模式附加到一個正在運行行程程式,亦或是在APP程式啟動的時候對其APP行程進行劫持,再在目標行程中執行我們的js檔案代碼邏輯,FRIDA腳本就是利用FRIDA動態插樁框架,使用FRIDA匯出的API和方法,對記憶體空間里的物件方法進行監視、修改或者替換的一段代碼,FRIDAAPI是使用JavaScript實作的,所以我們可以充分利用JS的匿名函式的優勢、以及大量的hook和回呼函式的API,那么大家跟我一起來操作吧,先打開在vscode中創建一個js檔案:helloworld.js

1.1.1 "hello world"腳本代碼示例

setTimeout(function(){
  Java.perform(function(){
      console.log("hello world!");
    });
});

1.1.2 "hello world"腳本代碼示例詳解

這基本上就是一個FRIDA版本的Hello World!,我們把一個匿名函式作為引數傳給了setTimeout()函式,然而函式體中的Java.perform()這個函式本身又接受了一個匿名函式作為引數,該匿名函式中最侄訓呼叫console.log()函式來列印一個Hello world!字串,我們需要呼叫setTimeout()方法因為該方法將我們的函式注冊到JavaScript運行時中去,然后需要呼叫Java.perform()方法將函式注冊到FridaJava運行時中去,用來執行函式中的操作,當然這里只是打了一條log,然后我們在手機上將frida-server運行起來,在電腦上進行操作:

roysue@ubuntu:~$ adb shell
sailfish:/ $ su
sailfish:/ $ ./data/local/tmp/frida-server

這個時候,我們需要再開啟一個終端運行另外一條命令:
frida -U com.roysue.roysueapplication -l helloworld.js
這句代碼是指通過USB連接對Android設備中的com.roysue.roysueapplication行程對其附加并且注入一個helloworld.js腳本,注入完成之后會立刻執行helloworld.js腳本所寫的代碼邏輯!
我們可以看到成功注入了腳本以及附加到自己所撰寫包名為:com.roysue.roysueapplicationapk應用程式中,并且列印了一條 hell world!


roysue@ubuntu:~$ frida -U -l helloworld.js com.roysue.roysueapplication
     ____
    / _  |   Frida 12.7.24 - A world-class dynamic instrumentation toolkit
   | (_| |
    > _  |   Commands:
   /_/ |_|       help      -> Displays the help system
   . . . .       object?   -> Display information about 'object'
   . . . .       exit/quit -> Exit
   . . . .
   . . . .   More info at https://www.frida.re/docs/home/
Attaching...
hello world!

執行了該命令之后,FRIDA回傳一個了CLI終端工具與我們互動,在上面可見列印出來了一些資訊,顯示了我們的FRIDA版本資訊還有一個反向R的圖形,往下看,需要退出的時候我們只需要在終端輸入exit即可完成退出對APP的附加,其后我們看到的是Attaching...正在對目標行程附加,當附加成功了列印了一句hello world!,至此,我們的helloworld.js通過FRIDA-l命令成功的注入到目標行程并且執行完畢,學會了注入可不要高興的太早喲~~咱們繼續深入學習HOOK Java代碼中的普通函式,

1.2 Java層攔截普通方法

Java層的普通方法相當常見,也是我們要學習的基礎中的基礎,我們先來看幾個比較常見的普通的方法,見下圖1-1,

圖1-1 JADX-GUI軟體打開的反編譯代碼
通過圖1-1我們能看三個函式分別是建構式a()、普通函式a()b(),諸如這種普通函式會特別多,那我們在本小章節中嘗試hook普通函式、查看函式中的引數的具體值,
在嘗試寫FRIDA HOOK腳本之前咱們先來看看需要hook的代碼吧~,Ordinary_Class類中有四個函式,都是很普通的函式,add函式的功能也很簡單,引數a+b;sub函式功能是引數a-b;而getNumber只回傳100getString方法回傳了 getString()+引數的str,見下圖1-2,

圖1-2 反編譯的Ordinary_Class類的代碼
然后咱們再看MainActivity中的撰寫的代碼,通過反編譯出來的代碼一共有四個按鈕(Button),當btn_add點擊時會運行Ordinary_Class類中add方法,計算100+200的結果,通過String.valueOf函式把計算結構轉字串然后通過Toast彈出資訊;點擊btn_sub按鈕的時候觸發點擊事件會運行Ordinary_Class類中sub方法,計算100-100的結果,通過String.valueOf函式把計算結構轉字串然后通過Toast彈出資訊,在MainActivity類中的onCreate方法中的四個按鈕分別對應情況是ADD按鈕對應btn_add點擊事件,SUB對應btn_sub的點擊事件,見下圖1-3,

圖1-3 MainActivity中的撰寫的代碼
按照正常流程當我們點擊ADD的按鈕界面會彈出一條資訊顯示,其中的值是300,因為我們在ADD的點擊事件中添加了Toast,將ADD方法運行的結果放在Toast引數中,通過它顯示了我們的計算結果;而SUB函式會顯示0,見下圖1-4,圖1-5,

圖1-4 點擊ADD按鈕時顯示的結果

圖1-5 點擊SUB按鈕時顯示的結果
我們現在知道已經知道它的運行流程以及函式的執行結果和所填寫的引數,我們現在來正式撰寫一個基本的使用Frida鉤子來攔截圖1-2中addsub函式的呼叫并且在終端顯示每個函式所傳入的引數、回傳的值,開始寫roysue_0.js

1.2.1 攔截普通方法腳本示例

setTimeout(function(){
    //判斷是否加載了Java VM,如果沒有加載則不運行下面的代碼
    if(Java.available) {
        Java.perform(function(){
            //先列印一句提示開始hook
            console.log("start hook");
            //先通過Java.use函式得到Ordinary_Class類
            var Ordinary_Class = Java.use("com.roysue.roysueapplication.Ordinary_Class");
            //這里我們需要進行一個NULL的判斷,通常這樣做會排除一些不必要的BUG
            if(Ordinary_Class != undefined) {
                //格式是:類名.函式名.implementation = function (a,b){
                //在這里使用鉤子攔截add方法,注意方法名稱和引數個數要一致,這里的a和b可以自己任意填寫,
                Ordinary_Class.add.implementation = function (a,b){
                    //在這里先得到運行的結果,因為我們要輸出這個函式的結果
                    var res = this.add(a,b);
                    //把計算的結果和引數一起輸出
                    console.log("執行了add方法 計算result:"+res);
                    console.log("執行了add方法 計算引數a:"+a);
                    console.log("執行了add方法 計算引數b:"+b);
                    //回傳結果,因為add函式本身是有回傳值的,否則APP運行的時候會報錯
                    return res;
                }
                Ordinary_Class.sub.implementation = function (a,b){
                    var res = this.sub(a,b);
                    console.log("執行了sub方法 計算result:"+res);
                    console.log("執行了sub方法 計算引數a:"+a);
                    console.log("執行了sub方法 計算引數b:"+b);
                    return res;
                }
                Ordinary_Class.getString.implementation = function (str){
                    var res = this.getString(str);
                    console.log("result:"+res);
                    return res;
                }
            } else {
                console.log("Ordinary_Class: undefined");
            }
            console.log("hook end");
          });
    }
});

1.2.2 執行攔截普通方法腳本示例

寫完腳本后我們執行:frida -U com.roysue.roysueapplication -l roysue_0.js,當我們執行了腳本后會進入cli控制臺與frida互動,可以看到已經對該app附加并且成功注入腳本,立刻列印出了start hookhook end,正是我們剛剛所寫的,再繼續點擊app應用中的ADD按鈕和SUB按鈕會在終端立刻輸出計算的結果和引數,在這里甚至可以看到清晰,引數、回傳值一覽無余,

roysue@ubuntu:~$ frida -U com.roysue.roysueapplication -l roysue_0.js
     ____
    / _  |   Frida 12.7.24 - A world-class dynamic instrumentation toolkit
   | (_| |
    > _  |   Commands:
   /_/ |_|       help      -> Displays the help system
   . . . .       object?   -> Display information about 'object'
   . . . .       exit/quit -> Exit
   . . . .
   . . . .   More info at https://www.frida.re/docs/home/
Attaching...
start hook
hook end
[Google Pixel::com.roysue.roysueapplication]-> 執行了add方法 計算result:300
執行了add方法 計算引數a:100
執行了add方法 計算引數b:200
執行了sub方法 計算result:0
執行了sub方法 計算引數a:100
執行了sub方法 計算引數b:100

這樣我們就已經成功的列印了來了我們想要知道的值,每個引數的值和回傳值的結構,我們就對普通函式的鉤子完成了一個基本操作,大家可以自己多多嘗試對其他的普通的函式進行hook,多多練習,那咱們這一章節就愉快的完成了~~繼續深入吧,

1.3 Java層攔截建構式

那咱們這章來玩如何HOOK類的建構式,很多時候在實體化類的瞬間就會把引數傳遞到內部為成員變數賦值,這樣一來就省的類中的成員變數一個個去賦值,在Android逆向中,也有很多的類似的場景,利用有參建構式實體化類并且賦值,我建立了一個class類,類名是User,其中代碼這樣寫:

public class User {
    public int age;
    public String name;
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("User{name='");
        sb.append(this.name);
        sb.append('\'');
        sb.append(", age=");
        sb.append(this.age);
        sb.append('}');
        return sb.toString();
    }

    public User(String name2, int age2) {
        this.name = name2;
        this.age = age2;
    }
    public User() {
    }
}

我們可以看到User類中有2個成員變數分別是agename,還有2個構造方法,分別是無參構造有有參構造,我們現在要做的是在User類進行有參實體化時查看所填入的引數分別是什么值,在圖1-3中,可以看到btn_init的點擊事件時會對User類進行實體化引數分別填寫了roysue30,然后再繼續呼叫了toString方法把它們組合到一起并且通過Toast彈出資訊顯示值,TEST_INTI對應btn_init的點擊事件,點擊時效果見下圖1-6,

圖1-6 點擊TEST_INIT時顯示的值

1.3.1 攔截建構式腳本代碼示例

現在開始撰寫frida鉤子來攔截User類的建構式的腳本,來列印出建構式的引數,撰寫roysue_1.js

setTimeout(function(){
    if(Java.available) {
        Java.perform(function(){
            console.log("start hook");
            //同樣的在這里先獲取User類物件
            var User = Java.use("com.roysue.roysueapplication.User");
            if(User != undefined) {
                //注意在使用鉤子攔截建構式時需要使用到 $init 也要注意引數的個數,因為該建構式是2個所以此處填2個引數
                User.$init.implementation = function (name,age){
                    //這里列印成員變數name和age的在運行中被呼叫填寫的值
                    console.log("name:"+name);
                    console.log("age:"+age);
                    //最終要執行原本的init方法否則運行時會報例外導致原程式無法正常運行,
                    this.$init(name, age);
                }
            } else {
                console.log("User: undefined");
            }
            console.log("hook end");
          });
    }
});

1.3.2 攔截建構式腳本代碼示例解詳解

腳本寫好之后打開終端執行frida -U com.roysue.roysueapplication -l roysue_1.js,把剛剛寫的腳本注入的目標行程,然后我們在APP應用中按下TEST_INIT按鈕,注入的腳本會立即攔截建構式并且列印2個引數的具體的值,見下圖1-7,
image.pngimage.gif
圖1-7 終端顯示
列印的值就是圖1-3中所填的roysue30,這就說明我們使用FRIDA鉤子攔截到了User類的有參建構式并且有效的列印了引數的值,需要注意的是在輸入列印引數的值之后一定要記得執行原本的有參建構式,這樣程式才可以正常執行,

1.4 Java層攔截方法多載

在學習HOOK之前,咱們先了解一下什么是方法多載,方法多載是指在同一個類內定義了多個相同的方法名稱,但是每個方法的引數型別和引數的個數都不同,在呼叫方法多載的函式編譯器會根據所填入的引數的個數以及型別來匹配具體呼叫對應的函式,總結起來就是方法名稱一樣但是引數不一樣,在逆向JAVA代碼的時候時常會遇到方法多載函式,見下圖1-8,

圖1-8 反編譯后多載函式樣本代碼
在圖1-8中,我們能看到一共有三個方法多載的函式,有時候實際情況甚至更多,咱們也不要怕,擼起袖子加油干,對于這種多載函式在FRIDA中,js會寫.overload來攔截方法多載函式,當我們使用overload關鍵字的時候FRIDA會非常智能把當前所有的多載函式的所需要的型別列印出來,在了解了這個之后我們來開始實戰使用FRIDA鉤子攔截我們想攔截的多載函式的腳本吧!還是之前的那個app,還是之前的那個類,原汁原味~~,我新增了一些add的方法,使add方法多載,見下圖1-9,

圖1-9 反編譯后的Ordinary_Class中的多載函式樣本代碼
在圖1-9中add有三個重名的方法名稱,但是引數的個數不同,在圖1-3中的btn_add點擊事件會執行擁有2個引數的方法多載的add函式,當我在腳本中寫Ordinary_Class.add..implementation = function (a,b),然后繼續注入所寫好的腳本,FRIDA在終端提示了紅色的字體,一看嚇一跳!但咱們仔細看,它說add是一個方法多載的函式,有三個引數不同的add函式,讓我們寫.overload(xxx),以識別hook的到底是哪個add的方法多載函式,
當我們寫了這樣的js腳本去運行的時候,frida提示報錯了,因為有三個多載函式,我用紅色的框圈出了,可以看到frida十分的智能,三個多載的引數型別完全一致的列印出來了,當它列印出來之后我們就可以復制它的這個智能提示的overloadxxx多載來修改我們自己的腳本了,進一步完善我們的腳本代碼如下,

1.4.1 攔截方法多載腳本代碼示例

function hook_overload() {
    if(Java.available) {
        Java.perform(function () {
            console.log("start hook");
            var Ordinary_Class = Java.use("com.roysue.roysueapplication.Ordinary_Class");
            if(Ordinary_Class != undefined) {
                //要做的僅僅是將frida提示出來的overload復制在此處
                Ordinary_Class.add.overload('int', 'int').implementation = function (a,b){
                    var res = this.add(a,b);
                    console.log("result:"+res);
                    return res;
                }
                Ordinary_Class.add.overload('int', 'int', 'int').implementation = function (a,b,d){
                    var res = this.add(a,b,d);
                    console.log("result:"+res);
                    return res;
                }
                Ordinary_Class.add.overload('int', 'int', 'int', 'int').implementation = function (a,b,d,c){
                    var res = this.add(a,b,d,c);
                    console.log("result:"+res);
                    return res;
                }
            } else {
                console.log("Ordinary_Class: undefined");
            }
            console.log("start end");
        });
    }
}
setImmediate(hook_overload);

修改完相應的地方之后我們保存代碼時終端會自動再次運行js中的代碼,不得不說frida太強大了~,當js再次運行的時候我們在app應用中點擊圖1-4中ADD按鈕時會立刻列印出結果,因為FRIDA鉤子已經對該類中的所有的add函式進行了攔截,執行了自己所寫的代碼邏輯,點擊效果如下圖1-11,
image.pngimage.gif
圖1-11 終端顯示效果
在這一章節中我們學會了處理方法多載的函式,我們只要依據FRIDA的終端提示,將智能提示出來的代碼銜接到自己的代碼就能夠對方法多載函式進行攔截,執行我們自己想要執行的代碼,

1.5 Java層攔截構造物件引數

很多時候,我們不但要HOOK使用鉤子攔截函式對函式的引數和回傳值進行記錄,而且還要自己主動呼叫類中的函式使用,FRIDA中有一個new()關鍵字,而這個關鍵字就是實體化類的重要方法,
在官方API中有這樣寫道:“Java.use(ClassName):動態獲取classNameJavaScript包裝器,通過對其呼叫new()來呼叫建構式,可以從中實體化物件,對實體呼叫Dispose()以顯式清理它(或等待JavaScript物件被垃圾收集,或腳本被卸載),靜態和非靜態方法都是可用的,”,那我們就知道通過Java.use獲取的class類可以呼叫$new()來呼叫建構式,可以從實體化物件,在圖1-9中有6個函式,了解了API的呼叫之后我們來開始入手撰寫我們的js檔案,(在這里我覺得大家一定要動手做測驗,動手嘗試,你會發現其中的妙趣無窮!),

1.5.1 攔截構造物件引數腳本示例

function hook_overload_1() {
    if(Java.available) {
        Java.perform(function () {
            console.log("start hook");
            //還是先獲取類
            var Ordinary_Class = Java.use("com.roysue.roysueapplication.Ordinary_Class");
            if(Ordinary_Class != undefined) {
                //這里因為add是一個靜態方法能夠直接呼叫方法
                var result = Ordinary_Class.add(100,200);
                console.log("result : " +result);
                //呼叫方法多載無壓力
                result = Ordinary_Class.add(100,200,300);
                console.log("result : " +result);
                //呼叫方法多載
                result = Ordinary_Class.add(100,200,300,400);
                console.log("result : " +result);         
                //呼叫方法多載       
                result = Ordinary_Class.getNumber();
                console.log("result : " +result);   
                //呼叫方法多載             
                result = Ordinary_Class.getString("  HOOK");
                console.log("result : " +result);

                //在這里,使用了官方API的$new()方法來實體化類,實體化之后回傳一個實體物件,通過這個實體物件來呼叫類中方法,
                var Ordinary_Class_instance = Ordinary_Class.$new();
                result = Ordinary_Class_instance.getString("Test");
                console.log("instance --> result : " +result);
                result = Ordinary_Class_instance.add(1,2,3,4);
                console.log("instance --> result : " +result);     
            } else {
                console.log("Ordinary_Class: undefined");
            }
            console.log("start end");
        });
    }
}
setImmediate(hook_overload_1);


當我們執行了上面寫的腳本之后終端會列印呼叫方法之后的結果,見下圖1-12,
image.pngimage.gif
圖1-12 終端顯示呼叫函式的結果
因為很多時候類中的方法并不一定是靜態的,所以這里提供了2種呼叫方法,第一種呼叫方式十分的方便,不需要實體化一個物件,再通過物件調本身的方法,但是遇到了沒有static關鍵字的函式時只能使用第二種方式來實作方法呼叫,在這一章節中我們學會了如何自己主動去呼叫類中的函式了~~大家也可以嘗試主動呼叫有參的建構式玩玩,

1.6 Java層修改成員變數的值以及函式的回傳值

我們上章學完了如何自己主動呼叫JAVA層的函式了,經過上章的學習我們的功夫又精進了一些~~,現在我們來深入內部修改類的物件的成員變數和回傳值,打入敵人內部,提高自己的內功,現在我們來看下圖1-13,

圖1-13 User類
上圖中的User類是我之前建的一個類,類中寫了2個公開成員變數分別是agename;還有2個方法分別是User的有參建構式和一個toString函式列印成員變數的函式,我們要做就是在User類實體化的時候攔行程式并且修改掉agename的值,從而改寫成我們自己需要的值再運行程式,那我們接下開始撰寫JS腳本來修改成員變數的值,
這段代碼主要有的功能是:通過User.$new("roysue",29)拿到User類的有引數構造的實體化物件,這個恰好也是使用了上章節中學到的知識自己構建物件,這里我們也學習了如何使用FRIDA框架通過有參建構式實體化物件,實體化之后先是呼叫了類本身的toString方法列印出未修改前的成員變數的值,列印了之后再通過User_instance.age.value = https://www.cnblogs.com/titodata/p/0;來修改物件當前的成員變數的值,可以看到修改age修改為0name修改為roysue_123,然后再次呼叫toString方法查看其成員變數的最新值是否已經被更改,

1.6.1 修改成員變數的值以及函式的回傳值腳本代碼示例

function hook_overload_2() {
    if(Java.available) {
        Java.perform(function () {
            console.log("start hook");
            //拿到User類
            var User = Java.use("com.roysue.roysueapplication.User");
            if(User != undefined) {
                //這里利用上章學到知識來自己構建一個User的有參構造的實體化物件
                var User_instance  = User.$new("roysue",29);
                //并且呼叫了類中的toString()方法
                var str = User_instance.toString();
                //列印成員變數的值
                console.log("str:"+str);

                //這里獲取了屬性的值以及列印
                console.log("User_instance.name:"+User_instance.name);
                console.log("User_instance.age:"+User_instance.age);

                //這里重新設定了age和name的值
                User_instance.age.value = https://www.cnblogs.com/titodata/p/0;
                User_instance.name.value ="roysue_123";
                str = User_instance.toString();
                //再次列印成員變數的值
                console.log("str:"+str);
            } else {
                console.log("User: undefined");
            }
            console.log("start end");
        });
    }
}


可以看到終端顯示了原本有參建構式的值roysue和30修改為roysue_123和0已經成功了,效果見下圖1-14,

圖1-14 終端顯示修改效果
通過上面的學習,我們學會了如何修改類的成員變數,上個例子中是使用的有參建構式給與成員變數賦值,通常在寫代碼類似這種物體類會定義相關的get set方法以及修飾符為私有權限,外部不可呼叫,這個時候他們可能會通過set方法來設定其值和get方法獲取成員的變數的值,這個時候我們可以通過鉤子攔截setget方法自己定義值也是可以達到修改和獲取的效果,現在學完了如何修改成員變數了,那我們接下來要學習如何修改函式的回傳值,假設在逆向的程序中已知檢測函式A的結果為B,正確結果為C,那我們可以強行修改函式A的回傳值,不論在函式中執行了什么與回傳結果無關,我們只要修改結果即可,

1.6.2 修改成員變數的值以及函式的回傳值之小實戰

我在rdinary_Class類建立了2個函式分別是isCheckisCheckResult,假設isCheck是一個檢測方法,經過add運行后必然結果2,代表被檢測到了,在isCheckResult方法進行了判斷呼叫isCheck函式結果為2就是錯誤的,那這個時候要把isCheck函式或者add函式的結果強行改成不是2之后isCheckResult即可列印Successful,見下圖1-15,

圖1-15 isCheck函式與isCheckResult函式
我們現在要做的是使sCheckResult函式成功列印出"Successful",而不是errer,那我們現在開始來寫js腳本吧~~

function hook_overload_7() {
    if(Java.available) {
        Java.perform(function () {
            console.log("start hook");
            //先獲取類
            var Ordinary_Class = Java.use('com.roysue.roysueapplication.Ordinary_Class');
            if(Ordinary_Class != undefined) {
                //先呼叫一次肯定會輸出error
                Ordinary_Class.isCheckResult();
                //在這里重寫isCheck方法將回傳值強行改為123并且輸出了一句Ordinary_Class: isCheck
                Ordinary_Class.isCheck.implementation = function (){
                    console.log("Ordinary_Class: isCheck");
                    return 123;
                }
                //再呼叫一次isCheckResult()方法
                Ordinary_Class.isCheckResult();
            } else {
                console.log("Ordinary_Class: undefined");
            }
            console.log("hook end");
        });
    }
}


上面這段代碼的主要功能是:首先通過Java.use獲取Ordinary_Class,因為isCheckResult()是靜態方法,可以直接呼叫,在這里先呼叫一次,因為這樣比較好看效果,第一次呼叫會在Android LOG中列印errer,之后緊接著利用FRIDA鉤子對isCheck函式進行攔截,改掉其回傳值為123,這樣每次呼叫isCheck函式時回傳值都必定會是123,再呼叫一次isCheckResult()方法,isCheckResult()方法中判斷isCheck回傳值是否等于2,因為我們已經重寫了isCheck函式,所以不等于2,所以程式往下執行,會列印Successful字串到Android Log中,實際運行效果見下圖1-16,

圖1-16 終端顯示以及Android Log資訊
可以清晰的看到先是列印了errer后列印了Successful了,這說明我們已經成功過掉isCheck的判斷了,這是一個小小的綜合例子,建議大家多多動手嘗試,

結語

在這章中我們學習了HOOK Java層的一些函式,如攔截普通函式、建構式、以及修改成員變數以及函式回傳值,下一篇中我們來列舉所有的類、所有的方法多載、所有的子類以及RPC遠程呼叫Java層函式,

短視頻、直播資料實時采集介面,請查看檔案: TiToData


免責宣告:本檔案僅供學習與參考,請勿用于非法用途!否則一切后果自負,

轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/251612.html

標籤:大數據

上一篇:Hadoop 學習筆記 生態

下一篇:Spark學習之Dataset (DataFrame) 的基礎操作

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • GPU虛擬機創建時間深度優化

    **?桔妹導讀:**GPU虛擬機實體創建速度慢是公有云面臨的普遍問題,由于通常情況下創建虛擬機屬于低頻操作而未引起業界的重視,實際生產中還是存在對GPU實體創建時間有苛刻要求的業務場景。本文將介紹滴滴云在解決該問題時的思路、方法、并展示最終的優化成果。 從公有云服務商那里購買過虛擬主機的資深用戶,一 ......

    uj5u.com 2020-09-10 06:09:13 more
  • 可編程網卡芯片在滴滴云網路的應用實踐

    **?桔妹導讀:**隨著云規模不斷擴大以及業務層面對延遲、帶寬的要求越來越高,采用DPDK 加速網路報文處理的方式在橫向縱向擴展都出現了局限性。可編程芯片成為業界熱點。本文主要講述了可編程網卡芯片在滴滴云網路中的應用實踐,遇到的問題、帶來的收益以及開源社區貢獻。 #1. 資料中心面臨的問題 隨著滴滴 ......

    uj5u.com 2020-09-10 06:10:21 more
  • 滴滴資料通道服務演進之路

    **?桔妹導讀:**滴滴資料通道引擎承載著全公司的資料同步,為下游實時和離線場景提供了必不可少的源資料。隨著任務量的不斷增加,資料通道的整體架構也隨之發生改變。本文介紹了滴滴資料通道的發展歷程,遇到的問題以及今后的規劃。 #1. 背景 資料,對于任何一家互聯網公司來說都是非常重要的資產,公司的大資料 ......

    uj5u.com 2020-09-10 06:11:05 more
  • 滴滴AI Labs斬獲國際機器翻譯大賽中譯英方向世界第三

    **桔妹導讀:**深耕人工智能領域,致力于探索AI讓出行更美好的滴滴AI Labs再次斬獲國際大獎,這次獲獎的專案是什么呢?一起來看看詳細報道吧! 近日,由國際計算語言學協會ACL(The Association for Computational Linguistics)舉辦的世界最具影響力的機器 ......

    uj5u.com 2020-09-10 06:11:29 more
  • MPP (Massively Parallel Processing)大規模并行處理

    1、什么是mpp? MPP (Massively Parallel Processing),即大規模并行處理,在資料庫非共享集群中,每個節點都有獨立的磁盤存盤系統和記憶體系統,業務資料根據資料庫模型和應用特點劃分到各個節點上,每臺資料節點通過專用網路或者商業通用網路互相連接,彼此協同計算,作為整體提供 ......

    uj5u.com 2020-09-10 06:11:41 more
  • 滴滴資料倉庫指標體系建設實踐

    **桔妹導讀:**指標體系是什么?如何使用OSM模型和AARRR模型搭建指標體系?如何統一流程、規范化、工具化管理指標體系?本文會對建設的方法論結合滴滴資料指標體系建設實踐進行解答分析。 #1. 什么是指標體系 ##1.1 指標體系定義 指標體系是將零散單點的具有相互聯系的指標,系統化的組織起來,通 ......

    uj5u.com 2020-09-10 06:12:52 more
  • 單表千萬行資料庫 LIKE 搜索優化手記

    我們經常在資料庫中使用 LIKE 運算子來完成對資料的模糊搜索,LIKE 運算子用于在 WHERE 子句中搜索列中的指定模式。 如果需要查找客戶表中所有姓氏是“張”的資料,可以使用下面的 SQL 陳述句: SELECT * FROM Customer WHERE Name LIKE '張%' 如果需要 ......

    uj5u.com 2020-09-10 06:13:25 more
  • 滴滴Ceph分布式存盤系統優化之鎖優化

    **桔妹導讀:**Ceph是國際知名的開源分布式存盤系統,在工業界和學術界都有著重要的影響。Ceph的架構和演算法設計發表在國際系統領域頂級會議OSDI、SOSP、SC等上。Ceph社區得到Red Hat、SUSE、Intel等大公司的大力支持。Ceph是國際云計算領域應用最廣泛的開源分布式存盤系統, ......

    uj5u.com 2020-09-10 06:14:51 more
  • es~通過ElasticsearchTemplate進行聚合~嵌套聚合

    之前寫過《es~通過ElasticsearchTemplate進行聚合操作》的文章,這一次主要寫一個嵌套的聚合,例如先對sex集合,再對desc聚合,最后再對age求和,共三層嵌套。 Aggregations的部分特性類似于SQL語言中的group by,avg,sum等函式,Aggregation ......

    uj5u.com 2020-09-10 06:14:59 more
  • 爬蟲日志監控 -- Elastc Stack(ELK)部署

    傻瓜式部署,只需替換IP與用戶 導讀: 現ELK四大組件分別為:Elasticsearch(核心)、logstash(處理)、filebeat(采集)、kibana(可視化) 下載均在https://www.elastic.co/cn/downloads/下tar包,各組件版本最好一致,配合fdm會 ......

    uj5u.com 2020-09-10 06:15:05 more
最新发布
  • day02-2-商鋪查詢快取

    功能02-商鋪查詢快取 3.商鋪詳情快取查詢 3.1什么是快取? 快取就是資料交換的緩沖區(稱作Cache),是存盤資料的臨時地方,一般讀寫性能較高。 快取的作用: 降低后端負載 提高讀寫效率,降低回應時間 快取的成本: 資料一致性成本 代碼維護成本 運維成本 3.2需求說明 如下,當我們點擊商店詳 ......

    uj5u.com 2023-04-20 08:33:24 more
  • MySQL中binlog備份腳本分享

    關于MySQL的二進制日志(binlog),我們都知道二進制日志(binlog)非常重要,尤其當你需要point to point災難恢復的時侯,所以我們要對其進行備份。關于二進制日志(binlog)的備份,可以基于flush logs方式先切換binlog,然后拷貝&壓縮到到遠程服務器或本地服務器 ......

    uj5u.com 2023-04-20 08:28:06 more
  • day02-短信登錄

    功能實作02 2.功能01-短信登錄 2.1基于Session實作登錄 2.1.1思路分析 2.1.2代碼實作 2.1.2.1發送短信驗證碼 發送短信驗證碼: 發送驗證碼的介面為:http://127.0.0.1:8080/api/user/code?phone=xxxxx<手機號> 請求方式:PO ......

    uj5u.com 2023-04-20 08:27:27 more
  • 快取與資料庫雙寫一致性幾種策略分析

    本文將對幾種快取與資料庫保證資料一致性的使用方式進行分析。為保證高并發性能,以下分析場景不考慮執行的原子性及加鎖等強一致性要求的場景,僅追求最終一致性。 ......

    uj5u.com 2023-04-20 08:26:48 more
  • sql陳述句優化

    問題查找及措施 問題查找 需要找到具體的代碼,對其進行一對一優化,而非一直把關注點放在服務器和sql平臺 降低簡化每個事務中處理的問題,盡量不要讓一個事務拖太長的時間 例如檔案上傳時,應將檔案上傳這一步放在事務外面 微軟建議 4.啟動sql定時執行計劃 怎么啟動sqlserver代理服務-百度經驗 ......

    uj5u.com 2023-04-20 08:26:35 more
  • 云時代,MySQL到ClickHouse資料同步產品對比推薦

    ClickHouse 在執行分析查詢時的速度優勢很好的彌補了MySQL的不足,但是對于很多開發者和DBA來說,如何將MySQL穩定、高效、簡單的同步到 ClickHouse 卻很困難。本文對比了 NineData、MaterializeMySQL(ClickHouse自帶)、Bifrost 三款產品... ......

    uj5u.com 2023-04-20 08:26:29 more
  • sql陳述句優化

    問題查找及措施 問題查找 需要找到具體的代碼,對其進行一對一優化,而非一直把關注點放在服務器和sql平臺 降低簡化每個事務中處理的問題,盡量不要讓一個事務拖太長的時間 例如檔案上傳時,應將檔案上傳這一步放在事務外面 微軟建議 4.啟動sql定時執行計劃 怎么啟動sqlserver代理服務-百度經驗 ......

    uj5u.com 2023-04-20 08:25:13 more
  • Redis 報”OutOfDirectMemoryError“(堆外記憶體溢位)

    Redis 報錯“OutOfDirectMemoryError(堆外記憶體溢位) ”問題如下: 一、報錯資訊: 使用 Redis 的業務介面 ,產生 OutOfDirectMemoryError(堆外記憶體溢位),如圖: 格式化后的報錯資訊: { "timestamp": "2023-04-17 22: ......

    uj5u.com 2023-04-20 08:24:54 more
  • day02-2-商鋪查詢快取

    功能02-商鋪查詢快取 3.商鋪詳情快取查詢 3.1什么是快取? 快取就是資料交換的緩沖區(稱作Cache),是存盤資料的臨時地方,一般讀寫性能較高。 快取的作用: 降低后端負載 提高讀寫效率,降低回應時間 快取的成本: 資料一致性成本 代碼維護成本 運維成本 3.2需求說明 如下,當我們點擊商店詳 ......

    uj5u.com 2023-04-20 08:24:03 more
  • day02-短信登錄

    功能實作02 2.功能01-短信登錄 2.1基于Session實作登錄 2.1.1思路分析 2.1.2代碼實作 2.1.2.1發送短信驗證碼 發送短信驗證碼: 發送驗證碼的介面為:http://127.0.0.1:8080/api/user/code?phone=xxxxx<手機號> 請求方式:PO ......

    uj5u.com 2023-04-20 08:23:11 more